forked from wts/wts
运行lint,将theLastPage的内容存储在sessionStorage里
This commit is contained in:
3
front/src/app.d.ts
vendored
3
front/src/app.d.ts
vendored
@@ -10,7 +10,4 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export {};
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
import Settings from 'carbon-icons-svelte/lib/Settings.svelte';
|
||||
import Home from 'carbon-icons-svelte/lib/Home.svelte';
|
||||
import Return from 'carbon-icons-svelte/lib/Return.svelte';
|
||||
import SearchAdvanced from "carbon-icons-svelte/lib/SearchAdvanced.svelte";
|
||||
import CarbonForIbmDotcom from "carbon-icons-svelte/lib/CarbonForIbmDotcom.svelte";
|
||||
import EventSchedule from "carbon-icons-svelte/lib/EventSchedule.svelte";
|
||||
import SearchAdvanced from 'carbon-icons-svelte/lib/SearchAdvanced.svelte';
|
||||
import CarbonForIbmDotcom from 'carbon-icons-svelte/lib/CarbonForIbmDotcom.svelte';
|
||||
import EventSchedule from 'carbon-icons-svelte/lib/EventSchedule.svelte';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let isAdminView = $derived(page.url.pathname.startsWith('/admin'));
|
||||
@@ -45,12 +45,15 @@
|
||||
<span>后台中心</span>
|
||||
</a>
|
||||
|
||||
<a href="/op/ticket_search" class="nav-item" class:active={page.url.pathname === '/op/ticket_search'}>
|
||||
<a
|
||||
href="/op/ticket_search"
|
||||
class="nav-item"
|
||||
class:active={page.url.pathname === '/op/ticket_search'}
|
||||
>
|
||||
<SearchAdvanced />
|
||||
<span>检索工单</span>
|
||||
</a>
|
||||
<a href="/op/scheduler" class="nav-item" class:active={page.url.pathname === '/op/scheduler'}>
|
||||
|
||||
<EventSchedule />
|
||||
<span>我的排班</span>
|
||||
</a>
|
||||
@@ -69,12 +72,19 @@
|
||||
<span>管理中心</span>
|
||||
</a>
|
||||
|
||||
<a href="/admin/add_ticket" class="nav-item" class:active={page.url.pathname === '/admin/add_ticket'}>
|
||||
<a
|
||||
href="/admin/add_ticket"
|
||||
class="nav-item"
|
||||
class:active={page.url.pathname === '/admin/add_ticket'}
|
||||
>
|
||||
<SearchAdvanced />
|
||||
<span>增添工单</span>
|
||||
</a>
|
||||
<a href="/admin/scheduler" class="nav-item" class:active={page.url.pathname === '/admin/scheduler'}>
|
||||
|
||||
<a
|
||||
href="/admin/scheduler"
|
||||
class="nav-item"
|
||||
class:active={page.url.pathname === '/admin/scheduler'}
|
||||
>
|
||||
<EventSchedule />
|
||||
<span>成员排班</span>
|
||||
</a>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { BlockMap } from '$lib/types/enum';
|
||||
import type { WtsBlock } from '$lib/types/enum';
|
||||
let { b,r }: { b: WtsBlock, r: string } = $props();
|
||||
let { b, r }: { b: WtsBlock; r: string } = $props();
|
||||
</script>
|
||||
|
||||
<span>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
let { a }: { a: WtsAccess } = $props();
|
||||
</script>
|
||||
|
||||
<span class="inline-block bg-gray-300 px-3 py-1 text-[15px] rounded-[19px]">
|
||||
<span class="inline-block rounded-[19px] bg-gray-300 px-3 py-1 text-[15px]">
|
||||
{AccessMap[a]}
|
||||
</span>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
canceled: 'text-gray-500'
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if s === 'scheduled' && isSameDay(ap, new Date())}
|
||||
<span>
|
||||
<strong class="text-blue-600">已预约</strong>
|
||||
|
||||
@@ -25,7 +25,12 @@
|
||||
open = $bindable(TicketModal.Opened),
|
||||
src = TicketModal.SRC,
|
||||
onTicketChanged
|
||||
}: { t?: Ticket | null; open?: boolean; src?: 'user' | 'operator'; onTicketChanged?: () => void | Promise<void>;} = $props();
|
||||
}: {
|
||||
t?: Ticket | null;
|
||||
open?: boolean;
|
||||
src?: 'user' | 'operator';
|
||||
onTicketChanged?: () => void | Promise<void>;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let traces: Trace[] = $state([]);
|
||||
@@ -129,7 +134,15 @@
|
||||
<NotificationQueue bind:this={q1} />
|
||||
<ModalHeader title=" 🖋️请更新No.{getTid(t)}的状态" />
|
||||
<ModalBody>
|
||||
<TraceUpdateView {t} bind:view bind:open bind:isUpReady {q} {q1} onUpdated={onTicketChanged} />
|
||||
<TraceUpdateView
|
||||
{t}
|
||||
bind:view
|
||||
bind:open
|
||||
bind:isUpReady
|
||||
{q}
|
||||
{q1}
|
||||
onUpdated={onTicketChanged}
|
||||
/>
|
||||
</ModalBody>
|
||||
<UpViewButton bind:view bind:isUpReady />
|
||||
</ComposedModal>
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
let {
|
||||
view = $bindable<'trace' | 'cancel' | 'update'>(),
|
||||
isUpReady = $bindable<boolean>(),
|
||||
isUpReady = $bindable<boolean>()
|
||||
}: {
|
||||
view: 'trace' | 'cancel' | 'update',
|
||||
isUpReady: boolean,
|
||||
view: 'trace' | 'cancel' | 'update';
|
||||
isUpReady: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ export function Guard(a: (subject: WtsAccess) => boolean) {
|
||||
return;
|
||||
}
|
||||
if (!a(jwt.access)) {
|
||||
if(jwt.access === "unregistered"){
|
||||
if (jwt.access === 'unregistered') {
|
||||
goto('/register');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
//全局状态,保存用户刚刚访问的页面以便JWT获取后跳转回来
|
||||
class theLastPage {
|
||||
p = $state('/');
|
||||
|
||||
constructor() {
|
||||
if (browser) {
|
||||
this.p = sessionStorage.getItem('_the_last_page') || '/';
|
||||
}
|
||||
}
|
||||
|
||||
Write(p: string) {
|
||||
this.p = p;
|
||||
if (browser) {
|
||||
sessionStorage.setItem('_the_last_page', p);
|
||||
}
|
||||
}
|
||||
|
||||
Read(): string {
|
||||
const p1 = this.p;
|
||||
this.p = '/';
|
||||
if (browser) {
|
||||
sessionStorage.removeItem('_the_last_page');
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export let criteria: Criteria = {
|
||||
category: [],
|
||||
isp: [],
|
||||
newer_than: undefined,
|
||||
older_than: undefined,
|
||||
older_than: undefined
|
||||
},
|
||||
_order: 'priority',
|
||||
_floor: null,
|
||||
@@ -38,12 +38,11 @@ export function resetCriteria() {
|
||||
category: [],
|
||||
isp: [],
|
||||
newer_than: undefined,
|
||||
older_than: undefined,
|
||||
older_than: undefined
|
||||
},
|
||||
_order: 'priority',
|
||||
_floor: null,
|
||||
_blocks_in_zone: [],
|
||||
_view_today_scheduled: false
|
||||
} as Criteria;
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export const sample1issuer: UserProfile = {
|
||||
phone: '13800138000',
|
||||
isp: 'mobile',
|
||||
account: '12345678901@139.gd',
|
||||
wx: 'zhangsan_wx',
|
||||
wx: 'zhangsan_wx'
|
||||
};
|
||||
|
||||
export const sample1: Ticket = {
|
||||
@@ -21,7 +21,7 @@ export const sample1: Ticket = {
|
||||
category: 'ip-or-device',
|
||||
status: 'scheduled',
|
||||
priority: 'assigned',
|
||||
appointed_at: NowRFC3339(),
|
||||
appointed_at: NowRFC3339()
|
||||
};
|
||||
|
||||
export const sample2issuer: UserProfile = {
|
||||
@@ -33,7 +33,7 @@ export const sample2issuer: UserProfile = {
|
||||
phone: '13800138000',
|
||||
isp: 'telecom',
|
||||
account: '18923456789',
|
||||
wx: 'zhangsan_wx',
|
||||
wx: 'zhangsan_wx'
|
||||
};
|
||||
|
||||
export const sample2: Ticket = {
|
||||
@@ -44,7 +44,7 @@ export const sample2: Ticket = {
|
||||
submitted_at: RFC3339('2024-01-01T00:10:00Z'),
|
||||
category: 'first-install',
|
||||
status: 'fresh',
|
||||
priority: 'mainline',
|
||||
priority: 'mainline'
|
||||
};
|
||||
|
||||
export const sampleTrace: Trace[] = [
|
||||
@@ -56,7 +56,7 @@ export const sampleTrace: Trace[] = [
|
||||
op_name: '(用户操作)',
|
||||
remark: '工单已提交',
|
||||
new_status: 'fresh',
|
||||
new_priority: 'mainline',
|
||||
new_priority: 'mainline'
|
||||
},
|
||||
{
|
||||
opid: 2,
|
||||
@@ -66,7 +66,7 @@ export const sampleTrace: Trace[] = [
|
||||
op_name: '哈哈哈',
|
||||
remark: '用户预约了时间',
|
||||
new_status: 'scheduled',
|
||||
new_appointment: RFC3339('2024-01-13T14:00:00Z'),
|
||||
new_appointment: RFC3339('2024-01-13T14:00:00Z')
|
||||
},
|
||||
{
|
||||
opid: 3,
|
||||
@@ -75,7 +75,7 @@ export const sampleTrace: Trace[] = [
|
||||
op: '2395',
|
||||
op_name: '啊啊啊',
|
||||
remark: '材料不足,改日修',
|
||||
new_status: 'delay',
|
||||
new_status: 'delay'
|
||||
},
|
||||
{
|
||||
opid: 4,
|
||||
@@ -85,7 +85,7 @@ export const sampleTrace: Trace[] = [
|
||||
op_name: '嘿嘿嘿',
|
||||
remark: '与用户重新约定时间,预约在2024-01-21下午',
|
||||
new_status: 'scheduled',
|
||||
new_appointment: RFC3339('2024-01-21T15:00:00Z'),
|
||||
new_appointment: RFC3339('2024-01-21T15:00:00Z')
|
||||
},
|
||||
{
|
||||
opid: 5,
|
||||
@@ -94,6 +94,6 @@ export const sampleTrace: Trace[] = [
|
||||
op: '2395',
|
||||
op_name: '喵喵喵',
|
||||
remark: '问题解决:用户路由器线路接触不良,更换后恢复正常',
|
||||
new_status: 'solved',
|
||||
},
|
||||
new_status: 'solved'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,32 +1,80 @@
|
||||
export type WtsBlock =
|
||||
| '1'| '2'| '3'| '4'| '5'| '6' //凤翔
|
||||
| '7'| '8'| '9'| '10'| '11' //北门
|
||||
| '12'| '13'| '14'| '15'| '20'| '21'| '22' //东门
|
||||
| '16'| '17'| '18'| '19' //岐头
|
||||
| 'XHA'| 'XHB'| 'XHC'| 'XHD' //香晖
|
||||
| '1'
|
||||
| '2'
|
||||
| '3'
|
||||
| '4'
|
||||
| '5'
|
||||
| '6' //凤翔
|
||||
| '7'
|
||||
| '8'
|
||||
| '9'
|
||||
| '10'
|
||||
| '11' //北门
|
||||
| '12'
|
||||
| '13'
|
||||
| '14'
|
||||
| '15'
|
||||
| '20'
|
||||
| '21'
|
||||
| '22' //东门
|
||||
| '16'
|
||||
| '17'
|
||||
| '18'
|
||||
| '19' //岐头
|
||||
| 'XHA'
|
||||
| 'XHB'
|
||||
| 'XHC'
|
||||
| 'XHD' //香晖
|
||||
| 'ZH' //朝晖
|
||||
| 'other';
|
||||
|
||||
export const BlockMap: Record<WtsBlock, string> = {
|
||||
'1':'1栋','2':'2栋','3':'3栋','4':'4栋','5':'5栋','6':'6栋',
|
||||
'7':'7栋','8':'8栋','9':'9栋','10':'10栋','11':'11栋',
|
||||
'12':'12栋','13':'13栋','14':'14栋','15':'15栋','20':'20栋','21':'21栋','22':'22栋',
|
||||
'16':'16栋','17':'17栋','18':'18栋','19':'19栋',
|
||||
'XHA':'香晖A','XHB':'香晖B','XHC':'香晖C','XHD':'香晖D',
|
||||
'ZH':'朝晖',
|
||||
'other':'其它',
|
||||
}
|
||||
'1': '1栋',
|
||||
'2': '2栋',
|
||||
'3': '3栋',
|
||||
'4': '4栋',
|
||||
'5': '5栋',
|
||||
'6': '6栋',
|
||||
'7': '7栋',
|
||||
'8': '8栋',
|
||||
'9': '9栋',
|
||||
'10': '10栋',
|
||||
'11': '11栋',
|
||||
'12': '12栋',
|
||||
'13': '13栋',
|
||||
'14': '14栋',
|
||||
'15': '15栋',
|
||||
'20': '20栋',
|
||||
'21': '21栋',
|
||||
'22': '22栋',
|
||||
'16': '16栋',
|
||||
'17': '17栋',
|
||||
'18': '18栋',
|
||||
'19': '19栋',
|
||||
XHA: '香晖A',
|
||||
XHB: '香晖B',
|
||||
XHC: '香晖C',
|
||||
XHD: '香晖D',
|
||||
ZH: '朝晖',
|
||||
other: '其它'
|
||||
};
|
||||
|
||||
export type WtsAccess =
|
||||
| 'dev'
|
||||
| 'chief'| 'api'| 'group-leader'
|
||||
| 'formal-member'| 'informal-member'
|
||||
| 'pre-member'| 'user'
|
||||
| 'chief'
|
||||
| 'api'
|
||||
| 'group-leader'
|
||||
| 'formal-member'
|
||||
| 'informal-member'
|
||||
| 'pre-member'
|
||||
| 'user'
|
||||
| 'unregistered';
|
||||
|
||||
export const IsAccessIn = (...targets: WtsAccess[]) => (subject: WtsAccess): boolean => {
|
||||
export const IsAccessIn =
|
||||
(...targets: WtsAccess[]) =>
|
||||
(subject: WtsAccess): boolean => {
|
||||
return targets.includes(subject);
|
||||
}
|
||||
};
|
||||
|
||||
export const IsOperator = IsAccessIn(
|
||||
'api',
|
||||
@@ -37,12 +85,7 @@ export const IsOperator = IsAccessIn(
|
||||
'informal-member'
|
||||
);
|
||||
|
||||
export const IsAdmin = IsAccessIn(
|
||||
'group-leader',
|
||||
'api',
|
||||
'chief',
|
||||
'dev'
|
||||
);
|
||||
export const IsAdmin = IsAccessIn('group-leader', 'api', 'chief', 'dev');
|
||||
|
||||
export const IsUser = IsAccessIn(
|
||||
'api',
|
||||
@@ -57,108 +100,129 @@ export const IsUser = IsAccessIn(
|
||||
|
||||
export const IsPreMember = IsAccessIn('pre-member');
|
||||
|
||||
export const IsFormalMember = IsAccessIn(
|
||||
'group-leader',
|
||||
'api',
|
||||
'chief',
|
||||
'dev',
|
||||
'formal-member'
|
||||
);
|
||||
export const IsFormalMember = IsAccessIn('group-leader', 'api', 'chief', 'dev', 'formal-member');
|
||||
|
||||
export const IsUnregistered = IsAccessIn('unregistered');
|
||||
|
||||
export const AccessMap: Record<WtsAccess, string> = {
|
||||
'dev': '开发组','chief':'科长','api':'API','group-leader':'组长',
|
||||
'formal-member':'正式成员','informal-member':'实习成员',
|
||||
'pre-member':'前成员','user':'用户',
|
||||
'unregistered':'未注册用户',
|
||||
}
|
||||
|
||||
dev: '开发组',
|
||||
chief: '科长',
|
||||
api: 'API',
|
||||
'group-leader': '组长',
|
||||
'formal-member': '正式成员',
|
||||
'informal-member': '实习成员',
|
||||
'pre-member': '前成员',
|
||||
user: '用户',
|
||||
unregistered: '未注册用户'
|
||||
};
|
||||
|
||||
export type WtsISP = 'telecom' | 'unicom' | 'mobile' | 'broadnet' | 'others';
|
||||
|
||||
export const ISPMap: Record<WtsISP, string> = {
|
||||
'telecom': '电信',
|
||||
'unicom': '联通',
|
||||
'mobile': '移动',
|
||||
'broadnet': '广电',
|
||||
'others': '其它',
|
||||
}
|
||||
telecom: '电信',
|
||||
unicom: '联通',
|
||||
mobile: '移动',
|
||||
broadnet: '广电',
|
||||
others: '其它'
|
||||
};
|
||||
|
||||
export type WtsStatus = 'fresh' | 'scheduled' | 'delay' | 'escalated' | 'solved' | 'canceled';
|
||||
|
||||
export const StatusMap: Record<WtsStatus, string> = {
|
||||
'fresh': '待解决',
|
||||
'scheduled': '已预约',
|
||||
'delay': '改日修',
|
||||
'escalated': '已上报',
|
||||
'solved': '已解决',
|
||||
'canceled': '已取消',
|
||||
}
|
||||
fresh: '待解决',
|
||||
scheduled: '已预约',
|
||||
delay: '改日修',
|
||||
escalated: '已上报',
|
||||
solved: '已解决',
|
||||
canceled: '已取消'
|
||||
};
|
||||
|
||||
export type WtsPriority = 'highest' | 'assigned' | 'mainline' | 'normal' | 'in-passing' | 'least';
|
||||
|
||||
export const PriorityMap: Record<WtsPriority, string> = {
|
||||
'highest': '>>紧急派单!<<',
|
||||
'assigned': '运营商工单',
|
||||
'mainline': '主线任务',
|
||||
'normal': '普通报修',
|
||||
highest: '>>紧急派单!<<',
|
||||
assigned: '运营商工单',
|
||||
mainline: '主线任务',
|
||||
normal: '普通报修',
|
||||
'in-passing': '顺路看看',
|
||||
'least': '最低',
|
||||
}
|
||||
least: '最低'
|
||||
};
|
||||
|
||||
export type WtsCategory =
|
||||
| 'first-install'| 'low-speed'| 'ip-or-device'| 'client-or-account'| 'others';
|
||||
| 'first-install'
|
||||
| 'low-speed'
|
||||
| 'ip-or-device'
|
||||
| 'client-or-account'
|
||||
| 'others';
|
||||
|
||||
export const CategoryMap: Record<WtsCategory, string> = {
|
||||
'first-install': '新装',
|
||||
'low-speed': '网速慢',
|
||||
'ip-or-device': 'IP或设备问题',
|
||||
'client-or-account': '客户端或账号问题',
|
||||
'others': '其它问题',
|
||||
}
|
||||
others: '其它问题'
|
||||
};
|
||||
|
||||
export type WtsAPIErrorType =
|
||||
| 1 | 2 | 3 | 4 | 5;
|
||||
export type WtsAPIErrorType = 1 | 2 | 3 | 4 | 5;
|
||||
|
||||
export const APIErrorTypeMap: Record<WtsAPIErrorType, string> = {
|
||||
1: '服务器内部错误,请联系我们的技术人员。',
|
||||
2: '你的请求无效,可能是由于格式错误或不支持的操作。',
|
||||
3: '您没有进行该操作的权限。',
|
||||
4: '数据库出现错误。',
|
||||
5: '您的请求在逻辑上不被允许。',
|
||||
}
|
||||
5: '您的请求在逻辑上不被允许。'
|
||||
};
|
||||
export type WtsZone = 'FX' | 'BM' | 'DM' | 'QT' | 'XHAB' | 'XHCD' | 'ZH' | 'other' | 'all';
|
||||
|
||||
export const ZoneMap: Record<WtsZone, string> = {
|
||||
'FX':'凤翔',
|
||||
'BM':'北门',
|
||||
'DM':'东门',
|
||||
'QT':'岐头',
|
||||
'XHAB':'香晖AB',
|
||||
'XHCD':'香晖CD',
|
||||
'ZH':'朝晖',
|
||||
'other':'其它',
|
||||
'all':'全部',
|
||||
}
|
||||
FX: '凤翔',
|
||||
BM: '北门',
|
||||
DM: '东门',
|
||||
QT: '岐头',
|
||||
XHAB: '香晖AB',
|
||||
XHCD: '香晖CD',
|
||||
ZH: '朝晖',
|
||||
other: '其它',
|
||||
all: '全部'
|
||||
};
|
||||
|
||||
export const ZoneToBlock: Record<WtsZone, WtsBlock[]> = {
|
||||
'FX':['1','2','3','4','5','6'],
|
||||
'BM':['7','8','9','10','11'],
|
||||
'DM':['12','13','14','15','20','21','22'],
|
||||
'QT':['16','17','18','19'],
|
||||
'XHAB':['XHA','XHB'],
|
||||
'XHCD':['XHC','XHD'],
|
||||
'ZH':['ZH'],
|
||||
'other':['other'],
|
||||
'all':[
|
||||
'1','2','3','4','5','6',
|
||||
'7','8','9','10','11',
|
||||
'12','13','14','15','20','21','22',
|
||||
'16','17','18','19',
|
||||
'XHA','XHB',
|
||||
'XHC','XHD',
|
||||
FX: ['1', '2', '3', '4', '5', '6'],
|
||||
BM: ['7', '8', '9', '10', '11'],
|
||||
DM: ['12', '13', '14', '15', '20', '21', '22'],
|
||||
QT: ['16', '17', '18', '19'],
|
||||
XHAB: ['XHA', 'XHB'],
|
||||
XHCD: ['XHC', 'XHD'],
|
||||
ZH: ['ZH'],
|
||||
other: ['other'],
|
||||
all: [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'XHA',
|
||||
'XHB',
|
||||
'XHC',
|
||||
'XHD',
|
||||
'ZH',
|
||||
'other'
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -41,12 +41,15 @@
|
||||
<div style="display: flex; flex-direction: column; gap: 0.25rem;">
|
||||
<h2>🥺不会使用校园网?</h2>
|
||||
<p>点击下方按钮,我们准备了校园网方方面面的攻略!</p>
|
||||
<Button href="/help" kind="secondary" style="align-self: flex-end;transform: translate(-25px,0px);">网络攻略</Button>
|
||||
<Button
|
||||
href="/help"
|
||||
kind="secondary"
|
||||
style="align-self: flex-end;transform: translate(-25px,0px);">网络攻略</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</RetroCard>
|
||||
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
<p>中山学院网络维护科是一个独立的<strong>学生组织</strong>,成立于2005年,接受校信息中心的指导和管理。</p>
|
||||
<p>
|
||||
中山学院网络维护科是一个独立的<strong>学生组织</strong
|
||||
>,成立于2005年,接受校信息中心的指导和管理。
|
||||
</p>
|
||||
<p>
|
||||
网维的主要任务是保证校园宿舍网络的正常运行,处理解决在校学生所报修的有线校园网问题,这项业务主要通过依托于微信的网络报修系统来运行。
|
||||
</p>
|
||||
@@ -11,7 +14,8 @@
|
||||
目前,我们与三大运营商建立了良好的合作关系,承接运营商在校园内的装维业务;在信息中心的关怀下,我们也承担学校部分IT后勤工作。
|
||||
</p>
|
||||
<p>
|
||||
对于学生校园网报修,我们的成员会在<strong>每天16:30~18:00</strong>统一上门解决问题,用户在这个时间段必须本人在宿舍。
|
||||
对于学生校园网报修,我们的成员会在<strong>每天16:30~18:00</strong
|
||||
>统一上门解决问题,用户在这个时间段必须本人在宿舍。
|
||||
</p>
|
||||
<p>
|
||||
网维一般会在每年的9~10月招新,对象为当年新生,要求有基础的计算机知识。具体招新事宜,请以实际通告为准。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import RetroCard from "$lib/components/RetroCard.svelte";
|
||||
|
||||
import RetroCard from '$lib/components/RetroCard.svelte';
|
||||
</script>
|
||||
|
||||
<h1>隐私权条款</h1>
|
||||
<br />
|
||||
<hr />
|
||||
@@ -61,4 +61,3 @@
|
||||
<hr />
|
||||
<br />
|
||||
<p>本条款最后更新于2025年12月27日,最终解释权归网维所有。</p>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
let q: NotificationQueue;
|
||||
|
||||
let r = $state({
|
||||
priority: 'normal',
|
||||
priority: 'normal'
|
||||
} as NewTicketReq);
|
||||
|
||||
function onOccurDateChange(event: CustomEvent) {
|
||||
@@ -223,4 +223,3 @@ helperText="选择工单的优先级类型,更高优先级会在系统中优
|
||||
<NotificationQueue bind:this={q} />
|
||||
|
||||
<Loading active={!notLoading} />
|
||||
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
</script>
|
||||
|
||||
<h1>Forbidden</h1>
|
||||
<p>对不起,您没有权限访问这个页面。</p>
|
||||
@@ -3,11 +3,11 @@
|
||||
@plugin '@tailwindcss/typography';
|
||||
@plugin 'daisyui';
|
||||
|
||||
@plugin "daisyui/theme" {
|
||||
name: "wireframe";
|
||||
@plugin 'daisyui/theme' {
|
||||
name: 'wireframe';
|
||||
default: true;
|
||||
prefersdark: false;
|
||||
color-scheme: "light";
|
||||
color-scheme: 'light';
|
||||
--color-base-100: #f4f4f4;
|
||||
--color-base-200: #e6e6e6;
|
||||
--color-base-300: #d5d5d5;
|
||||
@@ -38,9 +38,7 @@
|
||||
--noise: 1;
|
||||
}
|
||||
|
||||
|
||||
@layer base {
|
||||
|
||||
html {
|
||||
/* 移动端优化:防止点击高亮 */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
@@ -55,5 +53,4 @@
|
||||
/* 移动端优化:防止水平溢出 */
|
||||
@apply min-h-screen overflow-x-hidden bg-base-100 text-base-content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
function gotoAuthAPI() {
|
||||
if (!env.PUBLIC_JWT) {
|
||||
console.log("未找到PUBLIC_JWT")
|
||||
console.log('未找到PUBLIC_JWT');
|
||||
}
|
||||
if (dev && env.PUBLIC_JWT) {
|
||||
docCookies.setItem('jwt', env.PUBLIC_JWT, Infinity, '/');
|
||||
|
||||
@@ -67,7 +67,12 @@
|
||||
<RetroCard>
|
||||
<span style="display: flex; align-items: center;">
|
||||
<h2 style="margin-right: 0.5rem;">个人信息</h2>
|
||||
<Renew onclick={() => {TheLastPage.Write('/me'),goto('/login')}} style="cursor: pointer;" />
|
||||
<Renew
|
||||
onclick={() => {
|
||||
(TheLastPage.Write('/me'), goto('/login'));
|
||||
}}
|
||||
style="cursor: pointer;"
|
||||
/>
|
||||
</span>
|
||||
<StructuredList style="margin-bottom: 1rem;">
|
||||
<StructuredListBody>
|
||||
|
||||
@@ -115,7 +115,10 @@
|
||||
<div class="zone-tiles">
|
||||
{#each zoneDisplayOrder as zone}
|
||||
{#if typeof countByZone?.[zone] !== 'undefined'}
|
||||
<Tile class={`zone-tile zone-${zoneTone(countByZone?.[zone])}`} on:click={() => jumpSearch(zone)}>
|
||||
<Tile
|
||||
class={`zone-tile zone-${zoneTone(countByZone?.[zone])}`}
|
||||
on:click={() => jumpSearch(zone)}
|
||||
>
|
||||
<span class="zone-name">{ZoneMap[zone]}</span>
|
||||
<span class="zone-count">{countByZone?.[zone] ?? 0}</span>
|
||||
</Tile>
|
||||
|
||||
@@ -29,13 +29,15 @@
|
||||
import { criteria } from '$lib/states/ticketCriteriaSearch.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { WtsStatus, WtsPriority, WtsCategory, WtsISP } from '$lib/types/enum';
|
||||
import {WtsJWT} from '$lib/jwt'
|
||||
import { WtsJWT } from '$lib/jwt';
|
||||
|
||||
onMount(() => Guard(IsOperator));
|
||||
|
||||
let token: WtsJWT = $state({} as WtsJWT);
|
||||
|
||||
onMount(()=>{token =CheckAndGetJWT('parsed');})
|
||||
onMount(() => {
|
||||
token = CheckAndGetJWT('parsed');
|
||||
});
|
||||
|
||||
let req = $state(criteria.r as FilterTicketsReq);
|
||||
|
||||
@@ -116,7 +118,7 @@
|
||||
'delay',
|
||||
'escalated'
|
||||
] as const satisfies readonly WtsStatus[];
|
||||
const statusOptions: readonly WtsStatus[] = statusOptionsAdmin //之前的区分没有意义,在后端会拦截的,在这里高花样,好像反而会破坏正常功能,感觉这个页面还是重写的样子。。
|
||||
const statusOptions: readonly WtsStatus[] = statusOptionsAdmin; //之前的区分没有意义,在后端会拦截的,在这里高花样,好像反而会破坏正常功能,感觉这个页面还是重写的样子。。
|
||||
|
||||
const priorityOptions = [
|
||||
'highest',
|
||||
@@ -184,7 +186,7 @@
|
||||
|
||||
$effect(() => {
|
||||
isScheduledSelected = req.status?.includes('scheduled') ?? false;
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<h1>报修单检索</h1>
|
||||
@@ -244,7 +246,10 @@
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
<div class="toggle">
|
||||
<Toggle size="sm" toggled={allSelected(zoneSelected, zoneOptions)} on:toggle={(e)=> {
|
||||
<Toggle
|
||||
size="sm"
|
||||
toggled={allSelected(zoneSelected, zoneOptions)}
|
||||
on:toggle={(e) => {
|
||||
const { toggled } = e.detail as { toggled: boolean };
|
||||
zoneSelected = toggled ? [...zoneOptions] : [];
|
||||
}}
|
||||
@@ -283,7 +288,10 @@
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
<div class="toggle">
|
||||
<Toggle size="sm" toggled={allSelected(req.status, statusOptions)} on:toggle={(e)=> {
|
||||
<Toggle
|
||||
size="sm"
|
||||
toggled={allSelected(req.status, statusOptions)}
|
||||
on:toggle={(e) => {
|
||||
const { toggled } = e.detail as { toggled: boolean };
|
||||
req.status = toggled ? [...statusOptions] : [];
|
||||
}}
|
||||
@@ -320,7 +328,10 @@
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
<div class="toggle">
|
||||
<Toggle size="sm" toggled={allSelected(req.priority, priorityOptions)} on:toggle={(e)=> {
|
||||
<Toggle
|
||||
size="sm"
|
||||
toggled={allSelected(req.priority, priorityOptions)}
|
||||
on:toggle={(e) => {
|
||||
const { toggled } = e.detail as { toggled: boolean };
|
||||
req.priority = toggled ? [...priorityOptions] : [];
|
||||
}}
|
||||
@@ -353,7 +364,10 @@
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
<div class="toggle">
|
||||
<Toggle size="sm" toggled={allSelected(req.category, categoryOptions)} on:toggle={(e)=> {
|
||||
<Toggle
|
||||
size="sm"
|
||||
toggled={allSelected(req.category, categoryOptions)}
|
||||
on:toggle={(e) => {
|
||||
const { toggled } = e.detail as { toggled: boolean };
|
||||
req.category = toggled ? [...categoryOptions] : [];
|
||||
}}
|
||||
@@ -388,7 +402,10 @@
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
<div class="toggle">
|
||||
<Toggle size="sm" toggled={allSelected(req.isp, ispOptions)} on:toggle={(e)=> {
|
||||
<Toggle
|
||||
size="sm"
|
||||
toggled={allSelected(req.isp, ispOptions)}
|
||||
on:toggle={(e) => {
|
||||
const { toggled } = e.detail as { toggled: boolean };
|
||||
req.isp = toggled ? [...ispOptions] : [];
|
||||
}}
|
||||
@@ -410,12 +427,23 @@
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<NumberInput min={1} max={20} step={1} bind:value={floor} allowEmpty={true} allowDecimal={false}
|
||||
labelText="只看如下楼层(不填代表查看全部楼层)" />
|
||||
<NumberInput
|
||||
min={1}
|
||||
max={20}
|
||||
step={1}
|
||||
bind:value={floor}
|
||||
allowEmpty={true}
|
||||
allowDecimal={false}
|
||||
labelText="只看如下楼层(不填代表查看全部楼层)"
|
||||
/>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<Toggle labelText="只显示预约在今天的预约单" bind:toggled={viewTodayScheduled} disabled={!isScheduledSelected} />
|
||||
<Toggle
|
||||
labelText="只显示预约在今天的预约单"
|
||||
bind:toggled={viewTodayScheduled}
|
||||
disabled={!isScheduledSelected}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Button on:click={search}>搜索</Button>
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
const roomNum = Number.parseInt(digits, 10);
|
||||
if (!Number.isFinite(roomNum)) return null;
|
||||
|
||||
|
||||
|
||||
const floor = Math.floor(roomNum / 100);
|
||||
//console.log('getFloorFromRoom', { room, digits, roomNum, floor });
|
||||
return Number.isFinite(floor) ? floor : null;
|
||||
@@ -63,7 +61,11 @@
|
||||
if (criteria._view_today_scheduled) {
|
||||
const todayStart = new Date().setHours(0, 0, 0, 0);
|
||||
const todayEnd = new Date().setHours(23, 59, 59, 999);
|
||||
tickets = tickets.filter((t) => t.status !== 'scheduled' || (toMs(t.appointed_at) >= todayStart && toMs(t.appointed_at) <= todayEnd));
|
||||
tickets = tickets.filter(
|
||||
(t) =>
|
||||
t.status !== 'scheduled' ||
|
||||
(toMs(t.appointed_at) >= todayStart && toMs(t.appointed_at) <= todayEnd)
|
||||
);
|
||||
}
|
||||
|
||||
ok = true;
|
||||
@@ -123,6 +125,11 @@
|
||||
{:else}
|
||||
<span>没有找到符合条件的报修单。</span>
|
||||
{/if}
|
||||
<TicketDetail t={TicketModal.NowTicket} bind:open={TicketModal.Opened} src={TicketModal.SRC} onTicketChanged={refreshTickets}/>
|
||||
<TicketDetail
|
||||
t={TicketModal.NowTicket}
|
||||
bind:open={TicketModal.Opened}
|
||||
src={TicketModal.SRC}
|
||||
onTicketChanged={refreshTickets}
|
||||
/>
|
||||
|
||||
<NotificationQueue bind:this={q} />
|
||||
|
||||
@@ -69,6 +69,11 @@
|
||||
<UserTicket {t} />
|
||||
{/each}
|
||||
|
||||
<TicketDetail t={TicketModal.NowTicket} bind:open={TicketModal.Opened} src={TicketModal.SRC} onTicketChanged={refreshTickets1}/>
|
||||
<TicketDetail
|
||||
t={TicketModal.NowTicket}
|
||||
bind:open={TicketModal.Opened}
|
||||
src={TicketModal.SRC}
|
||||
onTicketChanged={refreshTickets1}
|
||||
/>
|
||||
|
||||
<NotificationQueue bind:this={q} />
|
||||
|
||||
Reference in New Issue
Block a user