sync: 对齐小程序 v1.0.2 生产代码并脱敏
This commit is contained in:
@@ -2,9 +2,8 @@
|
||||
import { createWorkOrder } from '../api/workOrder'
|
||||
import RouterPath from '@/constant/RouterPath'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { useTokenStore } from '@/store/token'
|
||||
import WorkOrderAttachments from '@/components/WorkOrderAttachments.vue'
|
||||
import { hasAnyFeature } from '@/utils/permission'
|
||||
import { getEnvBaseUrl } from '@/utils'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
@@ -24,14 +23,27 @@ const problemTypes = [
|
||||
const userStore = useUserStore()
|
||||
const noPermission = ref(false)
|
||||
const submitting = ref(false)
|
||||
const submitted = ref(false)
|
||||
const uploading = ref(false)
|
||||
const attachmentUrls = ref<string[]>([])
|
||||
const attachmentNames = ref<string[]>([])
|
||||
const relatedId = ref<number>()
|
||||
const typePickerOpen = ref(false)
|
||||
const canCreateWorkOrder = computed(() => hasAnyFeature(userStore.userInfo, 'workorder:create'))
|
||||
const formData = reactive({
|
||||
woType: [0],
|
||||
title: '',
|
||||
content: '',
|
||||
creatorPhone: userStore.userInfo?.phone || '',
|
||||
})
|
||||
|
||||
onLoad((query) => {
|
||||
const type = Number(query?.woType)
|
||||
const id = Number(query?.relatedId)
|
||||
if ([0, 3].includes(type) && Number.isSafeInteger(id) && id > 0) {
|
||||
formData.woType = [type]
|
||||
relatedId.value = id
|
||||
formData.content = String(query?.context || '').slice(0, 500)
|
||||
}
|
||||
})
|
||||
|
||||
const typeText = computed(() => {
|
||||
@@ -39,107 +51,27 @@ const typeText = computed(() => {
|
||||
return problemTypes.find(item => item.value === value)?.label || '卡片问题'
|
||||
})
|
||||
|
||||
function chooseAttachment() {
|
||||
// #ifdef H5
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = '*/*'
|
||||
input.onchange = (event) => {
|
||||
const file = (event.target as HTMLInputElement).files?.[0]
|
||||
if (file)
|
||||
void uploadAttachment(file, file.name)
|
||||
}
|
||||
input.click()
|
||||
return
|
||||
// #endif
|
||||
|
||||
const choose = (uni as any).chooseFile || (uni as any).chooseMessageFile
|
||||
if (typeof choose !== 'function') {
|
||||
uni.showToast({ title: '当前平台暂不支持选择附件', icon: 'none' })
|
||||
function openTypePicker() {
|
||||
if (relatedId.value || submitting.value || submitted.value)
|
||||
return
|
||||
}
|
||||
choose({
|
||||
count: 1,
|
||||
type: 'all',
|
||||
success: (res: any) => {
|
||||
const file = res.tempFiles?.[0] || res.tempFilePaths?.[0]
|
||||
const filePath = file?.path || file?.tempFilePath || file
|
||||
const fileName = file?.name || String(filePath || '').split('/').pop() || '附件'
|
||||
if (filePath)
|
||||
void uploadAttachment(filePath, fileName)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function uploadAttachment(filePath: string | File, fileName: string) {
|
||||
uploading.value = true
|
||||
try {
|
||||
if (typeof filePath !== 'string') {
|
||||
const token = useTokenStore().updateNowTime().validToken
|
||||
const form = new FormData()
|
||||
form.append('file', filePath, fileName)
|
||||
form.append('fileType', 'file')
|
||||
const response = await fetch(`${getEnvBaseUrl()}/work-order/upload`, {
|
||||
method: 'POST',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
|
||||
body: form,
|
||||
})
|
||||
const body = await response.json()
|
||||
if (!response.ok || Number(body.code) !== 0)
|
||||
throw new Error(body.message || body.msg || '附件上传失败')
|
||||
const data = body.data || body
|
||||
const url = data.url || data.path
|
||||
if (!url)
|
||||
throw new Error('上传接口未返回文件地址')
|
||||
attachmentUrls.value.push(url)
|
||||
attachmentNames.value.push(fileName)
|
||||
return
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `${getEnvBaseUrl()}/work-order/upload`,
|
||||
filePath,
|
||||
name: 'file',
|
||||
formData: { fileType: 'file' },
|
||||
success: (res) => {
|
||||
try {
|
||||
const body = JSON.parse(res.data)
|
||||
const data = body.data || body
|
||||
const url = data.url || data.path
|
||||
if (!url)
|
||||
throw new Error('上传接口未返回文件地址')
|
||||
attachmentUrls.value.push(url)
|
||||
attachmentNames.value.push(fileName)
|
||||
resolve()
|
||||
}
|
||||
catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
},
|
||||
fail: reject,
|
||||
})
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
uni.showToast({ title: getErrorMessage(error, '附件上传失败'), icon: 'none' })
|
||||
}
|
||||
finally {
|
||||
uploading.value = false
|
||||
}
|
||||
}
|
||||
function removeAttachment(index: number) {
|
||||
attachmentUrls.value.splice(index, 1)
|
||||
attachmentNames.value.splice(index, 1)
|
||||
typePickerOpen.value = true
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (submitting.value || submitted.value || uploading.value)
|
||||
return
|
||||
if (!canCreateWorkOrder.value) {
|
||||
uni.showToast({ title: '暂无提交工单权限', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const title = formData.title.trim()
|
||||
const content = formData.content.trim()
|
||||
const creatorPhone = formData.creatorPhone.trim()
|
||||
const woType = Number(formData.woType[0])
|
||||
if (!problemTypes.some(item => item.value === woType)) {
|
||||
uni.showToast({ title: '请选择有效的工单类型', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!title) {
|
||||
uni.showToast({ title: '请输入工单标题', icon: 'none' })
|
||||
return
|
||||
@@ -149,24 +81,33 @@ async function handleSubmit() {
|
||||
return
|
||||
}
|
||||
|
||||
if (!/^1[3-9]\d{9}$/.test(creatorPhone)) {
|
||||
uni.showToast({ title: creatorPhone ? '请输入正确的手机号' : '请输入创建人手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
const res = await createWorkOrder({
|
||||
woType: Number(formData.woType[0] ?? 0),
|
||||
woType,
|
||||
title,
|
||||
content,
|
||||
creatorPhone,
|
||||
attachmentUrls: attachmentUrls.value,
|
||||
relatedId: relatedId.value,
|
||||
})
|
||||
const woNo = res.workOrder?.woNo || ''
|
||||
submitted.value = true
|
||||
uni.showToast({ title: '工单已提交', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
if (woNo) {
|
||||
if (woNo && hasAnyFeature(userStore.userInfo, 'workorder:detail')) {
|
||||
uni.redirectTo({
|
||||
url: `${RouterPath.BusinessViewsWorkOrderDetail}?woNo=${encodeURIComponent(woNo)}`,
|
||||
fail: () => uni.navigateBack({ fail: () => uni.switchTab({ url: RouterPath.Business }) }),
|
||||
})
|
||||
}
|
||||
else {
|
||||
uni.navigateBack()
|
||||
uni.navigateBack({ fail: () => uni.switchTab({ url: RouterPath.Business }) })
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
@@ -195,6 +136,8 @@ function getErrorMessage(error: unknown, fallback: string) {
|
||||
|
||||
onMounted(async () => {
|
||||
await userStore.fetchUserInfo().catch(() => undefined)
|
||||
if (!formData.creatorPhone)
|
||||
formData.creatorPhone = userStore.userInfo?.phone || ''
|
||||
if (!canCreateWorkOrder.value) {
|
||||
noPermission.value = true
|
||||
uni.showToast({ title: '当前账号不能提交工单', icon: 'none' })
|
||||
@@ -203,91 +146,107 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen p-24rpx pb-40rpx">
|
||||
<view class="mx-auto max-w-920rpx flex flex-col gap-20rpx">
|
||||
<wd-card v-if="noPermission" custom-class="!mx-0 !mb-0">
|
||||
<view class="text-26rpx text-#64748b leading-38rpx">
|
||||
当前账号不能提交工单。
|
||||
<view class="min-h-screen bg-#f5f7fa p-24rpx pb-48rpx">
|
||||
<view class="mx-auto max-w-920rpx flex flex-col gap-20rpx">
|
||||
<wd-card v-if="noPermission" custom-class="!mx-0 !mb-0">
|
||||
<view class="text-26rpx text-#64748b leading-38rpx">
|
||||
当前账号不能提交工单。
|
||||
</view>
|
||||
</wd-card>
|
||||
|
||||
<template v-else>
|
||||
<wd-card custom-class="!mx-0 !mb-0">
|
||||
<view class="flex items-start gap-16rpx">
|
||||
<view class="h-64rpx w-64rpx center shrink-0 rounded-20rpx bg-#eff6ff text-#2563eb">
|
||||
<view class="i-carbon-chat text-36rpx" />
|
||||
</view>
|
||||
<view class="min-w-0 flex-1">
|
||||
<text class="block text-34rpx text-#111827 font-700">提交工单</text>
|
||||
<text class="mt-8rpx block text-24rpx text-#64748b leading-36rpx">
|
||||
提交后由服务部门跟进,可在工单详情查看进度
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</wd-card>
|
||||
|
||||
<template v-else>
|
||||
<wd-card custom-class="!mx-0 !mb-0">
|
||||
<view class="flex items-start gap-16rpx">
|
||||
<view class="h-64rpx w-64rpx center shrink-0 rounded-20rpx bg-#eff6ff text-#2563eb">
|
||||
<view class="i-carbon-chat text-36rpx" />
|
||||
</view>
|
||||
<view class="min-w-0 flex-1">
|
||||
<text class="block text-34rpx text-#111827 font-900">提交工单</text>
|
||||
<text class="mt-8rpx block text-24rpx text-#64748b leading-36rpx">
|
||||
工单会分派到平台服务部门处理
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</wd-card>
|
||||
|
||||
<wd-form :model="formData" error-type="toast">
|
||||
<wd-form :model="formData" error-type="toast">
|
||||
<view class="flex flex-col gap-20rpx">
|
||||
<wd-card custom-class="!mx-0 !mb-0" custom-content-class="!p-0">
|
||||
<template #title>
|
||||
<view class="h-88rpx flex items-center justify-between">
|
||||
<text class="text-30rpx text-#111827 font-900">基础信息</text>
|
||||
<text class="text-28rpx text-#0f172a font-600">基础信息</text>
|
||||
<wd-tag type="primary" variant="plain">
|
||||
{{ typeText }}
|
||||
</wd-tag>
|
||||
</view>
|
||||
</template>
|
||||
<wd-cell-group :border="false">
|
||||
<wd-picker
|
||||
v-model="formData.woType"
|
||||
label="问题类型"
|
||||
label-width="96px"
|
||||
:columns="problemTypes"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="formData.title"
|
||||
label="工单标题"
|
||||
label-width="96px"
|
||||
placeholder="请输入简短标题"
|
||||
clearable
|
||||
<wd-cell
|
||||
title="工单类型"
|
||||
:value="typeText"
|
||||
:label="relatedId ? '已关联业务,类型不可更改' : '请选择本次工单的问题分类'"
|
||||
:is-link="!relatedId && !submitting && !submitted"
|
||||
center
|
||||
custom-title-class="!text-28rpx !text-#334155"
|
||||
custom-value-class="!text-26rpx !text-#2563eb"
|
||||
@click="openTypePicker"
|
||||
/>
|
||||
<wd-form-item title="工单标题" prop="title" required title-width="96px" custom-title-class="!text-28rpx !text-#334155">
|
||||
<wd-input
|
||||
v-model="formData.title"
|
||||
:disabled="submitting || submitted"
|
||||
placeholder="请输入简短标题"
|
||||
:maxlength="100"
|
||||
compact
|
||||
clearable
|
||||
/>
|
||||
</wd-form-item>
|
||||
<wd-form-item title="创建人手机号" prop="creatorPhone" required title-width="96px" custom-title-class="!text-28rpx !text-#334155">
|
||||
<wd-input
|
||||
v-model="formData.creatorPhone"
|
||||
:disabled="submitting || submitted"
|
||||
type="number"
|
||||
placeholder="请输入创建人手机号"
|
||||
:maxlength="11"
|
||||
compact
|
||||
clearable
|
||||
/>
|
||||
</wd-form-item>
|
||||
</wd-cell-group>
|
||||
</wd-card>
|
||||
|
||||
<wd-card custom-class="!mx-0 !mb-0">
|
||||
<template #title>
|
||||
<view class="h-88rpx flex items-center">
|
||||
<text class="text-30rpx text-#111827 font-900">问题描述</text>
|
||||
<text class="text-28rpx text-#0f172a font-600">问题描述</text>
|
||||
</view>
|
||||
</template>
|
||||
<wd-textarea
|
||||
v-model="formData.content"
|
||||
:disabled="submitting || submitted"
|
||||
placeholder="请描述问题现象、发生时间和已尝试的处理方式"
|
||||
:maxlength="500"
|
||||
:maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
<view class="mt-20rpx flex items-center justify-between">
|
||||
<text class="text-24rpx text-#64748b">附件(可选)</text>
|
||||
<wd-button size="small" type="info" :loading="uploading" @click="chooseAttachment">选择附件</wd-button>
|
||||
</view>
|
||||
<view v-if="attachmentNames.length" class="mt-16rpx flex flex-col gap-12rpx">
|
||||
<view
|
||||
v-for="(name, index) in attachmentNames"
|
||||
:key="name + index"
|
||||
class="flex items-center justify-between rounded-12rpx bg-#f8fafc px-16rpx py-12rpx"
|
||||
>
|
||||
<text class="min-w-0 flex-1 truncate text-24rpx text-#334155">{{ name }}</text>
|
||||
<wd-button size="small" type="info" plain @click="removeAttachment(index)">移除</wd-button>
|
||||
</view>
|
||||
<view class="mt-20rpx">
|
||||
<WorkOrderAttachments v-model="attachmentUrls" :disabled="submitting || submitted" @uploading="uploading = $event" />
|
||||
</view>
|
||||
</wd-card>
|
||||
</wd-form>
|
||||
</view>
|
||||
</wd-form>
|
||||
|
||||
<wd-button block type="primary" :loading="submitting" :disabled="!canCreateWorkOrder || uploading" @click="handleSubmit">
|
||||
提交工单
|
||||
</wd-button>
|
||||
</template>
|
||||
</view>
|
||||
<wd-button block type="primary" :round="false" :loading="submitting" :disabled="!canCreateWorkOrder || submitting || uploading || submitted" @click="handleSubmit">
|
||||
提交工单
|
||||
</wd-button>
|
||||
</template>
|
||||
</view>
|
||||
<wd-picker
|
||||
v-model="formData.woType"
|
||||
v-model:visible="typePickerOpen"
|
||||
title="选择工单类型"
|
||||
:columns="[problemTypes]"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user