mirror of
https://github.com/m1ngsama/FUJI.git
synced 2025-12-25 02:56:38 +00:00
save
This commit is contained in:
parent
0c7a5a9578
commit
d782137f81
11 changed files with 407 additions and 54 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
"@logto/browser": "^2.2.18",
|
"@logto/browser": "^2.2.18",
|
||||||
"@stylistic/eslint-plugin": "^2.13.0",
|
"@stylistic/eslint-plugin": "^2.13.0",
|
||||||
"astro": "^4.16.18",
|
"astro": "^4.16.18",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"framer-motion": "^11.18.2",
|
"framer-motion": "^11.18.2",
|
||||||
"ical.js": "^1.5.0",
|
"ical.js": "^1.5.0",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ importers:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^4.16.18
|
specifier: ^4.16.18
|
||||||
version: 4.16.18(@types/node@22.14.1)(rollup@4.40.0)(typescript@5.8.3)
|
version: 4.16.18(@types/node@22.14.1)(rollup@4.40.0)(typescript@5.8.3)
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.13
|
||||||
|
version: 1.11.13
|
||||||
framer-motion:
|
framer-motion:
|
||||||
specifier: ^11.18.2
|
specifier: ^11.18.2
|
||||||
version: 11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
@ -3096,6 +3099,9 @@ packages:
|
||||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
dayjs@1.11.13:
|
||||||
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -9642,6 +9648,8 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-data-view: 1.0.2
|
is-data-view: 1.0.2
|
||||||
|
|
||||||
|
dayjs@1.11.13: {}
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
|
||||||
17
src/components/header/RepairHeader.astro
Normal file
17
src/components/header/RepairHeader.astro
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
import NavigationUser from "./NavigationUser.vue"
|
||||||
|
---
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const button = document.getElementById("repair-header")
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
window.location.href = "/repair"
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="box-border border-b sticky top-0 bg-white/80 backdrop-blur z-20 h-12">
|
||||||
|
<div class="h-full flex items-center justify-between text-lg max-w-[1024px] mx-auto px-[22px]">
|
||||||
|
<span id="repair-header" class="font-semibold select-none">维修</span>
|
||||||
|
<NavigationUser client:load />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
163
src/pages/repair/EventDetail.tsx
Normal file
163
src/pages/repair/EventDetail.tsx
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import type { components } from "../../types/saturday"
|
||||||
|
import { saturdayClient } from "../../utils/client"
|
||||||
|
import { Textarea, Input, Chip } from "@heroui/react"
|
||||||
|
import type { PublicMember } from "../../store/member"
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
import { EventStatus, UserEventAction } from "../../types/event"
|
||||||
|
|
||||||
|
type PublicEvent = components["schemas"]["PublicEvent"]
|
||||||
|
type EventLog = components["schemas"]["EventLog"]
|
||||||
|
|
||||||
|
function EventLogItem(props: {
|
||||||
|
eventLog: EventLog
|
||||||
|
actor?: PublicMember
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="py-1 flex items-center">
|
||||||
|
{/* <div className="mr-4 h-10 bg-red-400 flex flex-col items-center gap-2">
|
||||||
|
</div> */}
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="mr-4">
|
||||||
|
{
|
||||||
|
UserEventAction.find(v => v.action === props.eventLog.action)?.text || props.eventLog.action
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{
|
||||||
|
props.actor?.avatar
|
||||||
|
? <img src={props.actor?.avatar} alt="actor avatar" className="w-6 aspect-square rounded-full" />
|
||||||
|
: <></>
|
||||||
|
}
|
||||||
|
<span className="text-gray-600 ml-2">
|
||||||
|
{
|
||||||
|
props.actor ? props.actor.alias : ""
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 items-center mt-1 text-gray-600">
|
||||||
|
{dayjs(props.eventLog.gmtCreate).format("YYYY-MM-DD HH:mm")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EventStatusChip(props: {
|
||||||
|
status: string
|
||||||
|
}) {
|
||||||
|
switch (props.status) {
|
||||||
|
case EventStatus.open:
|
||||||
|
return <Chip>未开始</Chip>
|
||||||
|
case EventStatus.accepted:
|
||||||
|
return <Chip>维修中</Chip>
|
||||||
|
case EventStatus.committed:
|
||||||
|
return <Chip color="primary">维修中</Chip>
|
||||||
|
case EventStatus.closed:
|
||||||
|
return <Chip color="success">已完成</Chip>
|
||||||
|
case EventStatus.cancelled:
|
||||||
|
return <Chip>已取消</Chip>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterEventLog = (event: PublicEvent) => {
|
||||||
|
const eventLogs = event.logs
|
||||||
|
const filteredLogs: (EventLog & { actor?: PublicMember })[] = []
|
||||||
|
// find the first log that action is "create"
|
||||||
|
const createLog = eventLogs.find(log => log.action === "create")
|
||||||
|
filteredLogs.push(createLog)
|
||||||
|
// find the first log that action is "cancel"
|
||||||
|
const cancelLog = eventLogs.find(log => log.action === "cancel")
|
||||||
|
if (cancelLog) {
|
||||||
|
filteredLogs.push(cancelLog)
|
||||||
|
return filteredLogs
|
||||||
|
}
|
||||||
|
// find the last log that action is "accept"
|
||||||
|
const acceptLog = eventLogs.findLast(log => log.action === "accept")
|
||||||
|
if (acceptLog) {
|
||||||
|
filteredLogs.push({
|
||||||
|
...acceptLog,
|
||||||
|
actor: event.member,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// find the last log that action is "close"
|
||||||
|
const closeLog = eventLogs.findLast(log => log.action === "close")
|
||||||
|
if (closeLog) {
|
||||||
|
filteredLogs.push({
|
||||||
|
...closeLog,
|
||||||
|
actor: event.closedBy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return filteredLogs
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function EventDetail() {
|
||||||
|
const [event, setEvent] = useState<PublicEvent | undefined>()
|
||||||
|
const fetchAndSetEvent = async (eventId: number) => {
|
||||||
|
const { data } = await saturdayClient.GET("/events/{EventId}", {
|
||||||
|
params: {
|
||||||
|
path: {
|
||||||
|
EventId: eventId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
setEvent(data)
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
// get the eventId from the url
|
||||||
|
const url = new URL(window.location.href)
|
||||||
|
const eventId = url.searchParams.get("eventId")
|
||||||
|
if (!eventId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fetchAndSetEvent(eventId as unknown as number)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
event
|
||||||
|
? (
|
||||||
|
<section className="box-border mb-24">
|
||||||
|
<div className="section-content mt-8">
|
||||||
|
<h2 className="text-2xl font-bold">维修详情</h2>
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
<span>
|
||||||
|
#{event.eventId}
|
||||||
|
</span>
|
||||||
|
<EventStatusChip status={event.status}></EventStatusChip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="section-content my-8 flex flex-col gap-4">
|
||||||
|
<Textarea
|
||||||
|
label="问题描述"
|
||||||
|
readOnly
|
||||||
|
name="description"
|
||||||
|
value={event.problem || ""}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="型号"
|
||||||
|
type="text"
|
||||||
|
value={event.model || ""}
|
||||||
|
readOnly
|
||||||
|
>
|
||||||
|
</Input>
|
||||||
|
<div className="bg-gray-100 rounded-xl text-sm px-3 py-2 mt-2 ">
|
||||||
|
<div className="text-xs font-semibold text-gray-600 mb-1">
|
||||||
|
维修记录
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
filterEventLog(event).map((v, index) => {
|
||||||
|
return (
|
||||||
|
<EventLogItem key={index} actor={v.actor} eventLog={v} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
: <div></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
---
|
|
||||||
import NavigationUser from "../../components/header/NavigationUser.vue"
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="box-border border-b sticky top-0 bg-white/80 backdrop-blur z-20 h-12">
|
|
||||||
<div class="h-full flex items-center justify-between text-lg max-w-[1024px] mx-auto px-[22px]">
|
|
||||||
<span class="font-semibold">维修</span>
|
|
||||||
<NavigationUser client:load />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -3,49 +3,28 @@ import { makeLogtoClient } from "../../utils/auth"
|
||||||
import type { UserInfoResponse } from "@logto/browser"
|
import type { UserInfoResponse } from "@logto/browser"
|
||||||
import { Form, Input, Button, Textarea } from "@heroui/react"
|
import { Form, Input, Button, Textarea } from "@heroui/react"
|
||||||
import { saturdayClient } from "../../utils/client"
|
import { saturdayClient } from "../../utils/client"
|
||||||
import type LogtoClient from "@logto/browser"
|
import type { components } from "../../types/saturday"
|
||||||
|
import QRCode from "qrcode"
|
||||||
|
import EventDetail from "./EventDetail"
|
||||||
|
|
||||||
export default function App() {
|
type TicketFormData = {
|
||||||
const [userInfo, setUserInfo] = useState<UserInfoResponse>()
|
|
||||||
const [formData, setFormData] = useState<{
|
|
||||||
model?: string
|
model?: string
|
||||||
phone?: string
|
phone?: string
|
||||||
qq?: string
|
qq?: string
|
||||||
description?: string
|
description?: string
|
||||||
}>({})
|
|
||||||
|
|
||||||
let logtoClient: LogtoClient | undefined = undefined
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const check = async () => {
|
|
||||||
logtoClient = makeLogtoClient()
|
|
||||||
const createRepairPath = "/repair/create-ticket"
|
|
||||||
const authenticated = await logtoClient.isAuthenticated()
|
|
||||||
if (!authenticated) {
|
|
||||||
window.location.href = `/repair/login-hint?redirectUrl=${createRepairPath}`
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
const res = await logtoClient.getIdTokenClaims()
|
|
||||||
setUserInfo(res)
|
|
||||||
}
|
|
||||||
check()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
|
function TicketForm(props: {
|
||||||
|
userInfo: UserInfoResponse
|
||||||
|
onSubmit: (form: TicketFormData) => Promise<void>
|
||||||
|
}) {
|
||||||
|
const [loading, setLoading] = useState<boolean>()
|
||||||
|
const [formData, setFormData] = useState<TicketFormData>({})
|
||||||
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
setLoading(true)
|
||||||
const logtoToken = await logtoClient.getAccessToken()
|
await props.onSubmit(formData)
|
||||||
await saturdayClient.POST("/client/event", {
|
setLoading(false)
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${logtoToken}`,
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
Problem: formData.description,
|
|
||||||
model: formData.model,
|
|
||||||
phone: formData.phone,
|
|
||||||
qq: formData.qq,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -96,7 +75,7 @@ export default function App() {
|
||||||
placeholder="example@nbtca.space"
|
placeholder="example@nbtca.space"
|
||||||
isRequired
|
isRequired
|
||||||
type="email"
|
type="email"
|
||||||
value={userInfo?.email || ""}
|
value={props.userInfo?.email || ""}
|
||||||
readOnly
|
readOnly
|
||||||
description="我们会向此邮箱发送维修相关的通知"
|
description="我们会向此邮箱发送维修相关的通知"
|
||||||
/>
|
/>
|
||||||
|
|
@ -108,6 +87,7 @@ export default function App() {
|
||||||
type="phone"
|
type="phone"
|
||||||
name="phone"
|
name="phone"
|
||||||
value={formData.phone || ""}
|
value={formData.phone || ""}
|
||||||
|
maxLength={11}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setFormData({ ...formData, phone: e.target.value })
|
setFormData({ ...formData, phone: e.target.value })
|
||||||
}}
|
}}
|
||||||
|
|
@ -120,7 +100,7 @@ export default function App() {
|
||||||
setFormData({ ...formData, qq: e.target.value })
|
setFormData({ ...formData, qq: e.target.value })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button type="submit" color="primary" className="my-4 w-full">
|
<Button type="submit" color="primary" className="my-4 w-full" isLoading={loading}>
|
||||||
提交
|
提交
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
@ -128,3 +108,107 @@ export default function App() {
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
type PublicEvent = components["schemas"]["PublicEvent"]
|
||||||
|
function TicketFormCreated(props: {
|
||||||
|
event: PublicEvent
|
||||||
|
}) {
|
||||||
|
const [svg, setSvg] = useState<string>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
QRCode.toString(props.event.eventId.toString()).then((res) => {
|
||||||
|
// const root = createRoot(
|
||||||
|
// document.getElementById("svg-root"),
|
||||||
|
// )
|
||||||
|
// root.render(res)
|
||||||
|
setSvg(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// const svg = ref()
|
||||||
|
// watch(id, async () => {
|
||||||
|
// if (!id.value) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// svg.value = await QRCode.toString(useGraduationIdURL().constructURL(id.value))
|
||||||
|
// })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full h-[80vh] flex flex-col justify-between items-center">
|
||||||
|
<div className=" flex flex-col sm:flex-row items-center h-full max-w-[1280px] justify-center gap-8 p-8">
|
||||||
|
<div className="min-h-64 h-[36vh] aspect-square">
|
||||||
|
<div className="h-full" dangerouslySetInnerHTML={{ __html: svg }}></div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className=" sm:w-auto"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-brand text-nowrap text-3xl font-bold">
|
||||||
|
预约成功
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="sm:w-[30vw] mt-6 text-gray-600 lg:text-lg">
|
||||||
|
<div>
|
||||||
|
扫描二维码来查看预约详情
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
你也可以保存此二维码
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
// <div>{props.event.eventId}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [userInfo, setUserInfo] = useState<UserInfoResponse>()
|
||||||
|
const [event, setEvent] = useState<PublicEvent | undefined>({
|
||||||
|
eventId: 123,
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const check = async () => {
|
||||||
|
const createRepairPath = "/repair/create-ticket"
|
||||||
|
const authenticated = await makeLogtoClient().isAuthenticated()
|
||||||
|
if (!authenticated) {
|
||||||
|
window.location.href = `/repair/login-hint?redirectUrl=${createRepairPath}`
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res = await makeLogtoClient().getIdTokenClaims()
|
||||||
|
setUserInfo(res)
|
||||||
|
}
|
||||||
|
check()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onSubmit = async (formData: TicketFormData) => {
|
||||||
|
const logtoToken = await makeLogtoClient().getAccessToken()
|
||||||
|
try {
|
||||||
|
const res = await saturdayClient.POST("/client/event", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${logtoToken}`,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
Problem: formData.description,
|
||||||
|
model: formData.model,
|
||||||
|
phone: formData.phone,
|
||||||
|
qq: formData.qq,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
setEvent(res.data as unknown as PublicEvent)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EventDetail />
|
||||||
|
(
|
||||||
|
event?.eventId
|
||||||
|
? <TicketFormCreated event={event}></TicketFormCreated>
|
||||||
|
: <TicketForm userInfo={userInfo} onSubmit={onSubmit}></TicketForm>
|
||||||
|
)
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import BaseLayout from "../../layouts/BaseLayout.astro"
|
import BaseLayout from "../../layouts/BaseLayout.astro"
|
||||||
import RepairHeader from "./RepairHeader.astro"
|
import RepairHeader from "../../components/header/RepairHeader.astro"
|
||||||
import TicketForm from "./TicketForm"
|
import TicketForm from "./TicketForm"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro"
|
||||||
import hayasaka from "../_assets/hayasaka.jpg"
|
import hayasaka from "../_assets/hayasaka.jpg"
|
||||||
import repairDayOnSite from "../_assets/repair_day_on_site.jpeg"
|
import repairDayOnSite from "../_assets/repair_day_on_site.jpeg"
|
||||||
import { Button } from "@heroui/react"
|
import { Button } from "@heroui/react"
|
||||||
import RepairHeader from "./RepairHeader.astro";
|
import RepairHeader from "../../components/header/RepairHeader.astro"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import BaseLayout from "../../layouts/BaseLayout.astro"
|
import BaseLayout from "../../layouts/BaseLayout.astro"
|
||||||
import RepairHeader from "./RepairHeader.astro"
|
import RepairHeader from "../../components/header/RepairHeader.astro"
|
||||||
import { Button } from "@heroui/react"
|
import { Button } from "@heroui/react"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
12
src/pages/repair/ticket-detail.astro
Normal file
12
src/pages/repair/ticket-detail.astro
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
import BaseLayout from "../../layouts/BaseLayout.astro"
|
||||||
|
import RepairHeader from "../../components/header/RepairHeader.astro"
|
||||||
|
import EventDetail from "./EventDetail"
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout primaryTitle="Create Ticket">
|
||||||
|
<RepairHeader></RepairHeader>
|
||||||
|
<div>
|
||||||
|
<EventDetail client:only="react"></EventDetail>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
||||||
78
src/types/event.ts
Normal file
78
src/types/event.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
export interface Status {
|
||||||
|
status: string
|
||||||
|
text: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Action {
|
||||||
|
action: string
|
||||||
|
text: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EventStatus {
|
||||||
|
open = "open",
|
||||||
|
accepted = "accepted",
|
||||||
|
committed = "committed",
|
||||||
|
closed = "closed",
|
||||||
|
cancelled = "cancelled",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserEventStatus: Status[] = [
|
||||||
|
{
|
||||||
|
status: EventStatus.open,
|
||||||
|
text: "待处理",
|
||||||
|
icon: "status_initial.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: EventStatus.accepted,
|
||||||
|
text: "维修中",
|
||||||
|
icon: "status_ongoing.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: EventStatus.committed,
|
||||||
|
text: "维修中",
|
||||||
|
icon: "status_ongoing.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: EventStatus.closed,
|
||||||
|
text: "已完成",
|
||||||
|
icon: "status_complete.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: EventStatus.cancelled,
|
||||||
|
text: "已取消",
|
||||||
|
icon: "status_cancelled.svg",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export enum EventAction {
|
||||||
|
create = "create",
|
||||||
|
accept = "accept",
|
||||||
|
commit = "commit",
|
||||||
|
close = "close",
|
||||||
|
cancel = "cancel",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserEventAction: Action[] = [
|
||||||
|
{
|
||||||
|
action: EventAction.create,
|
||||||
|
text: "事件创建",
|
||||||
|
icon: "event_create.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: EventAction.accept,
|
||||||
|
text: "维修开始",
|
||||||
|
icon: "status_ongoing.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: EventAction.close,
|
||||||
|
text: "维修完成",
|
||||||
|
icon: "status_complete.svg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: EventAction.cancel,
|
||||||
|
text: "事件取消",
|
||||||
|
icon: "status_cancelled.svg",
|
||||||
|
},
|
||||||
|
]
|
||||||
Loading…
Reference in a new issue