feat 新增SSE的支持,并编写示例代码

master
管理员 12 months ago
parent 3259db4673
commit 4983d8d821

@ -0,0 +1,31 @@
package com.ruoyi.web.controller;
import com.ruoyi.common.annotation.Dev;
import com.ruoyi.common.sse.SseApiSupport;
import com.ruoyi.common.sse.SseEmitter;
import com.ruoyi.common.utils.IdUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sse-test")
@ConditionalOnProperty(prefix = "ruoyi",name = "dev",havingValue = "true")
@Slf4j
public class SseTestApi extends SseApiSupport {
@PostMapping
public SseEmitter getSseEmitter() {
return handleSubscribe(null);
}
@Scheduled(fixedRate = 1000)
public void rate() {
String id = IdUtils.nextDateId("sse-test", 17);
// log.info(id);
sendAll(id);
}
}

@ -38,20 +38,23 @@
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-3071120230427001",
"@dcloudio/uni-app-plus": "3.0.0-3071120230427001",
"@dcloudio/uni-components": "3.0.0-3071120230427001",
"@dcloudio/uni-h5": "3.0.0-3071120230427001",
"@dcloudio/uni-app": "3.0.0-4040520250104002",
"@dcloudio/uni-app-harmony": "3.0.0-4040520250104002",
"@dcloudio/uni-app-plus": "3.0.0-4040520250104002",
"@dcloudio/uni-components": "3.0.0-4040520250104002",
"@dcloudio/uni-h5": "3.0.0-4040520250104002",
"@dcloudio/uni-helper-json": "^1.0.13",
"@dcloudio/uni-mp-alipay": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-baidu": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-jd": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-lark": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-qq": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-toutiao": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-weixin": "3.0.0-3071120230427001",
"@dcloudio/uni-quickapp-webview": "3.0.0-3071120230427001",
"@dcloudio/uni-mp-alipay": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-baidu": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-jd": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-lark": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-qq": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-toutiao": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-weixin": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-xhs": "3.0.0-4040520250104002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4040520250104002",
"@microsoft/fetch-event-source": "2.0.1",
"clipboard": "2.0.11",
"dayjs": "1.11.13",
"pinia": "2.0.22",
@ -62,12 +65,13 @@
},
"devDependencies": {
"@dcloudio/types": "3.4.14",
"@dcloudio/uni-automator": "3.0.0-3071120230427001",
"@dcloudio/uni-cli-shared": "3.0.0-3071120230427001",
"@dcloudio/uni-stacktracey": "3.0.0-3071120230427001",
"@dcloudio/vite-plugin-uni": "3.0.0-3071120230427001",
"@dcloudio/uni-automator": "3.0.0-4040520250104002",
"@dcloudio/uni-cli-shared": "3.0.0-4040520250104002",
"@dcloudio/uni-stacktracey": "3.0.0-4040520250104002",
"@dcloudio/vite-plugin-uni": "3.0.0-4040520250104002",
"@vue/runtime-core": "^3.4.21",
"sass": "1.59.3",
"sass-loader": "10.4.1",
"vite": "4.1.4"
"vite": "5.2.8"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,360 @@
import { useAuthStore } from '@/store';
import { env } from '@/env';
import { params, URLSearchParams } from '@/URLSearchParams'
// #ifdef MP-WEIXIN
function uniEventSource(params) {
let uEventSource = {}
let {
url = '',
method = "POST",
header = {},
data = {},
sslVerify = false,
onopen = () => { },
onmessage = (message) => { },
onclose = () => { },
onerror = (error) => { },
} = params
if (!url) {
console.error("URL属性不能为空请添加 EventSource 地址")
return;
}
const requestTask = uni.request({
url,
enableChunked: true,
method,
sslVerify,
data,
header,
complete(res) {
if (res.statusCode != 200) {
onerror(res)
}
onclose()
}
})
requestTask.onHeadersReceived((res) => {
if (res.statusCode == 200) {
onopen()
} else {
console.error("链接失败")
}
})
requestTask.onChunkReceived(res => {
const uint8Array = new Uint8Array(res.data);
let text = String.fromCharCode.apply(null, uint8Array)
text = decodeURIComponent(escape(text))
onmessage(text)
})
uEventSource.abort = () => {
requestTask.offChunkReceived()
// requestTask.abort()
onclose()
}
uEventSource.url = url
uEventSource.method = method
uEventSource.header = header
uEventSource.data = data
return uEventSource
}
/**
* @description: 创建sse连接
*/
class ServerSentEvents {
static defaultConfig = {
base: env.baseApi, // 基础地址
url: '/sse', // 地址
data: undefined, // 请求正文
params: undefined, // 请求参数
method: 'get', // 提交方式
auth: true, // 是否携带token
json: true, // 是否返回json
returnData: false, // json数据是否返回data属性
reconnect: true, //是否重连
headers: {
'Content-Type': 'application/json'
},
onopen: () => { },
onmessage: () => { },
onerror: () => { },
onclose: () => { }
}
constructor(config) {
if (config) {
this.setConfig(config)
this.init()
}
}
static get(url, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
return new ServerSentEvents(config)
}
static post(url, data, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
config.method = 'post'
config.data = data
return new ServerSentEvents(config)
}
setConfig(config) {
this.config = {
...ServerSentEvents.defaultConfig,
...config
}
}
init() {
if (this.config.auth) {
this.config.headers.Authorization = 'Bearer ' + useAuthStore().token
}
let url = this.config.url
// 如果url不含协议
if (url.indexOf("//") == -1) {
url = this.config.base + url
}
if (this.config.params) {
if (url.indexOf("?") > -1) {
url += '&' + params(this.config.params).toString()
} else {
url += '?' + params(this.config.params).toString()
}
}
let body = undefined
if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
if (this.config.data.constructor == URLSearchParams) {
this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
body = params(this.config.data).toString()
} else {
body = JSON.stringify(body)
}
}
this.config._url = url
this.config._body = body
this.send()
}
send() {
this.sse = uniEventSource({
url: this.config._url,
method: this.config.method,
header: this.config.headers,
data: this.config._body,
onopen: this.config.onopen,
onmessage: (msg) => {
if (msg?.startsWith("data:")) {
msg = msg.substring(5)
if (!msg.trim()) {
return;
}
if (this.config.json) {
// console.debug("msg", msg)
let data = JSON.parse(msg)
if (this.config.returnData) {
data = data.data
}
this.config.onmessage(data)
} else {
this.config.onmessage(msg)
}
}
},
onclose: () => {
console.info('onclose')
// this.abort()
this.config.onclose()
if (this.config.reconnect) {
this.sse = undefined
this.send()
}
},
onerror: (err) => {
console.error(err)
this.config.onerror(err)
}
});
}
abort() {
if (this.sse) {
try {
this.sse.abort();
} catch (e) {
console.error(e)
}
this.sse = undefined
}
}
close() {
this.config.reconnect = false;
this.abort()
}
}
// #endif
// #ifdef H5
import { fetchEventSource } from '@microsoft/fetch-event-source'
// pnpm add @microsoft/fetch-event-source@2.0.1
class ServerSentEvents {
static defaultConfig = {
base: env.baseApi, // 基础地址
url: '/sse', // 地址
data: undefined, // 请求正文
params: undefined, // 请求参数
method: 'get', // 提交方式
auth: true, // 是否携带token
json: true, // 是否返回json
returnData: false, // json数据是否返回data属性
reconnect: true, //是否重连
headers: {
'Content-Type': 'application/json'
},
onopen: () => { },
onmessage: () => { },
onerror: () => { },
onclose: () => { }
}
constructor(config) {
if (config) {
this.setConfig(config)
this.init()
}
}
static get(url, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
return new ServerSentEvents(config)
}
static post(url, data, onmessage, config = {}) {
config.onmessage = onmessage
config.url = url
config.method = 'post'
config.data = data
return new ServerSentEvents(config)
}
setConfig(config) {
this.config = {
ctrl: new AbortController(),
...ServerSentEvents.defaultConfig,
...config
}
}
init() {
if (this.config.auth) {
this.config.headers.Authorization = 'Bearer ' + useAuthStore().token
}
let url = this.config.url
// 如果url不含协议
if (url.indexOf("//") == -1) {
url = this.config.base + url
}
if (this.config.params) {
if (url.indexOf("?") > -1) {
url += '&' + this.params(this.config.params)
} else {
url += '?' + this.params(this.config.params)
}
}
let body = undefined
if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
if (this.config.data.constructor == URLSearchParams) {
this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
body = this.params(this.config.data).toString()
} else if (this.config.data.constructor == FormData) {
this.config.headers['Content-Type'] = 'multipart/form-data'
body = this.config.data
} else {
body = JSON.stringify(body)
}
}
this.config._url = url
this.config._body = body
console.debug(this.config)
this.send()
}
send() {
fetchEventSource(this.config._url, {
method: this.config.method,
headers: this.config.headers,
body: this.config._body,
signal: this.config.ctrl.signal,
onopen: this.config.onopen,
onmessage: (msg) => {
if (this.config.json) {
let data = JSON.parse(msg.data)
if (this.config.returnData) {
data = data.data
}
this.config.onmessage(data)
} else {
this.config.onmessage(msg)
}
},
onclose: () => {
console.info('onclose')
this.abort()
this.config.onclose()
if (this.config.reconnect) {
this.send()
}
},
onerror: (err) => {
console.error(err)
this.abort()
this.config.onerror(err)
}
})
}
abort() {
if (this.config.ctrl && !this.config.reconnect) {
try {
this.config.ctrl.abort()
} catch (e) {
console.error(e)
}
}
}
close() {
this.config.reconnect = false;
this.abort()
}
}
// #endif
export {
params, ServerSentEvents as SSE
}
export default ServerSentEvents

@ -0,0 +1,82 @@
// #ifndef H5
class URLSearchParams {
constructor(queryString) {
this.params = new Map();
if (queryString) {
queryString.split('&').forEach(pair => {
const [key, value] = pair.split('=');
this.params.set(decodeURIComponent(key), decodeURIComponent(value));
});
}
}
append(key, value) {
this.params.set(key, value);
}
delete(key) {
this.params.delete(key);
}
get(key) {
const values = [...this.params.values()];
return values.length ? values[0] : null;
}
getAll(key) {
return this.params.get(key) || [];
}
has(key) {
return this.params.has(key);
}
set(key, value) {
this.params.set(key, value);
}
sort() {
// 按键排序
const sortedEntries = [...this.params.entries()].sort((a, b) => a[0].localeCompare(b[0]));
this.params = new Map(sortedEntries);
}
forEach(callbackFn, thisArg) {
this.params.forEach(callbackFn, thisArg);
}
toString() {
return [...this.params.entries()].map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');
}
}
// #endif
// #ifdef H5
const URLSearchParams = window.URLSearchParams;
// #endif
function params(param) {
if (param == null || param == "") {
return new URLSearchParams();
}
if (param.constructor == Array) {
let param1 = new URLSearchParams();
for (let obj of param) {
param1.append(obj.name, obj.value);
}
param = param1;
} else {
let param1 = new URLSearchParams();
for (let name in param) {
param1.append(name, param[name]);
}
param = param1;
}
return param;
}
export {
params, URLSearchParams
}

@ -1,5 +1,5 @@
{
"name" : "教学质量评价平台",
"name" : "某某系统",
"appid" : "__UNI__59B9EAC",
"description" : "",
"versionName" : "1.0.0",

@ -150,6 +150,12 @@
"style": {
"navigationBarTitleText": "WebSocket使用示例"
}
},
{
"path": "demo-sse",
"style": {
"navigationBarTitleText": "SSE使用示例"
}
}
]
}

@ -0,0 +1,55 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="SSE使用示例"></w-navbar>
<view class="w-pre">{{ text }}</view>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady, onUnload, onHide } from "@dcloudio/uni-app";
import { ref, getCurrentInstance } from "vue";
import { SSE } from "@/SSE";
const { proxy } = getCurrentInstance();
const text = ref("")
let sse = undefined;
onLoad(()=>{
console.debug("onLoad")
})
onShow(()=>{
console.debug("onShow")
});
onReady(()=>{
console.debug("onReady")
})
onUnload(()=>{
console.debug("onUnload")
})
onShow(()=>{
sse = SSE.post("/sse-test", {}, (data) => {
console.debug(data);
text.value += '\n'+JSON.stringify(data)
})
});
onUnload(() => {
sse.close();
});
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg);
font-size: 0.9rem;
min-height: 100vh;
}
</style>

@ -1,64 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="学生日课程表"></w-navbar>
<view class="w-flex w-p">
<view style="width: 30%;"><u-input v-model="xh1" /></view>
<view style="width: 40%;"><x-student :id="xh1"/></view>
<view style="width: 30%;"><u-button @click="xh = xh1;">设置学号</u-button></view>
</view>
<view class="w-flex w-p">
<view style="width: 50vw;" class="w-flex">{{ rq }}</view>
<view style="width: 50vw;"><u-button @click="show = true;">设置日期</u-button></view>
</view>
<view class="w-p">
<x-student-course-day :xh="xh" :rq="rq" />
</view>
<view class="w-p">
<x-student-course-day style="--size:12px; --text:var(--w-main);" :xh="xh" :rq="rq" />
</view>
<u-datetime-picker :show="show" v-model="rq1" mode="date" @confirm="show = false"
@cancel="show = false"></u-datetime-picker>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance, computed } from 'vue'
const { proxy } = getCurrentInstance();
const xh = ref("2301010001");
const xh1 = ref("2301010001");
const rq = ref('2024-03-07');
const rq1 = computed({
get() {
return rq.value.toDate();
},
set(value) {
rq.value = new Date(value).format();
}
})
const show = ref(false);
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg-light);
font-size: .9rem;
min-height: 100vh;
.w-p {
padding: 1rem;
}
}
</style>

@ -1,98 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="学生周课程表"></w-navbar>
<view class="w-flex w-p">
<view style="width: 30%;"><u-input v-model="xh1" /></view>
<view style="width: 40%;"><x-student :id="xh1"><template #error>错误的学号</template></x-student></view>
<view style="width: 30%;"><u-button @click="xh = xh1;">设置学号</u-button></view>
</view>
<view style="padding: 1rem;" class="w-flex">
<view style="position: relative; padding: .5rem 1rem; font-weight: bold; font-size: 1rem; display: flex;"
hover-class="w-hover-before" @click="proxy.$refs.xqRef.open();">
{{ xqs[0] }}年至{{ xqs[1] }}年第{{ xqs[2] }}学期
<u-icon name="arrow-down" style="margin-left: .5rem;" />
</view>
</view>
<view
style="padding: .5rem; margin: 0 1rem 1rem; background-color: var(--w-warn-light-2); color: var(--w-warn-dark-1); font-size: .7rem; border-radius: .5rem;">
学期:{{ xqInfo.XQMC }},教学周:{{ xqInfo.QSSKZ }}-{{ xqInfo.ZZSKZ
}},教学日期:{{ xqInfo.XQQSSJ }} {{ xqInfo.XQZZSJ }}
</view>
<view style="display: flex; flex-wrap: wrap; padding-left: .5rem;">
<view v-for="i in zcList" :key="i" class="week" :class="{selected: i==zc}" @click="zc=i;">{{ i.toString().padStart(2, '0') }}</view>
</view>
<view style="padding: .2rem;">
<x-student-course-week :xh="xh" :xq="xq" :zc="zc" />
</view>
<x-xq-select ref="xqRef" v-model="xq" v-model:info="xqInfo" current />
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance, computed } from 'vue'
const { proxy } = getCurrentInstance();
const xh = ref("2301010001");
const xh1 = ref("2301010001");
const xq = ref("");
const xqInfo = ref({});
const xqs = computed(() => {
if (xq.value) {
return xq.value.split('-')
} else {
return ['', '', '']
}
})
const zcList = computed(() => {
if (xqInfo.value.QSSKZ && xqInfo.value.ZZSKZ) {
let list = [];
for (let i = Number(xqInfo.value.QSSKZ); i <= Number(xqInfo.value.ZZSKZ); i++) {
list.push(i);
}
return list;
}
return [];
})
const zc = ref(1);
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg-light);
font-size: .9rem;
min-height: 100vh;
.w-p {
padding: 1rem;
}
.week {
padding: .3rem .5rem;
margin: 0 .5rem .5rem 0;
border: solid 1px #0002;
border-radius: .2rem;
&.selected {
border-color: var(--w-main);
color: var(--w-main);
}
}
}
</style>

@ -1,49 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="带数字的分段器"></w-navbar>
<view style="padding: 2rem;">
<x-tabs v-model="indexs[0]" />
{{ indexs[0] }}
</view>
<view style="padding: 2rem;">
<x-tabs v-model="indexs[1]" :tabs="list1" style="--size:1.3rem; --color: #00F;" />
{{ indexs[1] }}
</view>
<view style="padding: 1rem; display: flex; justify-content: flex-end;">
<view style="width: 80%;"><x-tabs v-model="indexs[2]" :tabs="list2" style="--size:0.6rem; --color: var(--w-success-dark-1); --num-color:#00f;" /></view>
{{ indexs[2] }}
</view>
<view style="padding: 2rem;">
<x-tabs v-model="indexs[2]" :tabs="list2" style="--size:.8rem; --border-radius: .2rem;" />
{{ indexs[2] }}
</view>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref } from 'vue'
const indexs = ref([0, 0, 0, 0]);
const list1 = ["张三", "李四"];
const list2 = [{ lable: '张三', num: 9 }, '李四', { lable: '王五', num: 5 }];
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg);
font-size: .9rem;
min-height: 100vh;
}
</style>

@ -1,64 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="教师日课程表"></w-navbar>
<view class="w-flex w-p">
<view style="width: 30%;"><u-input v-model="gh1" /></view>
<view style="width: 40%;"><x-teacher :id="gh1"/></view>
<view style="width: 30%;"><u-button @click="gh = gh1;">设置工号</u-button></view>
</view>
<view class="w-flex w-p">
<view style="width: 50vw;" class="w-flex">{{ rq }}</view>
<view style="width: 50vw;"><u-button @click="show = true;">设置日期</u-button></view>
</view>
<view class="w-p">
<x-teacher-course-day :gh="gh" :rq="rq" />
</view>
<view class="w-p">
<x-teacher-course-day style="--size:12px; --text:var(--w-main);" :gh="gh" :rq="rq" />
</view>
<u-datetime-picker :show="show" v-model="rq1" mode="date" @confirm="show = false"
@cancel="show = false"></u-datetime-picker>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance, computed } from 'vue'
const { proxy } = getCurrentInstance();
const gh = ref("2421");
const gh1 = ref("2421");
const rq = ref('2023-09-18');
const rq1 = computed({
get() {
return rq.value.toDate();
},
set(value) {
rq.value = new Date(value).format();
}
})
const show = ref(false);
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg-light);
font-size: .9rem;
min-height: 100vh;
.w-p {
padding: 1rem;
}
}
</style>

@ -1,98 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="教师周课程表"></w-navbar>
<view class="w-flex w-p">
<view style="width: 30%;"><u-input v-model="gh1" /></view>
<view style="width: 40%;"><x-teacher :id="gh1"/></view>
<view style="width: 30%;"><u-button @click="gh = gh1;">设置工号</u-button></view>
</view>
<view style="padding: 1rem;" class="w-flex">
<view style="position: relative; padding: .5rem 1rem; font-weight: bold; font-size: 1rem; display: flex;"
hover-class="w-hover-before" @click="proxy.$refs.xqRef.open();">
{{ xqs[0] }}年至{{ xqs[1] }}年第{{ xqs[2] }}学期
<u-icon name="arrow-down" style="margin-left: .5rem;" />
</view>
</view>
<view
style="padding: .5rem; margin: 0 1rem 1rem; background-color: var(--w-warn-light-2); color: var(--w-warn-dark-1); font-size: .7rem; border-radius: .5rem;">
学期:{{ xqInfo.XQMC }},教学周:{{ xqInfo.QSSKZ }}-{{ xqInfo.ZZSKZ
}},教学日期:{{ xqInfo.XQQSSJ }} {{ xqInfo.XQZZSJ }}
</view>
<view style="display: flex; flex-wrap: wrap; padding-left: .5rem;">
<view v-for="i in zcList" :key="i" class="week" :class="{selected: i==zc}" @click="zc=i;">{{ i.toString().padStart(2, '0') }}</view>
</view>
<view style="padding: .2rem;">
<x-teacher-course-week :gh="gh" :xq="xq" :zc="zc" />
</view>
<x-xq-select ref="xqRef" v-model="xq" v-model:info="xqInfo" current />
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance, computed } from 'vue'
const { proxy } = getCurrentInstance();
const gh = ref("2496");
const gh1 = ref("2496");
const xq = ref("");
const xqInfo = ref({});
const xqs = computed(() => {
if (xq.value) {
return xq.value.split('-')
} else {
return ['', '', '']
}
})
const zcList = computed(() => {
if (xqInfo.value.QSSKZ && xqInfo.value.ZZSKZ) {
let list = [];
for (let i = Number(xqInfo.value.QSSKZ); i <= Number(xqInfo.value.ZZSKZ); i++) {
list.push(i);
}
return list;
}
return [];
})
const zc = ref(1);
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg-light);
font-size: .9rem;
min-height: 100vh;
.w-p {
padding: 1rem;
}
.week {
padding: .3rem .5rem;
margin: 0 .5rem .5rem 0;
border: solid 1px #0002;
border-radius: .2rem;
&.selected {
border-color: var(--w-main);
color: var(--w-main);
}
}
}
</style>

@ -1,50 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="教学周历"></w-navbar>
<view style="padding: 1rem;" class="w-flex">
<view style="position: relative; padding: .5rem 1rem; font-weight: bold; font-size: 1rem; display: flex;" hover-class="w-hover-before" @click="proxy.$refs.xqRef.open();">
{{ xqs[0] }}年至{{ xqs[1] }}年第{{ xqs[2] }}学期
<u-icon name="arrow-down" style="margin-left: .5rem;" />
</view>
</view>
<view style="padding: .5rem; margin: 0 1rem 1rem; background-color: var(--w-warn-light-2); color: var(--w-warn-dark-1); font-size: .7rem; border-radius: .5rem;">
学期:{{ xqInfo.XQMC }},教学周:{{ xqInfo.QSSKZ }}-{{ xqInfo.ZZSKZ
}},教学日期:{{ xqInfo.XQQSSJ }} {{ xqInfo.XQZZSJ }}
</view>
<x-weeks :xq="xq" style="--size: 5vmin;"/>
<x-xq-select ref="xqRef" v-model="xq" v-model:info="xqInfo" current />
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance, computed } from 'vue'
const { proxy } = getCurrentInstance();
const xq = ref("");
const xqInfo = ref({});
const xqs = computed(()=>{
if(xq.value){
return xq.value.split('-')
}else{
return ['','','']
}
})
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg-light);
font-size: .9rem;
min-height: 100vh;
}
</style>

@ -1,26 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="课程节次"></w-navbar>
<view style="padding: 1rem;"><x-work-time/></view>
<view style="padding: 1rem;"><x-work-time style="--text:#c00; --tabs-color:#00c;font-size: 1rem;"/></view>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref } from 'vue'
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg);
font-size: .9rem;
min-height: 100vh;
}
</style>

@ -1,33 +0,0 @@
<template>
<view class="w-body">
<w-public />
<w-navbar left-back fixed title="学期选择器"></w-navbar>
<view>
<view>学期:{{ xq }} <u-button @click="proxy.$refs.xqSelectRef.open();"></u-button></view>
<view>学期信息:{{ xqInfo }}</view>
</view>
<x-xq-select ref="xqSelectRef" v-model="xq" v-model:info="xqInfo" current/>
</view>
</template>
<script setup>
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { ref, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance();
const xq=ref("2021-2022-1");
const xqInfo = ref({});
</script>
<style lang="scss" scoped>
.w-body {
--navbar-height: 44px;
background-color: var(--w-bg);
font-size: .9rem;
}
</style>

@ -28,6 +28,9 @@
<u-list-item>
<u-cell isLink url="/pages/demo/demo6" title="WebSocket使用示例"></u-cell>
</u-list-item>
<u-list-item>
<u-cell isLink url="/pages/demo/demo-sse" title="SSE使用示例"></u-cell>
</u-list-item>
</u-list>
</w-safe-area>
<w-footer></w-footer>

@ -0,0 +1,8 @@
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
uni(),
],
})
Loading…
Cancel
Save