聊天室url修正

This commit is contained in:
2026-01-09 16:40:28 +08:00
parent bfd06dd8f6
commit f4b7337210
18 changed files with 360 additions and 124 deletions

View File

@@ -263,8 +263,8 @@ CREATE TABLE workcase.tb_workcase(
type VARCHAR(50) NOT NULL, -- 故障类型 type VARCHAR(50) NOT NULL, -- 故障类型
device VARCHAR(50) DEFAULT NULL, -- 设备名称 device VARCHAR(50) DEFAULT NULL, -- 设备名称
device_code VARCHAR(50) DEFAULT NULL, -- 设备代码 device_code VARCHAR(50) DEFAULT NULL, -- 设备代码
device_name_plate VARCHAR(50) DEFAULT NULL, -- 设备名称牌 device_name_plate VARCHAR(50) NOT NULL, -- 设备名称牌
device_name_plate_img VARCHAR(50) NOT NULL, -- 设备名称牌图片 device_name_plate_img VARCHAR(50) DEFAULT NULL, -- 设备名称牌图片
address VARCHAR(1000) DEFAULT NULL, -- 现场地址 address VARCHAR(1000) DEFAULT NULL, -- 现场地址
description VARCHAR(1000) DEFAULT NULL, -- 故障描述 description VARCHAR(1000) DEFAULT NULL, -- 故障描述
imgs VARCHAR(50)[] DEFAULT '{}', -- 工单图片id imgs VARCHAR(50)[] DEFAULT '{}', -- 工单图片id

View File

@@ -120,4 +120,6 @@ public class LoginParam implements Serializable {
*/ */
private String iv; private String iv;
private Boolean mockMode;
} }

View File

@@ -224,7 +224,7 @@ public class AesEncryptUtil {
public static void main(String[] args) { public static void main(String[] args) {
AesEncryptUtil aesEncryptUtil = new AesEncryptUtil("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="); AesEncryptUtil aesEncryptUtil = new AesEncryptUtil("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=");
String phone = "17857100376"; String phone = "15170037929";
// 测试加密(每次都不同,不能用于查询) // 测试加密(每次都不同,不能用于查询)
String encryptedPhone1 = aesEncryptUtil.encryptPhone(phone); String encryptedPhone1 = aesEncryptUtil.encryptPhone(phone);

View File

@@ -127,14 +127,44 @@ public class GuestController {
// ========================= 微信小程序用户识别登录 ========================= // ========================= 微信小程序用户识别登录 =========================
/**
* 模拟用户数据用于测试没有手机号校验appid时使用
* 格式:手机号 -> [姓名, 微信ID, 角色]
*/
private static final java.util.Map<String, String[]> MOCK_USERS = new java.util.HashMap<String, String[]>() {{
put("17857100375", new String[]{"超级管理员", "17857100375", "admin"});
put("13870055185", new String[]{"魏瑶", "75719954", "engineer"});
put("15170466624", new String[]{"刘杰", "liujie1370984851", "engineer"});
put("15170037929", new String[]{"万家明", "WJM15170037929", "engineer"});
put("19100185270", new String[]{"戴斌", "BaiBin0714", "guest"});
put("15797790517", new String[]{"余其跃", "a540378218", "guest"});
put("15879126468", new String[]{"李小华", "wxid_vgmmzfdcwx9021", "guest"});
}};
@Operation(summary = "微信小程序用户识别登录") @Operation(summary = "微信小程序用户识别登录")
@PostMapping("/identify") @PostMapping("/identify")
public ResultDomain<LoginDomain> identifyUser(@RequestBody LoginParam loginParam, HttpServletRequest request) { public ResultDomain<LoginDomain> identifyUser(@RequestBody LoginParam loginParam, HttpServletRequest request) {
logger.info("微信小程序登录请求: wechatId={}, code={}, phoneCode={}", logger.info("微信小程序登录请求: wechatId={}, phone={}, mockMode={}",
loginParam.getWechatId(), loginParam.getWechatId(),
loginParam.getCode() != null ? loginParam.getCode().substring(0, Math.min(10, loginParam.getCode().length())) + "..." : null, loginParam.getPhone(),
loginParam.getPhoneCode() != null ? "" : ""); loginParam.getMockMode() != null ? loginParam.getMockMode() : false);
// ========== 模拟模式:直接使用传入的手机号匹配用户 ==========
if (Boolean.TRUE.equals(loginParam.getMockMode()) && loginParam.getPhone() != null) {
String phone = loginParam.getPhone().trim();
String[] mockUser = MOCK_USERS.get(phone);
if (mockUser != null) {
// 设置模拟用户信息
loginParam.setUsername(mockUser[0]);
loginParam.setWechatId(mockUser[1]);
logger.info("模拟登录: phone={}, name={}, wechatId={}, role={}",
phone, mockUser[0], mockUser[1], mockUser[2]);
} else {
return ResultDomain.failure("未找到该手机号对应的测试用户");
}
} else {
// ========== 正常模式通过微信API获取手机号 ==========
// 1. 处理微信登录code获取openid // 1. 处理微信登录code获取openid
String openid = null; String openid = null;
String sessionKey = null; String sessionKey = null;
@@ -144,7 +174,6 @@ public class GuestController {
openid = sessionResult.getData().getOpenid(); openid = sessionResult.getData().getOpenid();
sessionKey = sessionResult.getData().getSessionKey(); sessionKey = sessionResult.getData().getSessionKey();
logger.info("获取openid成功: {}", openid); logger.info("获取openid成功: {}", openid);
// 使用openid作为wechatId
loginParam.setWechatId(openid); loginParam.setWechatId(openid);
} else { } else {
logger.warn("获取openid失败: {}", sessionResult.getMessage()); logger.warn("获取openid失败: {}", sessionResult.getMessage());
@@ -186,6 +215,7 @@ public class GuestController {
if (phoneNumber != null) { if (phoneNumber != null) {
loginParam.setPhone(phoneNumber); loginParam.setPhone(phoneNumber);
} }
}
// 验证参数必须有wechatId或phone // 验证参数必须有wechatId或phone
if ((loginParam.getWechatId() == null || loginParam.getWechatId().trim().isEmpty()) if ((loginParam.getWechatId() == null || loginParam.getWechatId().trim().isEmpty())

View File

@@ -87,6 +87,18 @@ public class WorkcaseController {
return workcaseService.deleteWorkcase(workcase); return workcaseService.deleteWorkcase(workcase);
} }
@Operation(summary = "撤销工单")
@PreAuthorize("hasAuthority('workcase:ticket:update')")
@PostMapping("/revoke/{workcaseId}")
public ResultDomain<TbWorkcaseProcessDTO> revokeWorkcase(@PathVariable(value = "workcaseId") String workcaseId) {
// 创建撤销处理过程
TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO();
process.setWorkcaseId(workcaseId);
process.setAction("repeal");
process.setMessage("用户撤销工单");
return workcaseService.createWorkcaseProcess(process);
}
@Operation(summary = "获取工单详情") @Operation(summary = "获取工单详情")
@PreAuthorize("hasAuthority('workcase:ticket:view')") @PreAuthorize("hasAuthority('workcase:ticket:view')")
@GetMapping("/{workcaseId}") @GetMapping("/{workcaseId}")

View File

@@ -376,6 +376,7 @@ public class VideoMeetingServiceImpl implements VideoMeetingService {
meeting.setJwtToken(userJwtToken); meeting.setJwtToken(userJwtToken);
meeting.setJitsiIframeUrl(jitsiIframeUrl); // 真正的Jitsi URL meeting.setJitsiIframeUrl(jitsiIframeUrl); // 真正的Jitsi URL
meeting.setIframeUrl(meetingPageUrl); // 会议页面URL用于router跳转 meeting.setIframeUrl(meetingPageUrl); // 会议页面URL用于router跳转
meeting.setJitsiServerUrl(jitsiProperties.getServer().getUrl()); // 使用当前配置的服务器URL
logger.info("生成用户专属会议URL成功: meetingId={}, userId={}, status={}", logger.info("生成用户专属会议URL成功: meetingId={}, userId={}, status={}",
meetingId, userId, meeting.getStatus()); meetingId, userId, meeting.getStatus());

View File

@@ -416,10 +416,38 @@ public class WorkcaseServiceImpl implements WorkcaseService {
// 不影响工单完成流程,只记录错误日志 // 不影响工单完成流程,只记录错误日志
} }
} else if (WorkcaseProcessAction.REPEAL.getName().equals(action)) { } else if (WorkcaseProcessAction.REPEAL.getName().equals(action)) {
// 1. 更新工单状态为已撤销
TbWorkcaseDTO workcase = new TbWorkcaseDTO(); TbWorkcaseDTO workcase = new TbWorkcaseDTO();
workcase.setWorkcaseId(workcaseProcess.getWorkcaseId()); workcase.setWorkcaseId(workcaseProcess.getWorkcaseId());
workcase.setStatus("cancelled"); workcase.setStatus("cancelled");
workcaseMapper.updateWorkcase(workcase); workcaseMapper.updateWorkcase(workcase);
// 2. 发送系统评分消息到聊天室
try {
TbWorkcaseDTO workcaseData = workcaseMapper.selectWorkcaseById(workcaseProcess.getWorkcaseId());
if (workcaseData != null && workcaseData.getRoomId() != null) {
// 创建系统评分消息
org.xyzh.api.workcase.dto.TbChatRoomMessageDTO commentMessage = new org.xyzh.api.workcase.dto.TbChatRoomMessageDTO();
commentMessage.setMessageId(IdUtil.generateUUID());
commentMessage.setOptsn(IdUtil.getOptsn());
commentMessage.setRoomId(workcaseData.getRoomId());
commentMessage.setSenderId("system");
commentMessage.setSenderType("system"); // 系统消息
commentMessage.setSenderName("系统");
commentMessage.setMessageType("comment"); // 评分消息
commentMessage.setContent("工单已撤销,请为本次服务评分");
commentMessage.setStatus("sent");
commentMessage.setCreator("system");
// 发送消息到聊天室
chatRoomService.sendMessage(commentMessage);
logger.info("工单撤销,已发送系统评分消息: workcaseId={}, roomId={}",
workcaseProcess.getWorkcaseId(), workcaseData.getRoomId());
}
} catch (Exception e) {
logger.error("发送系统评分消息失败: workcaseId={}", workcaseProcess.getWorkcaseId(), e);
// 不影响工单撤销流程,只记录错误日志
}
} }
workcaseProcess.setCreator(LoginUtil.getCurrentUserId()); workcaseProcess.setCreator(LoginUtil.getCurrentUserId());

View File

@@ -41,6 +41,15 @@ export const workcaseAPI = {
return response.data return response.data
}, },
/**
* 撤销工单
* @param workcaseId 工单ID
*/
async revokeWorkcase(workcaseId: string): Promise<ResultDomain<TbWorkcaseProcessDTO>> {
const response = await api.post<TbWorkcaseProcessDTO>(`${this.baseUrl}/revoke/${workcaseId}`)
return response.data
},
/** /**
* 获取工单详情 * 获取工单详情
* @param workcaseId 工单ID * @param workcaseId 工单ID

View File

@@ -1,11 +1,11 @@
<template> <template>
<AdminLayout title="工单管理" info="查看和处理客户服务工单"> <AdminLayout title="工单管理" info="查看和处理客户服务工单">
<template #action> <!-- <template #action>
<el-button type="primary" @click="showCreateDialog = true"> <el-button type="primary" @click="showCreateDialog = true">
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
创建工单 创建工单
</el-button> </el-button>
</template> </template> -->
<div class="workcase-container"> <div class="workcase-container">
<!-- 筛选区域 --> <!-- 筛选区域 -->

View File

@@ -471,7 +471,7 @@ const handleSendMessage = async (content: string, files: File[]) => {
roomId: currentRoomId.value, roomId: currentRoomId.value,
senderId: loginDomain.user.userId, senderId: loginDomain.user.userId,
senderName: loginDomain.userInfo.username, senderName: loginDomain.userInfo.username,
senderType: 'agent', senderType: 'staff',
content, content,
files: fileIds, files: fileIds,
messageType: 'text' messageType: 'text'

View File

@@ -53,7 +53,7 @@ const getMeetingParams = () => {
} }
// 加载 Jitsi External API 脚本 // 加载 Jitsi External API 脚本
const loadJitsiScript = (): Promise<void> => { const loadJitsiScript = (jitsiServerUrl: string): Promise<void> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 检查是否已经加载 // 检查是否已经加载
if ((window as any).JitsiMeetExternalAPI) { if ((window as any).JitsiMeetExternalAPI) {
@@ -61,16 +61,19 @@ const loadJitsiScript = (): Promise<void> => {
return return
} }
// 从 jitsiServerUrl 提取域名
const urlObj = new URL(jitsiServerUrl)
const scriptUrl = `${urlObj.protocol}//${urlObj.host}/external_api.js`
const script = document.createElement('script') const script = document.createElement('script')
// 从 Jitsi 子域名加载 External API script.src = scriptUrl
script.src = 'https://org.xyzh.yslg.jitsi/external_api.js'
script.async = true script.async = true
script.onload = () => { script.onload = () => {
console.log('[JitsiMeetingView] Jitsi External API 脚本加载成功') console.log('[JitsiMeetingView] Jitsi External API 脚本加载成功:', scriptUrl)
resolve() resolve()
} }
script.onerror = () => { script.onerror = () => {
reject(new Error('加载 Jitsi External API 失败')) reject(new Error('加载 Jitsi External API 失败: ' + scriptUrl))
} }
document.head.appendChild(script) document.head.appendChild(script)
}) })
@@ -85,8 +88,8 @@ const initJitsiMeet = async (jitsiServerUrl: string, roomName: string, jwt: stri
name: displayName name: displayName
}) })
// 加载 External API 脚本 // 加载 External API 脚本从服务器URL动态获取
await loadJitsiScript() await loadJitsiScript(jitsiServerUrl)
const JitsiMeetExternalAPI = (window as any).JitsiMeetExternalAPI const JitsiMeetExternalAPI = (window as any).JitsiMeetExternalAPI

View File

@@ -39,44 +39,6 @@
// 检查并选择模式 // 检查并选择模式
checkModeSelection() { checkModeSelection() {
const mode = uni.getStorageSync('userMode') const mode = uni.getStorageSync('userMode')
if (!mode) {
this.showModeSelector()
}
},
// 显示模式选择器
showModeSelector() {
uni.showActionSheet({
itemList: ['员工模式 (17857100375)', '访客模式 (17857100377)'],
success: (res) => {
let wechatId = ''
let userMode = ''
let phone = ''
if (res.tapIndex === 0) {
wechatId = '17857100375'
phone = '17857100375'
userMode = 'staff'
} else {
wechatId = '17857100377'
phone = '17857100377'
userMode = 'guest'
}
// 存储选择
uni.setStorageSync('userMode', userMode)
uni.setStorageSync('wechatId', wechatId)
uni.setStorageSync('phone', phone)
console.log('已选择模式:', userMode, 'wechatId:', wechatId)
uni.showToast({
title: userMode === 'staff' ? '员工模式' : '访客模式',
icon: 'success'
})
},
fail: () => {
// 用户取消,默认使用访客模式
uni.setStorageSync('userMode', 'guest')
uni.setStorageSync('wechatId', '17857100377')
console.log('默认使用访客模式')
}
})
} }
} }
} }

View File

@@ -38,6 +38,14 @@ export const workcaseAPI = {
return request<TbWorkcaseDTO>({ url: `${this.baseUrl}/${workcaseId}`, method: 'DELETE' }) return request<TbWorkcaseDTO>({ url: `${this.baseUrl}/${workcaseId}`, method: 'DELETE' })
}, },
/**
* 撤销工单
* @param workcaseId 工单ID
*/
revokeWorkcase(workcaseId: string): Promise<ResultDomain<TbWorkcaseProcessDTO>> {
return request<TbWorkcaseProcessDTO>({ url: `${this.baseUrl}/revoke/${workcaseId}`, method: 'POST' })
},
/** /**
* 获取工单详情 * 获取工单详情
* @param workcaseId 工单ID * @param workcaseId 工单ID

View File

@@ -7,7 +7,7 @@
"uni-app-x" : {}, "uni-app-x" : {},
"quickapp" : {}, "quickapp" : {},
"mp-weixin" : { "mp-weixin" : {
"appid" : "wx15e67484db6d431f", "appid" : "wx3708f41b1dc31f52",
"setting" : { "setting" : {
"urlCheck" : false, "urlCheck" : false,
"postcss" : true, "postcss" : true,

View File

@@ -79,9 +79,9 @@
</view> </view>
<!-- 普通用户/客服消息 --> <!-- 普通用户/客服消息 -->
<view v-else :class="msg.senderType === 'guest' ? 'self' : 'other'"> <view v-else :class="msg.senderId === currentUserId ? 'self' : 'other'">
<!-- 对方消息(左侧) --> <!-- 对方消息(左侧) -->
<view class="message-row other-row" v-if="msg.senderType !== 'guest'"> <view class="message-row other-row" v-if="msg.senderId !== currentUserId">
<view> <view>
<view class="avatar"> <view class="avatar">
<text class="avatar-text">{{ msg.senderName?.charAt(0) || '客' }}</text> <text class="avatar-text">{{ msg.senderName?.charAt(0) || '客' }}</text>
@@ -174,11 +174,25 @@ const currentUserName = ref<string>('我')
function loadUserInfo() { function loadUserInfo() {
try { try {
const userInfo = uni.getStorageSync('userInfo') const userInfo = uni.getStorageSync('userInfo')
const loginDomain = uni.getStorageSync('loginDomain')
if (userInfo) { if (userInfo) {
const user = typeof userInfo === 'string' ? JSON.parse(userInfo) : userInfo const user = typeof userInfo === 'string' ? JSON.parse(userInfo) : userInfo
currentUserId.value = user.userId || user.id || '' currentUserId.value = user.userId || user.id || ''
currentUserName.value = user.username || user.nickName || '我' // 优先从 loginDomain.userInfo 获取用户名
if (loginDomain) {
const domain = typeof loginDomain === 'string' ? JSON.parse(loginDomain) : loginDomain
if (domain.userInfo && domain.userInfo.username) {
currentUserName.value = domain.userInfo.username
} else if (domain.userInfo && domain.userInfo.realName) {
currentUserName.value = domain.userInfo.realName
} else {
currentUserName.value = user.username || user.nickName || user.realName || user.name || '用户'
} }
} else {
currentUserName.value = user.username || user.nickName || user.realName || user.name || '用户'
}
}
console.log('[chatRoom] 用户信息:', currentUserId.value, currentUserName.value)
} catch (e) { } catch (e) {
console.error('获取用户信息失败:', e) console.error('获取用户信息失败:', e)
} }

View File

@@ -903,3 +903,53 @@
.skip-auth-btn::after { .skip-auth-btn::after {
border: none; border: none;
} }
// 模拟用户选择列表样式
.mock-user-list {
display: flex;
flex-direction: column;
gap: 16px;
max-height: 400px;
overflow-y: auto;
}
.mock-user-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.group-title {
font-size: 13px;
color: #999;
font-weight: 500;
padding-left: 4px;
margin-bottom: 4px;
}
.mock-user-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: #f8f9fa;
border-radius: 12px;
transition: all 0.2s;
}
.mock-user-item:active {
background: #e9ecef;
transform: scale(0.98);
}
.user-name {
font-size: 16px;
color: #333;
font-weight: 500;
}
.user-phone {
font-size: 14px;
color: #666;
}

View File

@@ -4,6 +4,9 @@
<view class="header" :style="{ paddingTop: headerPaddingTop + 'px', height: headerTotalHeight + 'px' }"> <view class="header" :style="{ paddingTop: headerPaddingTop + 'px', height: headerTotalHeight + 'px' }">
<text class="title">泰豪小电</text> <text class="title">泰豪小电</text>
<view class="header-right"> <view class="header-right">
<button class="workcase-btn" @tap="showUserSelector">
<text class="btn-text">{{userInfo.username || '切换'}}</text>
</button>
<button class="workcase-btn" @tap="goToChatRoomList"> <button class="workcase-btn" @tap="goToChatRoomList">
<text class="btn-text">聊天室</text> <text class="btn-text">聊天室</text>
</button> </button>
@@ -178,22 +181,48 @@
<view class="modal-mask"></view> <view class="modal-mask"></view>
<view class="modal-content phone-auth-content"> <view class="modal-content phone-auth-content">
<view class="modal-header"> <view class="modal-header">
<text class="modal-title">欢迎使用泰豪小电</text> <text class="modal-title">选择测试用户</text>
</view> </view>
<view class="modal-body phone-auth-body"> <view class="modal-body phone-auth-body">
<view class="auth-icon-wrap"> <view class="mock-user-list">
<text class="auth-icon">📱</text> <view class="mock-user-group">
<text class="group-title">管理员</text>
<view class="mock-user-item" @tap="selectMockUser('17857100375', '超级管理员', '17857100375')">
<text class="user-name">超级管理员</text>
<text class="user-phone">17857100375</text>
</view>
</view>
<view class="mock-user-group">
<text class="group-title">工程师</text>
<view class="mock-user-item" @tap="selectMockUser('13870055185', '魏瑶', '75719954')">
<text class="user-name">魏瑶</text>
<text class="user-phone">13870055185</text>
</view>
<view class="mock-user-item" @tap="selectMockUser('15170466624', '刘杰', 'liujie1370984851')">
<text class="user-name">刘杰</text>
<text class="user-phone">15170466624</text>
</view>
<view class="mock-user-item" @tap="selectMockUser('15170037929', '万家明', 'WJM15170037929')">
<text class="user-name">万家明</text>
<text class="user-phone">15170037929</text>
</view>
</view>
<view class="mock-user-group">
<text class="group-title">客户</text>
<view class="mock-user-item" @tap="selectMockUser('19100185270', '戴斌', 'BaiBin0714')">
<text class="user-name">戴斌</text>
<text class="user-phone">19100185270</text>
</view>
<view class="mock-user-item" @tap="selectMockUser('15797790517', '余其跃', 'a540378218')">
<text class="user-name">余其跃</text>
<text class="user-phone">15797790517</text>
</view>
<view class="mock-user-item" @tap="selectMockUser('15879126468', '李小华', 'wxid_vgmmzfdcwx9021')">
<text class="user-name">李小华</text>
<text class="user-phone">15879126468</text>
</view>
</view> </view>
<text class="auth-desc">为了给您提供更好的服务,需要获取您的手机号用于身份识别和工单通知</text>
</view> </view>
<view class="modal-footer phone-auth-footer">
<button
class="modal-btn confirm phone-auth-btn"
open-type="getPhoneNumber"
@getphonenumber="onGetPhoneNumber"
>
<text class="btn-text">授权手机号登录</text>
</button>
</view> </view>
</view> </view>
</view> </view>
@@ -364,7 +393,7 @@
} }
} }
// 获取手机号回调 // 获取手机号回调(保留用于正式环境)
async function onGetPhoneNumber(e: any) { async function onGetPhoneNumber(e: any) {
console.log('获取手机号回调:', e) console.log('获取手机号回调:', e)
@@ -462,6 +491,72 @@
} }
} }
// 选择模拟用户(测试用)
async function selectMockUser(phone: string, name: string, wechatId: string) {
showPhoneAuthModal.value = false
uni.showLoading({ title: '登录中...' })
try {
// 调用 identify 接口,使用模拟模式
const identifyRes = await guestAPI.identify({
phone: phone,
wechatId: wechatId,
username: name,
mockMode: true,
loginType: 'wechat_miniprogram'
})
uni.hideLoading()
if (identifyRes.success && identifyRes.data) {
const loginDomain = identifyRes.data
// 保存登录信息
uni.setStorageSync('token', loginDomain.token || '')
uni.setStorageSync('userInfo', JSON.stringify(loginDomain.user))
uni.setStorageSync('loginDomain', JSON.stringify(loginDomain))
uni.setStorageSync('wechatId', wechatId)
// 更新用户信息
userInfo.value = {
wechatId: wechatId,
username: name,
phone: phone,
userId: loginDomain.user?.userId || ''
}
// 判断用户类型
if (loginDomain.user?.status === 'guest') {
userType.value = false
} else {
userType.value = true
}
console.log('模拟登录成功:', userInfo.value)
uni.showToast({ title: `${name} 登录成功`, icon: 'success' })
} else {
uni.showToast({
title: identifyRes.message || '登录失败',
icon: 'none'
})
showPhoneAuthModal.value = true
}
} catch (error: any) {
console.error('模拟登录失败:', error)
uni.hideLoading()
uni.showToast({
title: error.message || '登录失败',
icon: 'none'
})
showPhoneAuthModal.value = true
}
}
// 显示用户选择弹窗(切换人员)
function showUserSelector() {
showPhoneAuthModal.value = true
}
// 生命周期 // 生命周期
onMounted(() => { onMounted(() => {
// 初始化用户信息 // 初始化用户信息

View File

@@ -1149,17 +1149,39 @@ async function submitWorkcase() {
} }
// 撤销工单 // 撤销工单
function handleRevoke() { async function handleRevoke() {
uni.showModal({ uni.showModal({
title: '撤销确认', title: '撤销确认',
content: '确认撤销该工单?撤销后无法恢复', content: '确认撤销该工单?撤销后无法恢复',
success: (res) => { success: async (res) => {
if (res.confirm) { if (res.confirm) {
// TODO: 调用 API 撤销工单 uni.showLoading({ title: '撤销中...' })
try {
const result = await workcaseAPI.revokeWorkcase(workcaseId.value)
uni.hideLoading()
if (result.success) {
uni.showToast({ uni.showToast({
title: '工单已撤销', title: '工单已撤销',
icon: 'success' icon: 'success'
}) })
// 刷新工单详情
setTimeout(() => {
loadWorkcaseDetail()
}, 500)
} else {
uni.showToast({
title: result.message || '撤销失败',
icon: 'none'
})
}
} catch (error: any) {
uni.hideLoading()
console.error('撤销工单失败:', error)
uni.showToast({
title: error.message || '撤销失败',
icon: 'none'
})
}
} }
} }
}) })