工单详情修改

This commit is contained in:
2025-12-25 16:55:46 +08:00
parent 062c5a8488
commit e39dc03f92
6 changed files with 170 additions and 141 deletions

View File

@@ -1,7 +1,7 @@
package org.xyzh.workcase.enums; package org.xyzh.workcase.enums;
public enum WorkcaseProcessAction { public enum WorkcaseProcessAction {
CREATE("create", "创建"),
INFO("info", "记录"), INFO("info", "记录"),
ASSIGN("assign","指派"), ASSIGN("assign","指派"),
REDEPLOY("redeploy", "转派"), REDEPLOY("redeploy", "转派"),

View File

@@ -76,7 +76,7 @@ public class WorkcaseServiceImpl implements WorkcaseService {
process.setProcessId(IdUtil.generateUUID()); process.setProcessId(IdUtil.generateUUID());
process.setOptsn(IdUtil.getOptsn()); process.setOptsn(IdUtil.getOptsn());
process.setWorkcaseId(workcase.getWorkcaseId()); process.setWorkcaseId(workcase.getWorkcaseId());
process.setAction(WorkcaseProcessAction.INFO.getName()); process.setAction(WorkcaseProcessAction.CREATE.getName());
process.setMessage("工单创建"); process.setMessage("工单创建");
process.setCreator(workcase.getCreator()); process.setCreator(workcase.getCreator());
workcaseProcessMapper.insertWorkcaseProcess(process); workcaseProcessMapper.insertWorkcaseProcess(process);

View File

@@ -4,11 +4,6 @@
import {loadShare} from "@module-federation/runtime"; import {loadShare} from "@module-federation/runtime";
const importMap = { const importMap = {
"axios": async () => {
let pkg = await import("__mf__virtual/workcase__prebuild__axios__prebuild__.js");
return pkg;
}
,
"element-plus": async () => { "element-plus": async () => {
let pkg = await import("__mf__virtual/workcase__prebuild__element_mf_2_plus__prebuild__.js"); let pkg = await import("__mf__virtual/workcase__prebuild__element_mf_2_plus__prebuild__.js");
return pkg; return pkg;
@@ -27,36 +22,6 @@
} }
const usedShared = { const usedShared = {
"axios": {
name: "axios",
version: "1.13.2",
scope: ["default"],
loaded: false,
from: "workcase",
async get () {
if (false) {
throw new Error(`Shared module '${"axios"}' must be provided by host`);
}
usedShared["axios"].loaded = true
const {"axios": pkgDynamicImport} = importMap
const res = await pkgDynamicImport()
const exportModule = {...res}
// All npm packages pre-built by vite will be converted to esm
Object.defineProperty(exportModule, "__esModule", {
value: true,
enumerable: false
})
return function () {
return exportModule
}
},
shareConfig: {
singleton: false,
requiredVersion: "^1.13.2",
}
}
,
"element-plus": { "element-plus": {
name: "element-plus", name: "element-plus",
version: "2.12.0", version: "2.12.0",

View File

@@ -81,7 +81,31 @@ declare module 'shared/api/ai' {
// ============ types模块 ================== // ============ types模块 ==================
declare module 'shared/types' { declare module 'shared/types' {
export type { BaseDTO, BaseVO } from '../../../shared/src/types/base' // 基础类型
export interface OrderField {
field: string
order: 'ASC' | 'DESC'
}
export interface BaseDTO {
optsn?: string
creator?: string
updater?: string
deptPath?: string
remark?: string
createTime?: string
updateTime?: string
deleteTime?: string
deleted?: boolean
limit?: number
startTime?: string
endTime?: string
orderFields?: OrderField[]
}
export interface BaseVO extends BaseDTO {
id?: string
}
// 重新导出 response // 重新导出 response
export type { ResultDomain } from '../../../shared/src/types/response' export type { ResultDomain } from '../../../shared/src/types/response'

View File

@@ -499,7 +499,22 @@
gap: 12rpx; gap: 12rpx;
margin-bottom: 8rpx; margin-bottom: 8rpx;
} }
.timeline-time {
display: block;
font-size: 30rpx;
color: #173294;
}
.timeline-date {
display: block;
font-size: 24rpx;
color: #6b7280;
}
.timeline-info{
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.timeline-actor { .timeline-actor {
font-size: 28rpx; font-size: 28rpx;
font-weight: 700; font-weight: 700;
@@ -514,15 +529,9 @@
.timeline-desc { .timeline-desc {
display: block; display: block;
font-size: 26rpx; font-size: 26rpx;
color: #6b7280; color: #111827;
line-height: 1.5; line-height: 1.5;
margin-bottom: 8rpx; margin-left: 8rpx;
}
.timeline-time {
display: block;
font-size: 24rpx;
color: #9ca3af;
} }
// 底部占位 // 底部占位

View File

@@ -169,12 +169,18 @@
<view class="timeline-dot" :class="getTimelineDotClass(item.status)"></view> <view class="timeline-dot" :class="getTimelineDotClass(item.status)"></view>
<view class="timeline-line" v-if="index < processList.length - 1"></view> <view class="timeline-line" v-if="index < processList.length - 1"></view>
<view class="timeline-body"> <view class="timeline-body">
<view class="timeline-header"> <view class="timeline-header">
<text class="timeline-actor">{{ item.actor }}</text> <text class="timeline-time">{{ getTime(item.createTime) }}</text>
<text class="timeline-action">{{ item.action }}</text> <text class="timeline-date">{{ getDate(item.createTime) }}</text>
</view>
<view class="timeline-info">
<text class="timeline-action" >{{ getActionText(item.action) }}:</text>
<text class="timeline-desc">{{ item.message }}</text>
</view>
<view class="timeline-files">
</view> </view>
<text class="timeline-desc" v-if="item.desc">{{ item.desc }}</text>
<text class="timeline-time">{{ item.time }}</text>
</view> </view>
</view> </view>
</view> </view>
@@ -206,20 +212,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted, reactive } from 'vue'
import { onLoad } from '@dcloudio/uni-app' import { onLoad } from '@dcloudio/uni-app'
import type { TbWorkcaseDTO, TbWorkcaseProcessDTO } from '@/types/workcase' import type { TbWorkcaseDTO, TbWorkcaseProcessDTO } from '@/types/workcase'
import { workcaseAPI, fileAPI } from '@/api' import { workcaseAPI, fileAPI } from '@/api'
// 接口定义
interface ProcessItem {
status: 'system' | 'manager' | 'engineer'
actor: string
action: string
desc?: string
time: string
}
// 响应式数据 // 响应式数据
const headerPaddingTop = ref<number>(44) const headerPaddingTop = ref<number>(44)
const headerTotalHeight = ref<number>(88) const headerTotalHeight = ref<number>(88)
@@ -233,10 +230,10 @@ const emergencies = ref<string[]>(['普通', '紧急'])
const emergencyIndex = ref<number>(0) const emergencyIndex = ref<number>(0)
// 工单数据 // 工单数据
const workcase = ref<TbWorkcaseDTO>({}) const workcase = reactive<TbWorkcaseDTO>({})
// 处理记录 // 处理记录
const processList = ref<ProcessItem[]>([]) const processList = reactive<TbWorkcaseProcessDTO[]>([])
// 获取图片 URL通过 fileId // 获取图片 URL通过 fileId
function getImageUrl(fileId: string): string { function getImageUrl(fileId: string): string {
@@ -278,7 +275,8 @@ onLoad((options: any) => {
console.error('读取loginDomain失败:', e) console.error('读取loginDomain失败:', e)
} }
workcase.value = { // 使用 Object.assign 更新 reactive 对象
Object.assign(workcase, {
username, username,
phone, phone,
userId, userId,
@@ -289,7 +287,7 @@ onLoad((options: any) => {
description: '', description: '',
emergency: 'normal', emergency: 'normal',
imgs: [] imgs: []
} })
} else if (options.workcaseId) { } else if (options.workcaseId) {
// 查看模式 // 查看模式
workcaseId.value = options.workcaseId workcaseId.value = options.workcaseId
@@ -319,44 +317,49 @@ onMounted(() => {
}) })
// 加载工单详情 // 加载工单详情
async function loadWorkcaseDetail(id: string) { async function loadWorkcaseDetail(workcaseId : string) {
uni.showLoading({ title: '加载中...' }) uni.showLoading({ title: '加载中...' })
try { try {
const res = await workcaseAPI.getWorkcaseById(id) const res = await workcaseAPI.getWorkcaseById(workcaseId)
if (res.success && res.data) { if (res.success && res.data) {
workcase.value = res.data // 使用 Object.assign 更新 reactive 对象
// 加载处理记录 Object.assign(workcase, res.data)
await loadProcessList(id) console.log('工单详情:', workcase)
} else { // 加载处理记录
uni.showToast({ title: res.message || '加载失败', icon: 'none' }) await loadProcessList(workcaseId)
} else {
uni.showToast({ title: res.message || '加载失败', icon: 'none' })
}
} catch (error) {
console.error('加载工单详情失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
} }
} catch (error) {
console.error('加载工单详情失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
} }
}
// 加载处理记录 // 加载处理记录
async function loadProcessList(id: string) { async function loadProcessList(workcaseId: string) {
try { try {
const res = await workcaseAPI.getWorkcaseProcessList({ workcaseId: id }) const res = await workcaseAPI.getWorkcaseProcessList({ workcaseId: workcaseId })
if (res.success && res.dataList) { if (res.success && res.dataList) {
// 转换为界面需要的格式 // 清空并重新填充 reactive 数组
processList.value = res.dataList.map((item: TbWorkcaseProcessDTO) => ({ processList.length = 0
status: item.processorType === 'system' ? 'system' : item.processorType === 'manager' ? 'manager' : 'engineer', processList.push(...res.dataList)
actor: item.processorName || '未知', console.log('处理记录:', processList)
action: item.action || '',
desc: item.description || '',
time: item.createTime || ''
}))
} }
} catch (error) { } catch (error) {
console.error('加载处理记录失败:', error) console.error('加载处理记录失败:', error)
} }
} }
function getTime(datetime: string): string{
return datetime.split(" ")[1]
}
function getDate(datetime: string): string{
return datetime.split(" ")[0]
}
// 获取状态样式类 // 获取状态样式类
function getStatusClass(status?: string): string { function getStatusClass(status?: string): string {
switch (status) { switch (status) {
@@ -378,23 +381,51 @@ function getStatusText(status?: string): string {
} }
// 获取时间线圆点样式类 // 获取时间线圆点样式类
function getTimelineDotClass(status: string): string { function getTimelineDotClass(action?: string): string {
switch (status) { switch (action) {
case 'system': return 'dot-system' case 'create':
case 'manager': return 'dot-manager' case 'info':
case 'engineer': return 'dot-engineer' return 'dot-system'
default: return 'dot-system' case 'assign':
case 'redeploy':
return 'dot-manager'
case 'finish':
return 'dot-engineer'
case 'repeal':
return 'dot-cancel'
default:
return 'dot-system'
}
}
// 获取动作文本
function getActionText(action?: string): string {
switch (action) {
case 'create':
return '工单创建'
case 'info':
return '记录信息'
case 'assign':
return '指派工程师'
case 'redeploy':
return '转派工程师'
case 'repeal':
return '撤销工单'
case 'finish':
return '完成工单'
default:
return '未知操作'
} }
} }
// 查看对话 // 查看对话
function handleViewChat() { function handleViewChat() {
if (!workcase.value.roomId) { if (!workcase.roomId) {
uni.showToast({ title: '未关联聊天室', icon: 'none' }) uni.showToast({ title: '未关联聊天室', icon: 'none' })
return return
} }
uni.navigateTo({ uni.navigateTo({
url: `/pages/chatRoom/chatRoom/chatRoom?roomId=${workcase.value.roomId}` url: `/pages/chatRoom/chatRoom/chatRoom?roomId=${workcase.roomId}`
}) })
} }
@@ -427,23 +458,23 @@ function handleComplete() {
// 表单选择器事件 // 表单选择器事件
function onTypeChange(e: any) { function onTypeChange(e: any) {
typeIndex.value = e.detail.value typeIndex.value = e.detail.value
workcase.value.type = faultTypes.value[e.detail.value] workcase.type = faultTypes.value[e.detail.value]
} }
function onEmergencyChange(e: any) { function onEmergencyChange(e: any) {
emergencyIndex.value = e.detail.value emergencyIndex.value = e.detail.value
workcase.value.emergency = emergencyIndex.value === 0 ? 'normal' : 'emergency' workcase.emergency = emergencyIndex.value === 0 ? 'normal' : 'emergency'
} }
// 选择故障图片 // 选择故障图片
async function chooseFaultImages() { async function chooseFaultImages() {
uni.chooseImage({ uni.chooseImage({
count: 9 - (workcase.value.imgs?.length || 0), count: 9 - (workcase.imgs?.length || 0),
sizeType: ['compressed'], sizeType: ['compressed'],
sourceType: ['camera', 'album'], sourceType: ['camera', 'album'],
success: async (res) => { success: async (res) => {
if (!workcase.value.imgs) { if (!workcase.imgs) {
workcase.value.imgs = [] workcase.imgs = []
} }
// 上传图片到服务器 // 上传图片到服务器
@@ -452,7 +483,7 @@ async function chooseFaultImages() {
const uploadPromises = res.tempFilePaths.map(filePath => const uploadPromises = res.tempFilePaths.map(filePath =>
fileAPI.uploadFile(filePath, { fileAPI.uploadFile(filePath, {
module: 'workcase', module: 'workcase',
optsn: workcase.value.workcaseId || 'temp' optsn: workcase.workcaseId || 'temp'
}) })
) )
@@ -462,7 +493,7 @@ async function chooseFaultImages() {
results.forEach(result => { results.forEach(result => {
if (result.success && result.data?.fileId) { if (result.success && result.data?.fileId) {
// 存储 fileId用于提交时使用 // 存储 fileId用于提交时使用
workcase.value.imgs!.push(result.data.fileId) workcase.imgs!.push(result.data.fileId)
} }
}) })
@@ -482,8 +513,8 @@ async function chooseFaultImages() {
// 删除故障图片 // 删除故障图片
function deleteFaultImage(index: number) { function deleteFaultImage(index: number) {
if (workcase.value.imgs) { if (workcase.imgs) {
workcase.value.imgs.splice(index, 1) workcase.imgs.splice(index, 1)
} }
} }
@@ -499,11 +530,11 @@ async function chooseNameplateImage() {
try { try {
const result = await fileAPI.uploadFile(res.tempFilePaths[0], { const result = await fileAPI.uploadFile(res.tempFilePaths[0], {
module: 'workcase', module: 'workcase',
optsn: workcase.value.workcaseId || 'temp' optsn: workcase.workcaseId || 'temp'
}) })
if (result.success && result.data?.fileId) { if (result.success && result.data?.fileId) {
workcase.value.deviceNamePlateImg = result.data.fileId workcase.deviceNamePlateImg = result.data.fileId
uni.hideLoading() uni.hideLoading()
uni.showToast({ title: '上传成功', icon: 'success' }) uni.showToast({ title: '上传成功', icon: 'success' })
} else { } else {
@@ -524,13 +555,13 @@ async function chooseNameplateImage() {
// 删除铭牌照片 // 删除铭牌照片
function deleteNameplateImage() { function deleteNameplateImage() {
workcase.value.deviceNamePlateImg = '' workcase.deviceNamePlateImg = ''
} }
// 预览铭牌照片 // 预览铭牌照片
function previewNameplateImage() { function previewNameplateImage() {
if (!workcase.value.deviceNamePlateImg) return if (!workcase.deviceNamePlateImg) return
const imageUrl = getImageUrl(workcase.value.deviceNamePlateImg) const imageUrl = getImageUrl(workcase.deviceNamePlateImg)
uni.previewImage({ uni.previewImage({
urls: [imageUrl], urls: [imageUrl],
current: 0 current: 0
@@ -539,9 +570,9 @@ function previewNameplateImage() {
// 预览故障图片 // 预览故障图片
function previewFaultImages(index: number) { function previewFaultImages(index: number) {
if (!workcase.value.imgs || workcase.value.imgs.length === 0) return if (!workcase.imgs || workcase.imgs.length === 0) return
// 将 fileId 数组转换为 URL 数组 // 将 fileId 数组转换为 URL 数组
const imageUrls = workcase.value.imgs.map(fileId => getImageUrl(fileId)) const imageUrls = workcase.imgs.map(fileId => getImageUrl(fileId))
uni.previewImage({ uni.previewImage({
urls: imageUrls, urls: imageUrls,
current: index current: index
@@ -551,35 +582,35 @@ function previewFaultImages(index: number) {
// 提交工单 // 提交工单
async function submitWorkcase() { async function submitWorkcase() {
// 校验必填项 // 校验必填项
if (!workcase.value.username) { if (!workcase.username) {
uni.showToast({ title: '请输入客户姓名', icon: 'none' }) uni.showToast({ title: '请输入客户姓名', icon: 'none' })
return return
} }
if (!workcase.value.phone) { if (!workcase.phone) {
uni.showToast({ title: '请输入联系电话', icon: 'none' }) uni.showToast({ title: '请输入联系电话', icon: 'none' })
return return
} }
if (!workcase.value.device) { if (!workcase.device) {
uni.showToast({ title: '请输入设备名称', icon: 'none' }) uni.showToast({ title: '请输入设备名称', icon: 'none' })
return return
} }
if (!workcase.value.type) { if (!workcase.type) {
uni.showToast({ title: '请选择故障类型', icon: 'none' }) uni.showToast({ title: '请选择故障类型', icon: 'none' })
return return
} }
if (!workcase.value.address) { if (!workcase.address) {
uni.showToast({ title: '请输入现场地址', icon: 'none' }) uni.showToast({ title: '请输入现场地址', icon: 'none' })
return return
} }
if (!workcase.value.description) { if (!workcase.description) {
uni.showToast({ title: '请输入故障描述', icon: 'none' }) uni.showToast({ title: '请输入故障描述', icon: 'none' })
return return
} }
if (!workcase.value.deviceNamePlateImg) { if (!workcase.deviceNamePlateImg) {
uni.showToast({ title: '请上传设备铭牌照片', icon: 'none' }) uni.showToast({ title: '请上传设备铭牌照片', icon: 'none' })
return return
} }
if (!workcase.value.imgs || workcase.value.imgs.length === 0) { if (!workcase.imgs || workcase.imgs.length === 0) {
uni.showToast({ title: '请至少上传一张故障图片', icon: 'none' }) uni.showToast({ title: '请至少上传一张故障图片', icon: 'none' })
return return
} }
@@ -588,7 +619,7 @@ async function submitWorkcase() {
try { try {
// 调用 API 提交工单 // 调用 API 提交工单
const res = await workcaseAPI.createWorkcase(workcase.value) const res = await workcaseAPI.createWorkcase(workcase)
uni.hideLoading() uni.hideLoading()
if (res.success && res.data) { if (res.success && res.data) {
@@ -599,7 +630,7 @@ async function submitWorkcase() {
// 创建成功后直接回到该聊天室(闭环) // 创建成功后直接回到该聊天室(闭环)
setTimeout(() => { setTimeout(() => {
uni.redirectTo({ uni.redirectTo({
url: `/pages/chatRoom/chatRoom/chatRoom?roomId=${workcase.value.roomId}&workcaseId=${res.data.workcaseId || ''}` url: `/pages/chatRoom/chatRoom/chatRoom?roomId=${workcase.roomId}&workcaseId=${res.data.workcaseId || ''}`
}) })
}, 600) }, 600)
} else { } else {