聊天室创建工单
This commit is contained in:
@@ -224,7 +224,45 @@
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
// 铭牌照片
|
||||
// 铭牌照片上传
|
||||
.nameplate-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nameplate-preview {
|
||||
position: relative;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
}
|
||||
|
||||
.nameplate-placeholder {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border: 2rpx dashed #d1d5db;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.nameplate-delete {
|
||||
position: absolute;
|
||||
top: 4rpx;
|
||||
right: 4rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nameplate-photo {
|
||||
width: 100%;
|
||||
max-width: 400rpx;
|
||||
@@ -240,6 +278,18 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #ef4444;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 6rpx;
|
||||
|
||||
@@ -37,28 +37,28 @@
|
||||
<view class="form-container">
|
||||
<!-- 客户姓名 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">客户姓名</text>
|
||||
<text class="form-label">客户姓名<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<input v-if="mode === 'create'" class="form-input" v-model="workcase.username" placeholder="请输入客户姓名" />
|
||||
<text v-else class="form-value">{{ workcase.username || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 联系电话 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">联系电话</text>
|
||||
<text class="form-label">联系电话<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<input v-if="mode === 'create'" class="form-input" v-model="workcase.phone" placeholder="请输入联系电话" />
|
||||
<text v-else class="form-value">{{ workcase.phone || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 设备名称 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">设备名称</text>
|
||||
<text class="form-label">设备名称<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<input v-if="mode === 'create'" class="form-input" v-model="workcase.device" placeholder="请输入设备名称" />
|
||||
<text v-else class="form-value">{{ workcase.device || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 故障类型 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">故障类型</text>
|
||||
<text class="form-label">故障类型<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<picker v-if="mode === 'create'" class="form-picker" :value="typeIndex" :range="faultTypes" @change="onTypeChange">
|
||||
<view class="picker-content">
|
||||
<text class="picker-text">{{ workcase.type || '请选择故障类型' }}</text>
|
||||
@@ -81,30 +81,46 @@
|
||||
|
||||
<!-- 现场地址 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">现场地址</text>
|
||||
<text class="form-label">现场地址<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<input v-if="mode === 'create'" class="form-input" v-model="workcase.address" placeholder="请输入现场地址" />
|
||||
<text v-else class="form-value">{{ workcase.address || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 故障描述 -->
|
||||
<view class="form-item">
|
||||
<text class="form-label">故障描述</text>
|
||||
<text class="form-label">故障描述<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<textarea v-if="mode === 'create'" class="form-textarea" v-model="workcase.description" placeholder="请详细描述故障现象..." maxlength="500" />
|
||||
<text v-else class="form-value">{{ workcase.description || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 设备铭牌 -->
|
||||
<view class="form-item" v-if="mode !== 'create'">
|
||||
<view class="form-item">
|
||||
<text class="form-label">设备铭牌</text>
|
||||
<text class="form-value">{{ workcase.deviceNamePlate || '-' }}</text>
|
||||
<input v-if="mode === 'create'" class="form-input" v-model="workcase.deviceNamePlate" placeholder="请输入设备铭牌"/>
|
||||
<text v-else class="form-value">{{ workcase.deviceNamePlate || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 铭牌照片 -->
|
||||
<view class="form-item" v-if="mode !== 'create' && workcase.deviceNamePlateImg">
|
||||
<text class="form-label">铭牌照片</text>
|
||||
<view class="nameplate-photo" @tap="previewNameplateImage">
|
||||
<image class="nameplate-image" :src="workcase.deviceNamePlateImg" mode="aspectFit" />
|
||||
<view class="form-item">
|
||||
<text class="form-label">铭牌照片<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
<!-- 创建模式:上传铭牌 -->
|
||||
<view v-if="mode === 'create'" class="nameplate-upload">
|
||||
<view v-if="workcase.deviceNamePlateImg" class="nameplate-preview" @tap="previewNameplateImage">
|
||||
<image class="nameplate-image" :src="getImageUrl(workcase.deviceNamePlateImg)" mode="aspectFit" />
|
||||
<view class="nameplate-delete" @tap.stop="deleteNameplateImage">
|
||||
<text class="delete-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="nameplate-placeholder" @tap="chooseNameplateImage">
|
||||
<text class="upload-plus">+</text>
|
||||
<text class="upload-text">上传设备铭牌</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 查看模式:显示铭牌 -->
|
||||
<view v-else-if="workcase.deviceNamePlateImg" class="nameplate-photo" @tap="previewNameplateImage">
|
||||
<image class="nameplate-image" :src="getImageUrl(workcase.deviceNamePlateImg)" mode="aspectFit" />
|
||||
</view>
|
||||
<text v-else class="form-value">-</text>
|
||||
</view>
|
||||
|
||||
<!-- 处理人 -->
|
||||
@@ -125,11 +141,11 @@
|
||||
<view class="section">
|
||||
<view class="section-title">
|
||||
<view class="title-icon">📷</view>
|
||||
<text class="title-text">故障图片</text>
|
||||
<text class="title-text">故障图片<text class="required" v-if="mode === 'create'">*</text></text>
|
||||
</view>
|
||||
<view class="photos-grid">
|
||||
<view class="photo-item" v-for="(img, index) in workcase.imgs" :key="index" @tap="previewFaultImages(index)">
|
||||
<image class="photo-image" :src="img" mode="aspectFill" />
|
||||
<image class="photo-image" :src="getImageUrl(img)" mode="aspectFill" />
|
||||
<view v-if="mode === 'create'" class="photo-delete" @tap.stop="deleteFaultImage(index)">
|
||||
<text class="delete-icon">×</text>
|
||||
</view>
|
||||
@@ -192,7 +208,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import type { TbWorkcaseDTO } from '@/types/workcase'
|
||||
import type { TbWorkcaseDTO, TbWorkcaseProcessDTO } from '@/types/workcase'
|
||||
import { workcaseAPI, fileAPI } from '@/api'
|
||||
|
||||
// 接口定义
|
||||
interface ProcessItem {
|
||||
@@ -216,49 +233,20 @@ const emergencies = ref<string[]>(['普通', '紧急'])
|
||||
const emergencyIndex = ref<number>(0)
|
||||
|
||||
// 工单数据
|
||||
const workcase = ref<TbWorkcaseDTO>({
|
||||
workcaseId: 'W0202501130001',
|
||||
userId: '1',
|
||||
username: '张伟',
|
||||
phone: '138****5678',
|
||||
type: '电气系统故障',
|
||||
device: 'TH-500GF',
|
||||
deviceCode: 'TH-500GF-2023-001',
|
||||
deviceNamePlate: 'TH-500GF',
|
||||
deviceNamePlateImg: 'https://via.placeholder.com/400x300?text=设备铭牌',
|
||||
address: '江西省南昌市红谷滩区xxx路xxx号',
|
||||
description: '发电机启动后电压不稳定,波动范围较大,影响正常使用',
|
||||
emergency: 'emergency',
|
||||
status: 'processing',
|
||||
processorName: '小李',
|
||||
createTime: '2025-01-13 09:30:00',
|
||||
imgs: []
|
||||
})
|
||||
const workcase = ref<TbWorkcaseDTO>({})
|
||||
|
||||
// 处理记录
|
||||
const processList = ref<ProcessItem[]>([
|
||||
{
|
||||
status: 'engineer',
|
||||
actor: '小李',
|
||||
action: '开始处理',
|
||||
desc: '已联系客户,计划今日上门检修',
|
||||
time: '2025-01-13 08:15:00'
|
||||
},
|
||||
{
|
||||
status: 'manager',
|
||||
actor: '管理员',
|
||||
action: '指派工程师',
|
||||
desc: '指派给小李工程师处理',
|
||||
time: '2025-01-12 15:00:00'
|
||||
},
|
||||
{
|
||||
status: 'system',
|
||||
actor: '系统',
|
||||
action: '工单创建',
|
||||
desc: '客户通过小电对话提交',
|
||||
time: '2025-01-12 14:20:00'
|
||||
const processList = ref<ProcessItem[]>([])
|
||||
|
||||
// 获取图片 URL(通过 fileId)
|
||||
function getImageUrl(fileId: string): string {
|
||||
// 如果已经是完整 URL,直接返回
|
||||
if (fileId.startsWith('http://') || fileId.startsWith('https://')) {
|
||||
return fileId
|
||||
}
|
||||
])
|
||||
// 否则通过 fileId 构建下载 URL
|
||||
return fileAPI.getDownloadUrl(fileId)
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad((options: any) => {
|
||||
@@ -273,6 +261,8 @@ onLoad((options: any) => {
|
||||
|
||||
let username = ''
|
||||
let phone = ''
|
||||
let userId = ''
|
||||
let roomId = options.roomId || ''
|
||||
|
||||
if (loginDomainRaw) {
|
||||
// 如果是字符串,需要先解析
|
||||
@@ -282,19 +272,17 @@ onLoad((options: any) => {
|
||||
}
|
||||
|
||||
// 尝试多种可能的字段路径
|
||||
username = loginDomain.userInfo?.username ||
|
||||
loginDomain.user?.username ||
|
||||
loginDomain.username || ''
|
||||
username = loginDomain.userInfo?.username
|
||||
|
||||
phone = loginDomain.user?.phone ||
|
||||
loginDomain.userInfo?.phone ||
|
||||
loginDomain.phone || ''
|
||||
phone = loginDomain.user?.phone
|
||||
userId = loginDomain.userInfo?.userId
|
||||
}
|
||||
|
||||
// 创建模式,初始化表单并填充用户信息
|
||||
workcase.value = {
|
||||
username: username,
|
||||
phone: phone,
|
||||
userId: userId,
|
||||
device: '',
|
||||
type: '',
|
||||
address: '',
|
||||
@@ -302,6 +290,11 @@ onLoad((options: any) => {
|
||||
emergency: 'normal',
|
||||
imgs: []
|
||||
}
|
||||
|
||||
// 如果有 roomId,添加到工单数据中
|
||||
if (roomId) {
|
||||
workcase.value.roomId = roomId
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('读取用户信息失败:', error)
|
||||
// 初始化空表单
|
||||
@@ -315,17 +308,18 @@ onLoad((options: any) => {
|
||||
emergency: 'normal',
|
||||
imgs: []
|
||||
}
|
||||
|
||||
// 如果有 roomId,添加到工单数据中
|
||||
if (options.roomId) {
|
||||
workcase.value.roomId = options.roomId
|
||||
}
|
||||
}
|
||||
} else if (options.workcaseId) {
|
||||
// 查看模式
|
||||
workcaseId.value = options.workcaseId
|
||||
mode.value = 'view'
|
||||
loadWorkcaseDetail(workcaseId.value)
|
||||
}
|
||||
|
||||
// 处理 roomId 参数
|
||||
if (options.roomId) {
|
||||
// TODO: 可以将 roomId 关联到工单
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
@@ -349,8 +343,42 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
// 加载工单详情
|
||||
function loadWorkcaseDetail(id: string) {
|
||||
// TODO: 调用 workcaseAPI.getWorkcaseById(id) 获取数据
|
||||
async function loadWorkcaseDetail(id: string) {
|
||||
uni.showLoading({ title: '加载中...' })
|
||||
try {
|
||||
const res = await workcaseAPI.getWorkcaseById(id)
|
||||
if (res.success && res.data) {
|
||||
workcase.value = res.data
|
||||
// 加载处理记录
|
||||
await loadProcessList(id)
|
||||
} else {
|
||||
uni.showToast({ title: res.message || '加载失败', icon: 'none' })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载工单详情失败:', error)
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 加载处理记录
|
||||
async function loadProcessList(id: string) {
|
||||
try {
|
||||
const res = await workcaseAPI.getWorkcaseProcessList({ workcaseId: id })
|
||||
if (res.success && res.dataList) {
|
||||
// 转换为界面需要的格式
|
||||
processList.value = res.dataList.map((item: TbWorkcaseProcessDTO) => ({
|
||||
status: item.processorType === 'system' ? 'system' : item.processorType === 'manager' ? 'manager' : 'engineer',
|
||||
actor: item.processorName || '未知',
|
||||
action: item.action || '',
|
||||
desc: item.description || '',
|
||||
time: item.createTime || ''
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载处理记录失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态样式类
|
||||
@@ -428,16 +456,43 @@ function onEmergencyChange(e: any) {
|
||||
}
|
||||
|
||||
// 选择故障图片
|
||||
function chooseFaultImages() {
|
||||
async function chooseFaultImages() {
|
||||
uni.chooseImage({
|
||||
count: 9 - (workcase.value.imgs?.length || 0),
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['camera', 'album'],
|
||||
success: (res) => {
|
||||
success: async (res) => {
|
||||
if (!workcase.value.imgs) {
|
||||
workcase.value.imgs = []
|
||||
}
|
||||
workcase.value.imgs.push(...res.tempFilePaths)
|
||||
|
||||
// 上传图片到服务器
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
try {
|
||||
const uploadPromises = res.tempFilePaths.map(filePath =>
|
||||
fileAPI.uploadFile(filePath, {
|
||||
module: 'workcase',
|
||||
optsn: workcase.value.workcaseId || 'temp'
|
||||
})
|
||||
)
|
||||
|
||||
const results = await Promise.all(uploadPromises)
|
||||
|
||||
// 使用 fileId 添加图片
|
||||
results.forEach(result => {
|
||||
if (result.success && result.data?.fileId) {
|
||||
// 存储 fileId,用于提交时使用
|
||||
workcase.value.imgs!.push(result.data.fileId)
|
||||
}
|
||||
})
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '上传成功', icon: 'success' })
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('上传图片失败:', error)
|
||||
uni.showToast({ title: '上传失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('选择图片失败:', err)
|
||||
@@ -452,11 +507,52 @@ function deleteFaultImage(index: number) {
|
||||
}
|
||||
}
|
||||
|
||||
// 选择铭牌照片
|
||||
async function chooseNameplateImage() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['camera', 'album'],
|
||||
success: async (res) => {
|
||||
// 上传铭牌照片到服务器
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
try {
|
||||
const result = await fileAPI.uploadFile(res.tempFilePaths[0], {
|
||||
module: 'workcase',
|
||||
optsn: workcase.value.workcaseId || 'temp'
|
||||
})
|
||||
|
||||
if (result.success && result.data?.fileId) {
|
||||
workcase.value.deviceNamePlateImg = result.data.fileId
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '上传成功', icon: 'success' })
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '上传失败', icon: 'none' })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('上传铭牌照片失败:', error)
|
||||
uni.showToast({ title: '上传失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('选择图片失败:', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除铭牌照片
|
||||
function deleteNameplateImage() {
|
||||
workcase.value.deviceNamePlateImg = ''
|
||||
}
|
||||
|
||||
// 预览铭牌照片
|
||||
function previewNameplateImage() {
|
||||
if (!workcase.value.deviceNamePlateImg) return
|
||||
const imageUrl = getImageUrl(workcase.value.deviceNamePlateImg)
|
||||
uni.previewImage({
|
||||
urls: [workcase.value.deviceNamePlateImg],
|
||||
urls: [imageUrl],
|
||||
current: 0
|
||||
})
|
||||
}
|
||||
@@ -464,38 +560,79 @@ function previewNameplateImage() {
|
||||
// 预览故障图片
|
||||
function previewFaultImages(index: number) {
|
||||
if (!workcase.value.imgs || workcase.value.imgs.length === 0) return
|
||||
// 将 fileId 数组转换为 URL 数组
|
||||
const imageUrls = workcase.value.imgs.map(fileId => getImageUrl(fileId))
|
||||
uni.previewImage({
|
||||
urls: workcase.value.imgs,
|
||||
urls: imageUrls,
|
||||
current: index
|
||||
})
|
||||
}
|
||||
|
||||
// 提交工单
|
||||
function submitWorkcase() {
|
||||
async function submitWorkcase() {
|
||||
// 校验必填项
|
||||
if (!workcase.value.username || !workcase.value.phone || !workcase.value.description) {
|
||||
uni.showToast({
|
||||
title: '请填写必填项',
|
||||
icon: 'none'
|
||||
})
|
||||
if (!workcase.value.username) {
|
||||
uni.showToast({ title: '请输入客户姓名', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.phone) {
|
||||
uni.showToast({ title: '请输入联系电话', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.device) {
|
||||
uni.showToast({ title: '请输入设备名称', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.type) {
|
||||
uni.showToast({ title: '请选择故障类型', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.address) {
|
||||
uni.showToast({ title: '请输入现场地址', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.description) {
|
||||
uni.showToast({ title: '请输入故障描述', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.deviceNamePlateImg) {
|
||||
uni.showToast({ title: '请上传设备铭牌照片', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!workcase.value.imgs || workcase.value.imgs.length === 0) {
|
||||
uni.showToast({ title: '请至少上传一张故障图片', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: '提交中...'
|
||||
})
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
|
||||
// TODO: 调用 API 提交工单
|
||||
setTimeout(() => {
|
||||
try {
|
||||
// 调用 API 提交工单
|
||||
const res = await workcaseAPI.createWorkcase(workcase.value)
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.success && res.data) {
|
||||
uni.showToast({
|
||||
title: '工单创建成功',
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.message || '创建失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('提交工单失败:', error)
|
||||
uni.showToast({
|
||||
title: '工单创建成功',
|
||||
icon: 'success'
|
||||
title: '提交失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
|
||||
Reference in New Issue
Block a user