Commit 4927ce371c725f55015c7996bcb781f1d79c5a60

Authored by wuxw
1 parent 2e0fd29c

开发完成报修功能

Showing 47 changed files with 5512 additions and 77 deletions
src/api/work/myRepairDispatchManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取维修已办列表
  4 +export function listStaffFinishRepairs(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/ownerRepair.listStaffFinishRepairs',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取维修已办列表失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 获取报修类型列表
  24 +export function listRepairSettings(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: 'repair.listRepairSettings',
  28 + method: 'get',
  29 + params
  30 + }).then(response => {
  31 + const res = response.data
  32 + if (res.code === 0) {
  33 + resolve(res)
  34 + } else {
  35 + reject(new Error(res.msg || '获取报修类型失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 结单操作
  44 +export function closeRepairDispatch(data) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/ownerRepair.closeRepairDispatch',
  48 + method: 'post',
  49 + data
  50 + }).then(response => {
  51 + const res = response.data
  52 + if (res.code === 0) {
  53 + resolve(res)
  54 + } else {
  55 + reject(new Error(res.msg || '结单操作失败'))
  56 + }
  57 + }).catch(error => {
  58 + reject(error)
  59 + })
  60 + })
  61 +}
0 62 \ No newline at end of file
... ...
src/api/work/ownerRepairManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询业主报修列表
  4 +export function listOwnerRepairs(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/ownerRepair.listOwnerRepairs',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code == 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取业主报修列表失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 添加业主报修
  24 +export function saveOwnerRepair(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/ownerRepair.saveOwnerRepair',
  28 + method: 'post',
  29 + data
  30 + }).then(response => {
  31 + const res = response.data
  32 + if (res.code == 0) {
  33 + resolve(res)
  34 + } else {
  35 + reject(new Error(res.msg || '添加业主报修失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 更新业主报修
  44 +export function updateOwnerRepair(data) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/ownerRepair.updateOwnerRepair',
  48 + method: 'post',
  49 + data
  50 + }).then(response => {
  51 + const res = response.data
  52 + if (res.code == 0) {
  53 + resolve(res)
  54 + } else {
  55 + reject(new Error(res.msg || '更新业主报修失败'))
  56 + }
  57 + }).catch(error => {
  58 + reject(error)
  59 + })
  60 + })
  61 +}
  62 +
  63 +// 删除业主报修
  64 +export function deleteOwnerRepair(data) {
  65 + return new Promise((resolve, reject) => {
  66 + request({
  67 + url: '/ownerRepair.deleteOwnerRepair',
  68 + method: 'post',
  69 + data
  70 + }).then(response => {
  71 + const res = response.data
  72 + if (res.code == 0) {
  73 + resolve(res)
  74 + } else {
  75 + reject(new Error(res.msg || '删除业主报修失败'))
  76 + }
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 查询报修类型列表
  84 +export function listRepairSettings(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/repair.listRepairSettings',
  88 + method: 'get',
  89 + params
  90 + }).then(response => {
  91 + const res = response.data
  92 + if (res.code == 0) {
  93 + resolve(res)
  94 + } else {
  95 + reject(new Error(res.msg || '获取报修类型列表失败'))
  96 + }
  97 + }).catch(error => {
  98 + reject(error)
  99 + })
  100 + })
  101 +}
  102 +
  103 +// 查询楼栋列表
  104 +export function queryFloors(params) {
  105 + return new Promise((resolve, reject) => {
  106 + request({
  107 + url: '/floor.queryFloors',
  108 + method: 'get',
  109 + params
  110 + }).then(response => {
  111 + const res = response.data
  112 + if (res.code == 0) {
  113 + resolve(res)
  114 + } else {
  115 + reject(new Error(res.msg || '获取楼栋列表失败'))
  116 + }
  117 + }).catch(error => {
  118 + reject(error)
  119 + })
  120 + })
  121 +}
  122 +
  123 +// 查询单元列表
  124 +export function queryUnits(params) {
  125 + return new Promise((resolve, reject) => {
  126 + request({
  127 + url: '/unit.queryUnits',
  128 + method: 'get',
  129 + params
  130 + }).then(response => {
  131 + const res = response.data
  132 + if (res.code == 0) {
  133 + resolve(res)
  134 + } else {
  135 + reject(new Error(res.msg || '获取单元列表失败'))
  136 + }
  137 + }).catch(error => {
  138 + reject(error)
  139 + })
  140 + })
  141 +}
  142 +
  143 +// 查询房屋列表
  144 +export function queryRooms(params) {
  145 + return new Promise((resolve, reject) => {
  146 + request({
  147 + url: '/room.queryRooms',
  148 + method: 'get',
  149 + params
  150 + }).then(response => {
  151 + const res = response.data
  152 + if (res.code == 0) {
  153 + resolve(res)
  154 + } else {
  155 + reject(new Error(res.msg || '获取房屋列表失败'))
  156 + }
  157 + }).catch(error => {
  158 + reject(error)
  159 + })
  160 + })
  161 +}
0 162 \ No newline at end of file
... ...
src/api/work/repairDetailApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取工单详情
  5 +export function getRepairDetail(repairId) {
  6 + return new Promise((resolve, reject) => {
  7 + const communityId = getCommunityId()
  8 + request({
  9 + url: '/ownerRepair.listOwnerRepairs',
  10 + method: 'get',
  11 + params: {
  12 + page: 1,
  13 + row: 1,
  14 + communityId,
  15 + repairId
  16 + }
  17 + }).then(response => {
  18 + const res = response.data
  19 + if (res.code === 0) {
  20 + resolve(res.data[0])
  21 + } else {
  22 + reject(new Error(res.msg || '获取工单详情失败'))
  23 + }
  24 + }).catch(error => {
  25 + reject(error)
  26 + })
  27 + })
  28 +}
  29 +
  30 +// 获取工单图片
  31 +export function getRepairPhotos(repairId) {
  32 + return new Promise((resolve, reject) => {
  33 + const communityId = getCommunityId()
  34 + request({
  35 + url: '/ownerRepair.listOwnerRepairs',
  36 + method: 'get',
  37 + params: {
  38 + page: 1,
  39 + row: 1,
  40 + communityId,
  41 + repairId
  42 + }
  43 + }).then(response => {
  44 + const res = response.data
  45 + if (res.code === 0) {
  46 + resolve({
  47 + photos: res.data[0].repairPhotos || [],
  48 + beforePhotos: res.data[0].beforePhotos || [],
  49 + afterPhotos: res.data[0].afterPhotos || []
  50 + })
  51 + } else {
  52 + reject(new Error(res.msg || '获取工单图片失败'))
  53 + }
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
  59 +
  60 +// 获取维修物品
  61 +export function getRepairResources(repairId) {
  62 + return new Promise((resolve, reject) => {
  63 + const communityId = getCommunityId()
  64 + request({
  65 + url: '/resourceStore.listResourceStoreUseRecords',
  66 + method: 'get',
  67 + params: {
  68 + page: 1,
  69 + row: 100,
  70 + communityId,
  71 + repairId
  72 + }
  73 + }).then(response => {
  74 + const res = response.data
  75 + if (res.code === 0) {
  76 + const resources = res.data.map(item => {
  77 + if (item.resId === '666666') {
  78 + return { ...item, rstName: '自定义', specName: '自定义' }
  79 + }
  80 + return item
  81 + })
  82 + resolve(resources)
  83 + } else {
  84 + reject(new Error(res.msg || '获取维修物品失败'))
  85 + }
  86 + }).catch(error => {
  87 + reject(error)
  88 + })
  89 + })
  90 +}
  91 +
  92 +// 获取工单流转
  93 +export function getRepairFlow(repairId) {
  94 + return new Promise((resolve, reject) => {
  95 + const communityId = getCommunityId()
  96 + request({
  97 + url: '/ownerRepair.listRepairStaffs',
  98 + method: 'get',
  99 + params: {
  100 + page: 1,
  101 + row: 100,
  102 + communityId,
  103 + repairId
  104 + }
  105 + }).then(response => {
  106 + const res = response.data
  107 + if (res.code === 0) {
  108 + resolve(res.data)
  109 + } else {
  110 + reject(new Error(res.msg || '获取工单流转失败'))
  111 + }
  112 + }).catch(error => {
  113 + reject(error)
  114 + })
  115 + })
  116 +}
  117 +
  118 +// 获取工单事件
  119 +export function getRepairEvents(repairId) {
  120 + return new Promise((resolve, reject) => {
  121 + const communityId = getCommunityId()
  122 + request({
  123 + url: '/repair.listRepairEvent',
  124 + method: 'get',
  125 + params: {
  126 + page: 1,
  127 + row: 100,
  128 + communityId,
  129 + repairId
  130 + }
  131 + }).then(response => {
  132 + const res = response.data
  133 + if (res.code === 0) {
  134 + resolve(res.data)
  135 + } else {
  136 + reject(new Error(res.msg || '获取工单事件失败'))
  137 + }
  138 + }).catch(error => {
  139 + reject(error)
  140 + })
  141 + })
  142 +}
  143 +
  144 +// 回复评价
  145 +export function replyAppraise(data) {
  146 + return new Promise((resolve, reject) => {
  147 + const communityId = getCommunityId()
  148 + request({
  149 + url: '/repair.replyRepairAppraise',
  150 + method: 'post',
  151 + data: {
  152 + ...data,
  153 + communityId
  154 + }
  155 + }).then(response => {
  156 + const res = response.data
  157 + if (res.code === 0) {
  158 + resolve()
  159 + } else {
  160 + reject(new Error(res.msg || '回复评价失败'))
  161 + }
  162 + }).catch(error => {
  163 + reject(error)
  164 + })
  165 + })
  166 +}
0 167 \ No newline at end of file
... ...
src/api/work/repairDispatchManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取报修单列表
  5 +export function listStaffRepairs(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/ownerRepair.listStaffRepairs',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + if (res.code === 0) {
  17 + resolve(res)
  18 + } else {
  19 + reject(new Error(res.msg || '获取报修单列表失败'))
  20 + }
  21 + }).catch(error => {
  22 + reject(error)
  23 + })
  24 + })
  25 +}
  26 +
  27 +// 获取报修类型
  28 +export function listRepairSettings(params) {
  29 + return new Promise((resolve, reject) => {
  30 + request({
  31 + url: '/repair.listRepairSettings',
  32 + method: 'get',
  33 + params: {
  34 + ...params,
  35 + communityId: getCommunityId()
  36 + }
  37 + }).then(response => {
  38 + const res = response.data
  39 + if (res.code === 0) {
  40 + resolve(res)
  41 + } else {
  42 + reject(new Error(res.msg || '获取报修类型失败'))
  43 + }
  44 + }).catch(error => {
  45 + reject(error)
  46 + })
  47 + })
  48 +}
  49 +
  50 +// 获取维修师傅列表
  51 +export function listRepairTypeUsers(params) {
  52 + return new Promise((resolve, reject) => {
  53 + request({
  54 + url: '/repair.listRepairTypeUsers',
  55 + method: 'get',
  56 + params: {
  57 + ...params,
  58 + communityId: getCommunityId()
  59 + }
  60 + }).then(response => {
  61 + const res = response.data
  62 + if (res.code === 0) {
  63 + resolve(res)
  64 + } else {
  65 + reject(new Error(res.msg || '获取维修师傅列表失败'))
  66 + }
  67 + }).catch(error => {
  68 + reject(error)
  69 + })
  70 + })
  71 +}
  72 +
  73 +// 报修派单
  74 +export function repairDispatch(data) {
  75 + return new Promise((resolve, reject) => {
  76 + request({
  77 + url: '/ownerRepair.repairDispatch',
  78 + method: 'post',
  79 + data: {
  80 + ...data,
  81 + communityId: getCommunityId()
  82 + }
  83 + }).then(response => {
  84 + const res = response.data
  85 + if (res.code === 0) {
  86 + resolve(res)
  87 + } else {
  88 + reject(new Error(res.msg || '报修派单失败'))
  89 + }
  90 + }).catch(error => {
  91 + reject(error)
  92 + })
  93 + })
  94 +}
  95 +
  96 +// 回访工单
  97 +export function appraiseRepair(data) {
  98 + return new Promise((resolve, reject) => {
  99 + request({
  100 + url: '/ownerRepair.appraiseRepair',
  101 + method: 'post',
  102 + data: {
  103 + ...data,
  104 + communityId: getCommunityId()
  105 + }
  106 + }).then(response => {
  107 + const res = response.data
  108 + if (res.code === 0) {
  109 + resolve(res)
  110 + } else {
  111 + reject(new Error(res.msg || '回访工单失败'))
  112 + }
  113 + }).catch(error => {
  114 + reject(error)
  115 + })
  116 + })
  117 +}
  118 +
  119 +// 暂停报修
  120 +export function repairStop(data) {
  121 + return new Promise((resolve, reject) => {
  122 + request({
  123 + url: '/ownerRepair.repairStop',
  124 + method: 'post',
  125 + data: {
  126 + ...data,
  127 + communityId: getCommunityId()
  128 + }
  129 + }).then(response => {
  130 + const res = response.data
  131 + if (res.code === 0) {
  132 + resolve(res)
  133 + } else {
  134 + reject(new Error(res.msg || '暂停报修失败'))
  135 + }
  136 + }).catch(error => {
  137 + reject(error)
  138 + })
  139 + })
  140 +}
  141 +
  142 +// 启动报修
  143 +export function repairStart(data) {
  144 + return new Promise((resolve, reject) => {
  145 + request({
  146 + url: '/ownerRepair.repairStart',
  147 + method: 'post',
  148 + data: {
  149 + ...data,
  150 + communityId: getCommunityId()
  151 + }
  152 + }).then(response => {
  153 + const res = response.data
  154 + if (res.code === 0) {
  155 + resolve(res)
  156 + } else {
  157 + reject(new Error(res.msg || '启动报修失败'))
  158 + }
  159 + }).catch(error => {
  160 + reject(error)
  161 + })
  162 + })
  163 +}
0 164 \ No newline at end of file
... ...
src/api/work/repairForceFinishManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取报修设置列表
  5 +export function listRepairSettings() {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/repair.listRepairSettings',
  9 + method: 'get',
  10 + params: {
  11 + page: 1,
  12 + row: 50,
  13 + communityId: getCommunityId()
  14 + }
  15 + }).then(response => {
  16 + const res = response.data
  17 + if (res.code == 0) {
  18 + resolve(res.data)
  19 + } else {
  20 + reject(new Error(res.msg || '获取报修设置失败'))
  21 + }
  22 + }).catch(error => {
  23 + reject(error)
  24 + })
  25 + })
  26 +}
  27 +
  28 +// 获取报修池列表
  29 +export function listOwnerRepairs(params) {
  30 + return new Promise((resolve, reject) => {
  31 + request({
  32 + url: '/ownerRepair.listOwnerRepairs',
  33 + method: 'get',
  34 + params: {
  35 + ...params,
  36 + communityId: getCommunityId()
  37 + }
  38 + }).then(response => {
  39 + const res = response.data
  40 + if (res.code == 0) {
  41 + resolve({
  42 + data: res.data,
  43 + total: res.total,
  44 + records: res.records
  45 + })
  46 + } else {
  47 + reject(new Error(res.msg || '获取报修列表失败'))
  48 + }
  49 + }).catch(error => {
  50 + reject(error)
  51 + })
  52 + })
  53 +}
  54 +
  55 +// 获取资源物品类型
  56 +export function listResourceStoreTypes(parentId = '0') {
  57 + return new Promise((resolve, reject) => {
  58 + request({
  59 + url: '/resourceStoreType.listResourceStoreTypes',
  60 + method: 'get',
  61 + params: {
  62 + page: 1,
  63 + row: 100,
  64 + communityId: getCommunityId(),
  65 + parentId,
  66 + giveType: 1
  67 + }
  68 + }).then(response => {
  69 + const res = response.data
  70 + if (res.code == 0) {
  71 + resolve(res.data)
  72 + } else {
  73 + reject(new Error(res.msg || '获取资源物品类型失败'))
  74 + }
  75 + }).catch(error => {
  76 + reject(error)
  77 + })
  78 + })
  79 +}
  80 +
  81 +// 获取用户仓库物品
  82 +export function listUserStorehouses(params) {
  83 + return new Promise((resolve, reject) => {
  84 + request({
  85 + url: '/resourceStore.listUserStorehouses',
  86 + method: 'get',
  87 + params: {
  88 + ...params,
  89 + communityId: getCommunityId(),
  90 + chooseType: "repair",
  91 + flag: 1,
  92 + sign: 1,
  93 + giveType: 1
  94 + }
  95 + }).then(response => {
  96 + const res = response.data
  97 + if (res.code == 0) {
  98 + resolve(res.data)
  99 + } else {
  100 + reject(new Error(res.msg || '获取仓库物品失败'))
  101 + }
  102 + }).catch(error => {
  103 + reject(error)
  104 + })
  105 + })
  106 +}
  107 +
  108 +// 强制回单
  109 +export function repairForceFinish(data) {
  110 + return new Promise((resolve, reject) => {
  111 + request({
  112 + url: '/ownerRepair.repairForceFinish',
  113 + method: 'post',
  114 + data: {
  115 + ...data,
  116 + communityId: getCommunityId()
  117 + }
  118 + }).then(response => {
  119 + const res = response.data
  120 + if (res.code == 0) {
  121 + resolve(res)
  122 + } else {
  123 + reject(new Error(res.msg || '强制回单失败'))
  124 + }
  125 + }).catch(error => {
  126 + reject(error)
  127 + })
  128 + })
  129 +}
  130 +
  131 +// 获取字典数据
  132 +export function getDict(dictType, statusCd) {
  133 + return new Promise((resolve, reject) => {
  134 + request({
  135 + url: '/dict.listDict',
  136 + method: 'get',
  137 + params: {
  138 + dictType,
  139 + statusCd,
  140 + page: 1,
  141 + row: 100
  142 + }
  143 + }).then(response => {
  144 + const res = response.data
  145 + if (res.code == 0) {
  146 + resolve(res.data)
  147 + } else {
  148 + reject(new Error(res.msg || '获取字典失败'))
  149 + }
  150 + }).catch(error => {
  151 + reject(error)
  152 + })
  153 + })
  154 +}
0 155 \ No newline at end of file
... ...
src/api/work/repairPoolManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询报修工单池
  5 +export function listRepairPools(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const baseParams = {
  8 + communityId: getCommunityId(),
  9 + page: params.page || 1,
  10 + row: params.row || 10
  11 + }
  12 +
  13 + const queryParams = { ...baseParams, ...params }
  14 +
  15 + if (queryParams.state === 'TIMEOUT') {
  16 + queryParams.state = ''
  17 + queryParams.timeoutFlag = 'Y'
  18 + }
  19 +
  20 + request({
  21 + url: '/ownerRepair.listOwnerRepairs',
  22 + method: 'get',
  23 + params: queryParams
  24 + }).then(response => {
  25 + const res = response.data
  26 + if (res.code === 0) {
  27 + resolve(res)
  28 + } else {
  29 + reject(new Error(res.msg || 'Failed to fetch repair pools'))
  30 + }
  31 + }).catch(error => {
  32 + reject(error)
  33 + })
  34 + })
  35 +}
  36 +
  37 +// 派单
  38 +export function dispatchRepair(data) {
  39 + return new Promise((resolve, reject) => {
  40 + request({
  41 + url: '/ownerRepair.repairDispatch',
  42 + method: 'post',
  43 + data: {
  44 + ...data,
  45 + communityId: getCommunityId()
  46 + }
  47 + }).then(response => {
  48 + const res = response.data
  49 + if (res.code === 0) {
  50 + resolve(res)
  51 + } else {
  52 + reject(new Error(res.msg || 'Dispatch failed'))
  53 + }
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
  59 +
  60 +// 结束工单
  61 +export function endRepair(data) {
  62 + return new Promise((resolve, reject) => {
  63 + request({
  64 + url: '/ownerRepair.repairEnd',
  65 + method: 'post',
  66 + data: {
  67 + ...data,
  68 + communityId: getCommunityId()
  69 + }
  70 + }).then(response => {
  71 + const res = response.data
  72 + if (res.code === 0) {
  73 + resolve(res)
  74 + } else {
  75 + reject(new Error(res.msg || 'End repair failed'))
  76 + }
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 更新业主报修
  84 +export function updateOwnerRepair(data) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/ownerRepair.updateOwnerRepair',
  88 + method: 'post',
  89 + data: {
  90 + ...data,
  91 + communityId: getCommunityId()
  92 + }
  93 + }).then(response => {
  94 + const res = response.data
  95 + if (res.code === 0) {
  96 + resolve(res)
  97 + } else {
  98 + reject(new Error(res.msg || 'Update failed'))
  99 + }
  100 + }).catch(error => {
  101 + reject(error)
  102 + })
  103 + })
  104 +}
  105 +
  106 +// 删除业主报修
  107 +export function deleteOwnerRepair(data) {
  108 + return new Promise((resolve, reject) => {
  109 + request({
  110 + url: '/ownerRepair.deleteOwnerRepair',
  111 + method: 'post',
  112 + data: {
  113 + ...data,
  114 + communityId: getCommunityId()
  115 + }
  116 + }).then(response => {
  117 + const res = response.data
  118 + if (res.code === 0) {
  119 + resolve(res)
  120 + } else {
  121 + reject(new Error(res.msg || 'Delete failed'))
  122 + }
  123 + }).catch(error => {
  124 + reject(error)
  125 + })
  126 + })
  127 +}
  128 +
  129 +// 抢单
  130 +export function grabbingRepair(data) {
  131 + return new Promise((resolve, reject) => {
  132 + request({
  133 + url: '/ownerRepair.grabbingRepair',
  134 + method: 'post',
  135 + data: {
  136 + ...data,
  137 + communityId: getCommunityId()
  138 + }
  139 + }).then(response => {
  140 + const res = response.data
  141 + if (res.code === 0) {
  142 + resolve(res)
  143 + } else {
  144 + reject(new Error(res.msg || 'Grab order failed'))
  145 + }
  146 + }).catch(error => {
  147 + reject(error)
  148 + })
  149 + })
  150 +}
0 151 \ No newline at end of file
... ...
src/api/work/repairReturnVisitApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询报修回访列表
  4 +export function getRepairReturnVisitList(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/repair/queryRepairReturnVisit',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve({
  14 + data: res.data,
  15 + total: res.total
  16 + })
  17 + } else {
  18 + reject(new Error(res.msg || '查询报修回访列表失败'))
  19 + }
  20 + }).catch(error => {
  21 + reject(error)
  22 + })
  23 + })
  24 +}
  25 +
  26 +// 保存报修回访记录
  27 +export function saveRepairReturnVisit(data) {
  28 + return new Promise((resolve, reject) => {
  29 + request({
  30 + url: '/repair/saveRepairReturnVisit',
  31 + method: 'post',
  32 + data
  33 + }).then(response => {
  34 + const res = response.data
  35 + if (res.code === 0) {
  36 + resolve(res)
  37 + } else {
  38 + reject(new Error(res.msg || '保存回访记录失败'))
  39 + }
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
  45 +
  46 +// 查询报修类型设置
  47 +export function listRepairSettings(params) {
  48 + return new Promise((resolve, reject) => {
  49 + request({
  50 + url: '/repair.listRepairSettings',
  51 + method: 'get',
  52 + params
  53 + }).then(response => {
  54 + const res = response.data
  55 + if (res.code === 0) {
  56 + resolve({
  57 + data: res.data
  58 + })
  59 + } else {
  60 + reject(new Error(res.msg || '查询报修类型设置失败'))
  61 + }
  62 + }).catch(error => {
  63 + reject(error)
  64 + })
  65 + })
  66 +}
0 67 \ No newline at end of file
... ...
src/api/work/repairTypeUserApi.js
... ... @@ -38,7 +38,7 @@ export function updateRepairTypeUser(data) {
38 38  
39 39 return new Promise((resolve, reject) => {
40 40 request({
41   - url: '/repair/updateRepairTypeUser',
  41 + url: '/repair.updateRepairTypeUser',
42 42 method: 'post',
43 43 data
44 44 }).then(response => {
... ... @@ -55,7 +55,7 @@ export function deleteRepairTypeUser(data) {
55 55  
56 56 return new Promise((resolve, reject) => {
57 57 request({
58   - url: '/repair/deleteRepairTypeUser',
  58 + url: '/repair.deleteRepairTypeUser',
59 59 method: 'post',
60 60 data
61 61 }).then(response => {
... ... @@ -71,7 +71,7 @@ export function listOrgTree(params) {
71 71  
72 72 return new Promise((resolve, reject) => {
73 73 request({
74   - url: '/org/listOrgTree',
  74 + url: '/org.listOrgTree',
75 75 method: 'get',
76 76 params
77 77 }).then(response => {
... ...
src/components/work/OrgTreeShow.vue renamed to src/components/org/OrgTreeShow.vue
1 1 <template>
2 2 <div>
3   - <el-tree
4   - ref="orgTree"
5   - :data="orgs"
6   - node-key="id"
7   - :props="defaultProps"
8   - default-expand-all
9   - :expand-on-click-node="false"
10   - @node-click="handleNodeClick"
11   - ></el-tree>
  3 + <el-tree ref="orgTree" :data="orgs" node-key="id" :props="defaultProps" default-expand-all
  4 + :expand-on-click-node="false" @node-click="handleNodeClick"></el-tree>
12 5 </div>
13 6 </template>
14 7  
... ... @@ -36,7 +29,7 @@ export default {
36 29 }
37 30 const response = await listOrgTree(params)
38 31 if (response.code === 0) {
39   - this.orgs = response.data
  32 + this.orgs = [response.data]
40 33 } else {
41 34 this.$message.error(response.msg || this.$t('common.requestFailed'))
42 35 }
... ...
src/components/work/SelectStaff.vue renamed to src/components/staff/SelectStaff.vue
1 1 <template>
2   - <el-dialog
3   - :visible="visible"
4   - :title="$t('selectStaff.title')"
5   - width="80%"
6   - @close="handleClose"
7   - >
  2 + <el-dialog :visible="visible" :title="$t('selectStaff.title')" width="80%" @close="handleClose">
8 3 <el-row :gutter="20">
9 4 <el-col :span="12" class="border-right">
10 5 <div class="text-center">
... ... @@ -19,13 +14,8 @@
19 14 <h4>{{ $t('selectStaff.staffInfo') }}</h4>
20 15 </div>
21 16 <div class="padding-left staff padding padding-top-xs">
22   - <div
23   - v-for="(item, index) in staffs"
24   - :key="index"
25   - class="staff-item"
26   - :class="{'selected': curStaffId === item.staffId}"
27   - @click="selectStaff(item)"
28   - >
  17 + <div v-for="(item, index) in staffs" :key="index" class="staff-item"
  18 + :class="{'selected': curStaffId == item.userId }" @click="selectStaff(item)">
29 19 <div>
30 20 <i class="el-icon-user margin-right-xs"></i>
31 21 {{ item.name }}
... ... @@ -43,7 +33,7 @@
43 33 </template>
44 34  
45 35 <script>
46   -import OrgTreeShow from '@/components/work/OrgTreeShow'
  36 +import OrgTreeShow from '@/components/org/OrgTreeShow'
47 37 import { getStaffInfos } from '@/api/work/repairTypeUserApi'
48 38  
49 39 export default {
... ... @@ -62,8 +52,7 @@ export default {
62 52 }
63 53 },
64 54 methods: {
65   - open(staffConfig) {
66   - this.staffConfig = staffConfig || {}
  55 + open() {
67 56 this.visible = true
68 57 this.$nextTick(() => {
69 58 this.$refs.orgTree.refreshTree()
... ... @@ -83,34 +72,29 @@ export default {
83 72 try {
84 73 const params = {
85 74 orgId: orgId,
86   - row: 50
  75 + row: 50,
  76 + page: 1
87 77 }
88   - const response = await getStaffInfos(params)
89   - if (response.code === 0) {
90   - this.staffs = response.data
  78 + const {staffs} = await getStaffInfos(params)
  79 +
  80 + this.staffs = staffs
91 81 if (this.staffs.length > 0) {
92   - this.curStaffId = this.staffs[0].staffId
  82 + this.curStaffId = this.staffs[0].userId
93 83 }
94   - } else {
95   - this.$message.error(response.msg || this.$t('common.requestFailed'))
96   - }
97 84 } catch (error) {
98 85 console.error('Error loading staff:', error)
99 86 this.$message.error(this.$t('common.requestFailed'))
100 87 }
101 88 },
102 89 selectStaff(staff) {
103   - this.curStaffId = staff.staffId
  90 + this.curStaffId = staff.userId
104 91 this.selectedStaff = staff
105 92 },
106 93 handleSubmit() {
107 94 if (this.selectedStaff) {
108   - if (this.staffConfig.call) {
109   - this.staffConfig.call({
110   - staffId: this.selectedStaff.staffId,
111   - staffName: this.selectedStaff.name
112   - })
113   - }
  95 + this.selectedStaff.staffId = this.selectedStaff.userId
  96 + this.selectedStaff.staffName = this.selectedStaff.userName
  97 + this.$emit('selectStaff', this.selectedStaff)
114 98 this.handleClose()
115 99 } else {
116 100 this.$message.warning(this.$t('selectStaff.selectStaffFirst'))
... ... @@ -124,23 +108,28 @@ export default {
124 108 .border-right {
125 109 border-right: 1px solid #ebeef5;
126 110 }
  111 +
127 112 .padding {
128 113 padding: 15px;
129 114 }
  115 +
130 116 .staff-item {
131 117 padding: 10px;
132 118 margin-bottom: 10px;
133   - border: 1px solid #ebeef5;
  119 +
134 120 border-radius: 4px;
135 121 cursor: pointer;
136 122 }
  123 +
137 124 .staff-item:hover {
138 125 background-color: #f5f7fa;
139 126 }
140   -.staff-item.selected {
  127 +
  128 +.selected {
141 129 background-color: #ecf5ff;
142   - border-color: #409eff;
  130 + border: 1px solid #409eff;
143 131 }
  132 +
144 133 .text-center {
145 134 text-align: center;
146 135 margin-bottom: 15px;
... ...
src/components/work/AppraiseRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairDispatchManage.returnVisit')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="resetForm"
  7 + >
  8 + <el-form :model="form" ref="form" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('repairDispatchManage.returnVisitSuggestion')"
  11 + prop="context"
  12 + :rules="[{ required: true, message: $t('repairDispatchManage.requiredReturnVisitSuggestion'), trigger: 'blur' }]"
  13 + >
  14 + <el-input
  15 + type="textarea"
  16 + :rows="4"
  17 + v-model="form.context"
  18 + :placeholder="$t('repairDispatchManage.requiredReturnVisitSuggestion')"
  19 + />
  20 + </el-form-item>
  21 + </el-form>
  22 +
  23 + <div slot="footer" class="dialog-footer">
  24 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  25 + <el-button type="primary" @click="submitForm">{{ $t('common.submit') }}</el-button>
  26 + </div>
  27 + </el-dialog>
  28 +</template>
  29 +
  30 +<script>
  31 +import { appraiseRepair } from '@/api/work/repairDispatchManageApi'
  32 +import { getCommunityId } from '@/api/community/communityApi'
  33 +
  34 +export default {
  35 + name: 'AppraiseRepair',
  36 + data() {
  37 + return {
  38 + visible: false,
  39 + form: {
  40 + repairId: '',
  41 + repairType: '',
  42 + context: '',
  43 + publicArea: '',
  44 + repairChannel: '',
  45 + maintenanceType: ''
  46 + }
  47 + }
  48 + },
  49 + methods: {
  50 + open(row) {
  51 + this.form = {
  52 + repairId: row.repairId,
  53 + repairType: row.repairType,
  54 + publicArea: row.publicArea,
  55 + repairChannel: row.repairChannel,
  56 + maintenanceType: row.maintenanceType,
  57 + context: ''
  58 + }
  59 + this.visible = true
  60 + },
  61 + async submitForm() {
  62 + this.$refs.form.validate(async valid => {
  63 + if (!valid) return
  64 +
  65 + try {
  66 + const data = {
  67 + ...this.form,
  68 + communityId: getCommunityId()
  69 + }
  70 +
  71 + await appraiseRepair(data)
  72 + this.$emit('success')
  73 + this.visible = false
  74 + this.$message.success(this.$t('common.operationSuccess'))
  75 + } catch (error) {
  76 + console.error('回访失败:', error)
  77 + this.$message.error(this.$t('repairDispatchManage.returnVisitFailed'))
  78 + }
  79 + })
  80 + },
  81 + resetForm() {
  82 + this.$refs.form.resetFields()
  83 + this.form = {
  84 + repairId: '',
  85 + repairType: '',
  86 + context: '',
  87 + publicArea: '',
  88 + repairChannel: '',
  89 + maintenanceType: ''
  90 + }
  91 + }
  92 + }
  93 +}
  94 +</script>
0 95 \ No newline at end of file
... ...
src/components/work/DeleteRepairTypeUser.vue
... ... @@ -10,7 +10,7 @@
10 10 </div>
11 11 <div slot="footer" class="dialog-footer">
12 12 <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
13   - <el-button type="danger" @click="confirmDelete">{{ $t('common.confirmDelete') }}</el-button>
  13 + <el-button type="danger" @click="confirmDelete">{{ $t('common.delete') }}</el-button>
14 14 </div>
15 15 </el-dialog>
16 16 </template>
... ...
src/components/work/EditRepairTypeUser.vue
1 1 <template>
2   - <el-dialog
3   - :visible="visible"
4   - :title="$t('editRepairTypeUser.title')"
5   - width="50%"
6   - @close="handleClose"
7   - >
  2 + <el-dialog :visible="visible" :title="$t('editRepairTypeUser.title')" width="50%" @close="handleClose">
8 3 <el-form ref="form" :model="form" label-width="120px">
9 4 <el-form-item :label="$t('editRepairTypeUser.status')" prop="state" required>
10 5 <el-select v-model="form.state" style="width: 100%">
... ... @@ -35,7 +30,8 @@ export default {
35 30 form: {
36 31 typeUserId: '',
37 32 state: '',
38   - remark: ''
  33 + remark: '',
  34 + repairType: ''
39 35 }
40 36 }
41 37 },
... ... @@ -43,6 +39,7 @@ export default {
43 39 open(repairTypeUser) {
44 40 this.form = {
45 41 typeUserId: repairTypeUser.typeUserId,
  42 + repairType: repairTypeUser.repairType,
46 43 state: repairTypeUser.state,
47 44 remark: repairTypeUser.remark
48 45 }
... ... @@ -53,7 +50,8 @@ export default {
53 50 this.form = {
54 51 typeUserId: '',
55 52 state: '',
56   - remark: ''
  53 + remark: '',
  54 + repairType: ''
57 55 }
58 56 },
59 57 async saveChanges() {
... ... @@ -62,13 +60,13 @@ export default {
62 60 this.$message.warning(this.$t('editRepairTypeUser.statusRequired'))
63 61 return
64 62 }
65   -
  63 +
66 64 const communityId = await getCommunityId()
67 65 const data = {
68 66 ...this.form,
69 67 communityId: communityId
70 68 }
71   -
  69 +
72 70 const response = await updateRepairTypeUser(data)
73 71 if (response.code === 0) {
74 72 this.$message.success(this.$t('common.saveSuccess'))
... ...
src/components/work/StartRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairDispatchManage.confirmOperation')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + >
  7 + <div class="text-center">
  8 + <p>{{ $t('repairDispatchManage.confirmStartRepair') }}</p>
  9 + </div>
  10 +
  11 + <div slot="footer" class="dialog-footer">
  12 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  13 + <el-button type="primary" @click="submitForm">{{ $t('common.confirm') }}</el-button>
  14 + </div>
  15 + </el-dialog>
  16 +</template>
  17 +
  18 +<script>
  19 +import { repairStart } from '@/api/work/repairDispatchManageApi'
  20 +import { getCommunityId } from '@/api/community/communityApi'
  21 +
  22 +export default {
  23 + name: 'StartRepair',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + form: {}
  28 + }
  29 + },
  30 + methods: {
  31 + open(row) {
  32 + this.form = { ...row }
  33 + this.visible = true
  34 + },
  35 + async submitForm() {
  36 + try {
  37 + const data = {
  38 + ...this.form,
  39 + communityId: getCommunityId()
  40 + }
  41 +
  42 + await repairStart(data)
  43 + this.$emit('success')
  44 + this.visible = false
  45 + this.$message.success(this.$t('common.operationSuccess'))
  46 + } catch (error) {
  47 + console.error('启动失败:', error)
  48 + this.$message.error(this.$t('repairDispatchManage.startFailed'))
  49 + }
  50 + }
  51 + }
  52 +}
  53 +</script>
0 54 \ No newline at end of file
... ...
src/components/work/StopRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairDispatchManage.pauseRepair')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="resetForm"
  7 + >
  8 + <el-form :model="form" ref="form" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('repairDispatchManage.pauseReason')"
  11 + prop="remark"
  12 + :rules="[{ required: true, message: $t('repairDispatchManage.requiredPauseReason'), trigger: 'blur' }]"
  13 + >
  14 + <el-input
  15 + type="textarea"
  16 + :rows="4"
  17 + v-model="form.remark"
  18 + :placeholder="$t('repairDispatchManage.requiredPauseReason')"
  19 + />
  20 + </el-form-item>
  21 + </el-form>
  22 +
  23 + <div slot="footer" class="dialog-footer">
  24 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  25 + <el-button type="primary" @click="submitForm">{{ $t('common.submit') }}</el-button>
  26 + </div>
  27 + </el-dialog>
  28 +</template>
  29 +
  30 +<script>
  31 +import { repairStop } from '@/api/work/repairDispatchManageApi'
  32 +import { getCommunityId } from '@/api/community/communityApi'
  33 +
  34 +export default {
  35 + name: 'StopRepair',
  36 + data() {
  37 + return {
  38 + visible: false,
  39 + form: {
  40 + repairId: '',
  41 + repairType: '',
  42 + remark: ''
  43 + }
  44 + }
  45 + },
  46 + methods: {
  47 + open(row) {
  48 + this.form = {
  49 + repairId: row.repairId,
  50 + repairType: row.repairType,
  51 + remark: ''
  52 + }
  53 + this.visible = true
  54 + },
  55 + async submitForm() {
  56 + this.$refs.form.validate(async valid => {
  57 + if (!valid) return
  58 +
  59 + try {
  60 + const data = {
  61 + ...this.form,
  62 + communityId: getCommunityId()
  63 + }
  64 +
  65 + await repairStop(data)
  66 + this.$emit('success')
  67 + this.visible = false
  68 + this.$message.success(this.$t('common.operationSuccess'))
  69 + } catch (error) {
  70 + console.error('暂停失败:', error)
  71 + this.$message.error(this.$t('repairDispatchManage.pauseFailed'))
  72 + }
  73 + })
  74 + },
  75 + resetForm() {
  76 + this.$refs.form.resetFields()
  77 + this.form = {
  78 + repairId: '',
  79 + repairType: '',
  80 + remark: ''
  81 + }
  82 + }
  83 + }
  84 +}
  85 +</script>
0 86 \ No newline at end of file
... ...
src/components/work/addOwnerRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('addOwnerRepair.title')" :visible.sync="visible" width="50%" @close="closeDialog">
  3 + <el-form ref="form" :model="formData" label-width="120px">
  4 + <el-form-item :label="$t('addOwnerRepair.repairScope')" prop="repairObjType" required>
  5 + <el-select v-model="formData.repairObjType" style="width:100%" @change="changeRepairObjType">
  6 + <el-option v-for="item in repairObjTypes" :key="item.value" :label="item.label" :value="item.value" />
  7 + </el-select>
  8 + </el-form-item>
  9 +
  10 + <el-form-item v-if="formData.repairObjType && formData.repairObjType !== '001'"
  11 + :label="$t('addOwnerRepair.belongBuilding')">
  12 + <el-select v-model="formData.floorId" style="width:100%" @change="handleFloorChange">
  13 + <el-option v-for="item in floors" :key="item.floorId" :label="item.floorNum" :value="item.floorId" />
  14 + </el-select>
  15 + </el-form-item>
  16 +
  17 + <el-form-item v-if="formData.repairObjType === '003' || formData.repairObjType === '004'"
  18 + :label="$t('addOwnerRepair.belongUnit')">
  19 + <el-select v-model="formData.unitId" style="width:100%" @change="handleUnitChange">
  20 + <el-option v-for="item in units" :key="item.unitId" :label="item.unitNum" :value="item.unitId" />
  21 + </el-select>
  22 + </el-form-item>
  23 +
  24 + <el-form-item v-if="formData.repairObjType === '004'" :label="$t('addOwnerRepair.belongRoom')">
  25 + <el-select v-model="formData.roomId" style="width:100%" @change="handleRoomChange">
  26 + <el-option v-for="item in rooms" :key="item.roomId" :label="item.roomName" :value="item.roomId" />
  27 + </el-select>
  28 + </el-form-item>
  29 +
  30 + <el-form-item :label="$t('addOwnerRepair.repairType')" prop="repairType" required>
  31 + <el-select v-model="formData.repairType" style="width:100%">
  32 + <el-option v-for="item in repairSettings" :key="item.repairType" :label="item.repairTypeName"
  33 + :value="item.repairType" />
  34 + </el-select>
  35 + </el-form-item>
  36 +
  37 + <el-form-item :label="$t('addOwnerRepair.repairName')" prop="repairName" required>
  38 + <el-input v-model.trim="formData.repairName" />
  39 + </el-form-item>
  40 +
  41 + <el-form-item :label="$t('addOwnerRepair.tel')" prop="tel" required>
  42 + <el-input v-model.trim="formData.tel" type="tel" />
  43 + </el-form-item>
  44 +
  45 + <el-form-item :label="$t('addOwnerRepair.appointmentTime')" prop="appointmentTime" required>
  46 + <el-date-picker v-model="formData.appointmentTime" type="datetime" style="width:100%"
  47 + :placeholder="$t('addOwnerRepair.placeholder.appointmentTime')" value-format="yyyy-MM-dd HH:mm:ss" />
  48 + </el-form-item>
  49 +
  50 + <el-form-item :label="$t('addOwnerRepair.context')" prop="context" required>
  51 + <el-input v-model.trim="formData.context" type="textarea" rows="4" />
  52 + </el-form-item>
  53 + </el-form>
  54 +
  55 + <span slot="footer" class="dialog-footer">
  56 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  57 + <el-button type="primary" @click="saveOwnerRepairInfo">{{ $t('common.submit') }}</el-button>
  58 + </span>
  59 + </el-dialog>
  60 +</template>
  61 +
  62 +<script>
  63 +import * as ownerRepairManageApi from '@/api/work/ownerRepairManageApi'
  64 +import { getCommunityName } from '@/api/community/communityApi'
  65 +import {getFloors, getUnits, queryRooms} from '@/api/room/roomApi'
  66 +import {getDateYYYYMMDD} from '@/utils/dateUtil'
  67 +
  68 +export default {
  69 + name: 'AddOwnerRepair',
  70 + data() {
  71 + return {
  72 + visible: false,
  73 + formData: {
  74 + repairType: '',
  75 + repairName: '',
  76 + tel: '',
  77 + appointmentTime: '',
  78 + context: '',
  79 + repairObjType: '',
  80 + repairObjId: '',
  81 + repairObjName: '',
  82 + repairChannel: 'T',
  83 + floorId: '',
  84 + unitId: '',
  85 + roomId: ''
  86 + },
  87 + repairSettings: [],
  88 + repairObjTypes: [
  89 + { value: '001', label: this.$t('addOwnerRepair.community') },
  90 + { value: '002', label: this.$t('addOwnerRepair.building') },
  91 + { value: '003', label: this.$t('addOwnerRepair.unit') },
  92 + { value: '004', label: this.$t('addOwnerRepair.room') }
  93 + ],
  94 + floors:[],
  95 + units:[],
  96 + rooms:[]
  97 + }
  98 + },
  99 + methods: {
  100 + open() {
  101 + this.visible = true
  102 + this.resetForm()
  103 + this.formData.appointmentTime =getDateYYYYMMDD()
  104 + this.listRepairSettings('T')
  105 + },
  106 + closeDialog() {
  107 + this.$refs.form.resetFields()
  108 + },
  109 + resetForm() {
  110 + this.formData = {
  111 + repairType: '',
  112 + repairName: '',
  113 + tel: '',
  114 + appointmentTime: '',
  115 + context: '',
  116 + repairObjType: '',
  117 + repairObjId: '',
  118 + repairObjName: '',
  119 + repairChannel: 'T'
  120 + }
  121 + },
  122 + handleFloorChange(floorId) {
  123 + if (this.formData.repairObjType == '002') {
  124 + this.formData.repairObjId = floorId
  125 + this.formData.repairObjName = this.floors.find(item => item.floorId == floorId).floorNum + this.$t('addOwnerRepair.buildingSuffix')
  126 + }else{
  127 + this.listUnits()
  128 + }
  129 + },
  130 + handleUnitChange(unitId) {
  131 + if (this.formData.repairObjType == '003') {
  132 + this.formData.repairObjId = unitId
  133 + this.formData.repairObjName = this.units.find(item => item.unitId == unitId).unitNum + this.$t('addOwnerRepair.unitSuffix')
  134 + }else{
  135 + this.listRooms()
  136 + }
  137 + },
  138 + handleRoomChange(roomId) {
  139 + if (this.formData.repairObjType === '004') {
  140 + this.formData.repairObjId = roomId
  141 + this.formData.repairObjName =this.rooms.find(item => item.roomId == roomId).roomNum + this.$t('addOwnerRepair.roomSuffix')
  142 + }
  143 + },
  144 + changeRepairObjType() {
  145 + this.formData.repairType = ''
  146 + const publicArea = this.formData.repairObjType === '004' ? 'F' : 'T'
  147 + this.listRepairSettings(publicArea)
  148 + this.listFloors()
  149 + },
  150 + async listFloors() {
  151 + const params = {
  152 + communityId: this.getCommunityId(),
  153 + page: 1,
  154 + row: 200
  155 + }
  156 + const { apiFloorDataVoList } = await getFloors(params);
  157 + this.floors = apiFloorDataVoList
  158 + },
  159 + async listUnits() {
  160 + const params = {
  161 + communityId: this.getCommunityId(),
  162 + floorId: this.formData.floorId,
  163 + page: 1,
  164 + row: 200
  165 + }
  166 + const data = await getUnits(params);
  167 + this.units = data
  168 + },
  169 + async listRooms() {
  170 + const params = {
  171 + communityId: this.getCommunityId(),
  172 + unitId: this.formData.unitId,
  173 + page: 1,
  174 + row: 500
  175 + }
  176 + const { rooms } = await queryRooms(params);
  177 + this.rooms = rooms
  178 + },
  179 + async listRepairSettings(publicArea) {
  180 + const params = {
  181 + page: 1,
  182 + row: 50,
  183 + publicArea: publicArea,
  184 + communityId: this.getCommunityId()
  185 + }
  186 + const { data } = await ownerRepairManageApi.listRepairSettings(params);
  187 + this.repairSettings = data
  188 + },
  189 + saveOwnerRepairInfo() {
  190 + if (this.formData.repairObjType === '001') {
  191 + this.formData.repairObjId = this.getCommunityId()
  192 + this.formData.repairObjName = getCommunityName()
  193 + }
  194 + this.formData.communityId = this.getCommunityId()
  195 +
  196 + this.$refs.form.validate(valid => {
  197 + if (valid) {
  198 + ownerRepairManageApi.saveOwnerRepair(this.formData).then(res => {
  199 + if (res.code === 0) {
  200 + this.$message.success(this.$t('common.addSuccess'))
  201 + this.visible = false
  202 + this.$emit('success')
  203 + } else {
  204 + this.$message.error(res.msg)
  205 + }
  206 + })
  207 + }
  208 + })
  209 + }
  210 + }
  211 +}
  212 +</script>
0 213 \ No newline at end of file
... ...
src/components/work/chooseSingleResource.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('chooseSingleResource.title')"
  4 + :visible.sync="visible"
  5 + width="60%"
  6 + @close="closeDialog"
  7 + >
  8 + <el-form label-width="120px">
  9 + <el-form-item :label="$t('chooseSingleResource.goodsType')">
  10 + <el-select
  11 + v-model="form.rsId"
  12 + placeholder="请选择"
  13 + style="width:100%"
  14 + @change="listSonResourceStoreType"
  15 + >
  16 + <el-option
  17 + v-for="item in resourceStoreTypes"
  18 + :key="item.rstId"
  19 + :label="item.name"
  20 + :value="item.rstId"
  21 + />
  22 + </el-select>
  23 + </el-form-item>
  24 +
  25 + <template v-if="form.isCustom">
  26 + <el-form-item :label="$t('chooseSingleResource.goodsName')">
  27 + <el-input
  28 + v-model="form.customGoodsName"
  29 + :placeholder="$t('chooseSingleResource.goodsNamePlaceholder')"
  30 + />
  31 + </el-form-item>
  32 + </template>
  33 +
  34 + <template v-else>
  35 + <el-form-item :label="$t('chooseSingleResource.secondaryCategory')">
  36 + <el-select
  37 + v-model="form.rstId"
  38 + placeholder="请选择"
  39 + style="width:100%"
  40 + @change="choseGoods"
  41 + >
  42 + <el-option
  43 + v-for="item in sonResourceStoreTypes"
  44 + :key="item.rstId"
  45 + :label="item.name"
  46 + :value="item.rstId"
  47 + />
  48 + </el-select>
  49 + </el-form-item>
  50 +
  51 + <el-form-item v-if="form.rstId" :label="$t('chooseSingleResource.goods')">
  52 + <el-select
  53 + v-model="form.resId"
  54 + placeholder="请选择"
  55 + style="width:100%"
  56 + @change="chosePrice"
  57 + >
  58 + <el-option
  59 + v-for="item in resourceStores"
  60 + :key="item.resId"
  61 + :label="item.resName"
  62 + :value="item.resId"
  63 + />
  64 + </el-select>
  65 + </el-form-item>
  66 + </template>
  67 +
  68 + <template v-if="form.resId || form.isCustom">
  69 + <el-form-item :label="$t('chooseSingleResource.quantity')">
  70 + <el-input-number
  71 + v-model="form.useNumber"
  72 + :min="1"
  73 + label="数量"
  74 + />
  75 + </el-form-item>
  76 + </template>
  77 + </el-form>
  78 +
  79 + <div slot="footer" class="dialog-footer">
  80 + <el-button @click="closeDialog">{{ $t('chooseSingleResource.cancel') }}</el-button>
  81 + <el-button type="primary" @click="confirmSelection">{{ $t('chooseSingleResource.confirm') }}</el-button>
  82 + </div>
  83 + </el-dialog>
  84 +</template>
  85 +
  86 +<script>
  87 +import { listResourceStoreTypes, listUserStorehouses } from '@/api/work/repairForceFinishManageApi'
  88 +
  89 +export default {
  90 + name: 'ChooseSingleResource',
  91 + props: {
  92 + visible: {
  93 + type: Boolean,
  94 + default: false
  95 + },
  96 + maintenanceType: {
  97 + type: String,
  98 + default: ''
  99 + },
  100 + repairId: {
  101 + type: String,
  102 + default: ''
  103 + }
  104 + },
  105 + data() {
  106 + return {
  107 + form: {
  108 + maintenanceType: '',
  109 + resourceStoreTypes: [],
  110 + sonResourceStoreTypes: [],
  111 + rstId: '',
  112 + rsId: '',
  113 + resId: '',
  114 + repairId: '',
  115 + selectedGoodsInfo: {},
  116 + resourceStores: [],
  117 + isCustom: false,
  118 + customGoodsName: '',
  119 + price: '',
  120 + outLowPrice: '',
  121 + outHighPrice: '',
  122 + useNumber: 1,
  123 + sign: ''
  124 + }
  125 + }
  126 + },
  127 + watch: {
  128 + maintenanceType(newVal) {
  129 + this.form.maintenanceType = newVal
  130 + },
  131 + repairId(newVal) {
  132 + this.form.repairId = newVal
  133 + }
  134 + },
  135 + mounted() {
  136 + this.listResourceStoreType()
  137 + },
  138 + methods: {
  139 + open(param) {
  140 + this.form = {
  141 + ...this.form,
  142 + maintenanceType: param.maintenanceType,
  143 + repairId: param.repairId || '',
  144 + sign: param.sign || ''
  145 + }
  146 + this.listResourceStoreType()
  147 + },
  148 + closeDialog() {
  149 + this.$emit('update:visible', false)
  150 + },
  151 + async listResourceStoreType() {
  152 + try {
  153 + const data = await listResourceStoreTypes('0')
  154 + this.form.resourceStoreTypes = [...data, { rstId: 'custom', name: '自定义' }]
  155 + } catch (error) {
  156 + console.error('获取资源类型失败:', error)
  157 + this.$message.error('获取资源类型失败')
  158 + }
  159 + },
  160 + async listSonResourceStoreType() {
  161 + if (this.form.rsId === 'custom') {
  162 + this.form.isCustom = true
  163 + return
  164 + }
  165 +
  166 + this.form.isCustom = false
  167 + try {
  168 + const data = await listResourceStoreTypes(this.form.rsId)
  169 + this.form.sonResourceStoreTypes = data
  170 + } catch (error) {
  171 + console.error('获取子资源类型失败:', error)
  172 + this.$message.error('获取子资源类型失败')
  173 + }
  174 + },
  175 + async choseGoods() {
  176 + if (!this.form.rstId) return
  177 +
  178 + try {
  179 + const params = {
  180 + repairId: this.form.repairId,
  181 + rstId: this.form.rstId,
  182 + sign: this.form.sign
  183 + }
  184 + const data = await listUserStorehouses(params)
  185 + this.form.resourceStores = data
  186 + } catch (error) {
  187 + console.error('获取商品失败:', error)
  188 + this.$message.error('获取商品失败')
  189 + }
  190 + },
  191 + chosePrice() {
  192 + const selected = this.form.resourceStores.find(item => item.resId === this.form.resId)
  193 + if (selected) {
  194 + this.form.selectedGoodsInfo = selected
  195 + if (selected.outLowPrice === selected.outHighPrice) {
  196 + this.form.price = selected.outLowPrice
  197 + } else {
  198 + this.form.price = ''
  199 + }
  200 + this.form.outLowPrice = selected.outLowPrice
  201 + this.form.outHighPrice = selected.outHighPrice
  202 + }
  203 + },
  204 + confirmSelection() {
  205 + if (this.validateForm()) {
  206 + this.$emit('confirm', {
  207 + ...this.form.selectedGoodsInfo,
  208 + price: this.form.price,
  209 + useNumber: this.form.useNumber,
  210 + isCustom: this.form.isCustom,
  211 + customGoodsName: this.form.customGoodsName
  212 + })
  213 + this.closeDialog()
  214 + }
  215 + },
  216 + validateForm() {
  217 + if (this.form.isCustom) {
  218 + if (!this.form.customGoodsName) {
  219 + this.$message.warning('请填写商品名')
  220 + return false
  221 + }
  222 + if (this.form.maintenanceType === '1001' && !this.form.price) {
  223 + this.$message.warning('请填写价格')
  224 + return false
  225 + }
  226 + } else {
  227 + if (!this.form.rsId) {
  228 + this.$message.warning('请选择商品类型')
  229 + return false
  230 + }
  231 + if (!this.form.rstId) {
  232 + this.$message.warning('请选择二级分类')
  233 + return false
  234 + }
  235 + if (!this.form.resId) {
  236 + this.$message.warning('请选择商品')
  237 + return false
  238 + }
  239 + }
  240 + return true
  241 + }
  242 + }
  243 +}
  244 +</script>
0 245 \ No newline at end of file
... ...
src/components/work/closeOrder.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('closeOrder.closeOrderInfo')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="closeOrderInfo" label-width="120px">
  9 + <el-form-item :label="$t('closeOrder.closeStatus')" prop="state" required>
  10 + <el-select
  11 + v-model="closeOrderInfo.state"
  12 + :placeholder="$t('closeOrder.selectCloseStatus')"
  13 + style="width:100%;"
  14 + >
  15 + <el-option
  16 + :label="$t('closeOrder.closeOrder')"
  17 + value="1100"
  18 + />
  19 + <el-option
  20 + :label="$t('closeOrder.returnOrder')"
  21 + value="1200"
  22 + />
  23 + </el-select>
  24 + </el-form-item>
  25 +
  26 + <el-form-item :label="$t('closeOrder.reason')" prop="remark">
  27 + <el-input
  28 + v-model="closeOrderInfo.remark"
  29 + type="textarea"
  30 + :placeholder="$t('closeOrder.reasonPlaceholder')"
  31 + :rows="4"
  32 + />
  33 + </el-form-item>
  34 + </el-form>
  35 +
  36 + <div slot="footer" class="dialog-footer">
  37 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  38 + <el-button type="primary" @click="_closeOrderSubmit">{{ $t('common.submit') }}</el-button>
  39 + </div>
  40 + </el-dialog>
  41 + </template>
  42 +
  43 + <script>
  44 + export default {
  45 + name: 'CloseOrder',
  46 + data() {
  47 + return {
  48 + visible: false,
  49 + closeOrderInfo: {
  50 + state: '',
  51 + remark: ''
  52 + }
  53 + }
  54 + },
  55 + watch: {
  56 + 'closeOrderInfo.state': {
  57 + handler(val) {
  58 + if (val === '1100') {
  59 + this.closeOrderInfo.remark = this.$t('closeOrder.processed')
  60 + } else {
  61 + this.closeOrderInfo.remark = ''
  62 + }
  63 + },
  64 + deep: true
  65 + }
  66 + },
  67 + methods: {
  68 + open() {
  69 + this.visible = true
  70 + this.resetForm()
  71 + },
  72 +
  73 + handleClose() {
  74 + this.visible = false
  75 + this.resetForm()
  76 + },
  77 +
  78 + resetForm() {
  79 + this.closeOrderInfo = {
  80 + state: '',
  81 + remark: ''
  82 + }
  83 + if (this.$refs.form) {
  84 + this.$refs.form.resetFields()
  85 + }
  86 + },
  87 +
  88 + _closeOrderSubmit() {
  89 + this.$refs.form.validate(valid => {
  90 + if (valid) {
  91 + this.$emit('success', this.closeOrderInfo)
  92 + this.handleClose()
  93 + }
  94 + })
  95 + }
  96 + }
  97 + }
  98 + </script>
  99 +
  100 + <style scoped>
  101 + .dialog-footer {
  102 + text-align: right;
  103 + }
  104 + </style>
0 105 \ No newline at end of file
... ...
src/components/work/deleteOwnerRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('common.delete')" :visible.sync="visible" width="30%">
  3 + <p>{{ $t('common.deleteConfirm') }}</p>
  4 +
  5 + <span slot="footer" class="dialog-footer">
  6 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  7 + <el-button type="primary" @click="confirmDelete">{{ $t('common.confirm') }}</el-button>
  8 + </span>
  9 + </el-dialog>
  10 +</template>
  11 +
  12 +<script>
  13 +import { deleteOwnerRepair } from '@/api/work/repairPoolManageApi'
  14 +import { getCommunityId } from '@/api/community/communityApi'
  15 +
  16 +export default {
  17 + name: 'DeleteOwnerRepair',
  18 + data() {
  19 + return {
  20 + visible: false,
  21 + repairId: ''
  22 + }
  23 + },
  24 + methods: {
  25 + open(repairId) {
  26 + this.repairId = repairId
  27 + this.visible = true
  28 + },
  29 +
  30 + async confirmDelete() {
  31 + try {
  32 + await deleteOwnerRepair({
  33 + repairId: this.repairId,
  34 + communityId: getCommunityId()
  35 + })
  36 +
  37 + this.$message.success(this.$t('common.deleteSuccess'))
  38 + this.visible = false
  39 + this.$emit('success')
  40 + } catch (error) {
  41 + console.error('Delete repair failed:', error)
  42 + }
  43 + }
  44 + }
  45 +}
  46 +</script>
0 47 \ No newline at end of file
... ...
src/components/work/dispatchRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('repairPoolManage.dispatch')" :visible.sync="visible" width="50%" @close="resetForm">
  3 + <el-form ref="form" :model="formData" label-width="120px">
  4 + <el-form-item v-if="formData.action === 'BACK'" :label="$t('repairPoolManage.repairPerson')" prop="staffName">
  5 + <el-input v-model="formData.staffName" disabled />
  6 + </el-form-item>
  7 +
  8 + <el-form-item v-else :label="$t('repairPoolManage.repairPerson')" prop="staffId"
  9 + :rules="[{ required: true, message: $t('repairPoolManage.selectRepairPerson'), trigger: 'blur' }]">
  10 + <el-select v-model="formData.staffId" style="width:100%">
  11 + <el-option v-for="item in repairTypeUsers" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
  12 + </el-select>
  13 + </el-form-item>
  14 +
  15 + <el-form-item :label="$t('repairPoolManage.operationSuggestions')" prop="context"
  16 + :rules="[{ required: true, message: $t('repairPoolManage.operationSuggestions'), trigger: 'blur' }]">
  17 + <el-input v-model="formData.context" type="textarea" :rows="4"
  18 + :placeholder="$t('repairPoolManage.processingOpinionsPlaceholder')" />
  19 + </el-form-item>
  20 + </el-form>
  21 +
  22 + <span slot="footer" class="dialog-footer">
  23 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  24 + <el-button type="primary" @click="submitForm">{{ $t('common.submit') }}</el-button>
  25 + </span>
  26 + </el-dialog>
  27 +</template>
  28 +
  29 +<script>
  30 +import { dispatchRepair } from '@/api/work/repairPoolManageApi'
  31 +import {listRepairTypeUsers} from '@/api/work/repairTypeUserApi'
  32 +import { getCommunityId } from '@/api/community/communityApi'
  33 +
  34 +export default {
  35 + name: 'DispatchRepair',
  36 + data() {
  37 + return {
  38 + visible: false,
  39 + formData: {
  40 + repairId: '',
  41 + repairType: '',
  42 + staffId: '',
  43 + staffName: '',
  44 + context: '',
  45 + action: '',
  46 + repairTypeUsers: [],
  47 + currentUserId: ''
  48 + },
  49 + repairTypeUsers: []
  50 + }
  51 + },
  52 + methods: {
  53 + open(repair) {
  54 + this.formData = {
  55 + ...this.formData,
  56 + repairId: repair.repairId,
  57 + repairType: repair.repairType,
  58 + action: repair.action || 'DISPATCH'
  59 + }
  60 +
  61 + if (repair.action === 'BACK') {
  62 + this.formData.staffId = repair.preStaffId
  63 + this.formData.staffName = repair.preStaffName
  64 + }
  65 +
  66 + this.listRepairTypeUsers()
  67 + this.visible = true
  68 + },
  69 +
  70 + async listRepairTypeUsers() {
  71 + try {
  72 + const params = {
  73 + page: 1,
  74 + row: 50,
  75 + communityId: getCommunityId(),
  76 + repairType: this.formData.repairType,
  77 + state: '9999'
  78 + }
  79 +
  80 + const res = await listRepairTypeUsers(params)
  81 + this.repairTypeUsers = res.data || []
  82 + } catch (error) {
  83 + console.error('Failed to fetch repair type users:', error)
  84 + }
  85 + },
  86 +
  87 + async submitForm() {
  88 + this.$refs.form.validate(async valid => {
  89 + if (valid) {
  90 + try {
  91 + const staff = this.repairTypeUsers.find(item => item.staffId === this.formData.staffId)
  92 + if (staff) {
  93 + this.formData.staffName = staff.staffName
  94 + }
  95 +
  96 + if (this.formData.action === 'TRANSFER' && this.formData.currentUserId === this.formData.staffId) {
  97 + this.$message.error(this.$t('repairPoolManage.cannotTransferSelf'))
  98 + return
  99 + }
  100 +
  101 + const data = {
  102 + ...this.formData,
  103 + communityId: getCommunityId()
  104 + }
  105 +
  106 + await dispatchRepair(data)
  107 + this.$message.success(this.$t('common.operationSuccess'))
  108 + this.visible = false
  109 + this.$emit('success')
  110 + } catch (error) {
  111 + console.error('Dispatch repair failed:', error)
  112 + }
  113 + }
  114 + })
  115 + },
  116 +
  117 + resetForm() {
  118 + this.$refs.form.resetFields()
  119 + this.formData = {
  120 + repairId: '',
  121 + repairType: '',
  122 + staffId: '',
  123 + staffName: '',
  124 + context: '',
  125 + action: '',
  126 + repairTypeUsers: [],
  127 + currentUserId: this.$store.getters.userId
  128 + }
  129 + }
  130 + }
  131 +}
  132 +</script>
0 133 \ No newline at end of file
... ...
src/components/work/editOwnerRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('repairPoolManage.modify')" :visible.sync="visible" width="50%" @close="resetForm">
  3 + <el-form ref="form" :model="formData" label-width="120px">
  4 + <el-form-item :label="$t('repairPoolManage.repairType')" prop="repairType"
  5 + :rules="[{ required: true, message: $t('repairPoolManage.repairTypeRequired'), trigger: 'change' }]">
  6 + <el-select v-model="formData.repairType" style="width:100%">
  7 + <el-option v-for="item in repairSettings" :key="item.repairType" :label="item.repairTypeName"
  8 + :value="item.repairType" />
  9 + </el-select>
  10 + </el-form-item>
  11 +
  12 + <el-form-item :label="$t('repairPoolManage.repairPerson')" prop="repairName"
  13 + :rules="[{ required: true, message: $t('repairPoolManage.repairPersonRequired'), trigger: 'blur' }]">
  14 + <el-input v-model="formData.repairName" />
  15 + </el-form-item>
  16 +
  17 + <el-form-item :label="$t('repairPoolManage.contact')" prop="tel" :rules="[
  18 + { required: true, message: $t('repairPoolManage.contactRequired'), trigger: 'blur' },
  19 + { pattern: /^1[3-9]\d{9}$/, message: $t('repairPoolManage.contactFormat'), trigger: 'blur' }
  20 + ]">
  21 + <el-input v-model="formData.tel" type="tel" />
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('repairPoolManage.appointmentTime')" prop="appointmentTime"
  25 + :rules="[{ required: true, message: $t('repairPoolManage.appointmentTimeRequired'), trigger: 'blur' }]">
  26 + <el-date-picker v-model="formData.appointmentTime" type="datetime" style="width:100%"
  27 + value-format="yyyy-MM-dd HH:mm:ss" :placeholder="$t('repairPoolManage.selectAppointmentTime')" />
  28 + </el-form-item>
  29 +
  30 + <el-form-item :label="$t('repairPoolManage.repairContent')" prop="context"
  31 + :rules="[{ required: true, message: $t('repairPoolManage.repairContentRequired'), trigger: 'blur' }]">
  32 + <el-input v-model="formData.context" type="textarea" :rows="4"
  33 + :placeholder="$t('repairPoolManage.repairContentPlaceholder')" />
  34 + </el-form-item>
  35 + </el-form>
  36 +
  37 + <span slot="footer" class="dialog-footer">
  38 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  39 + <el-button type="primary" @click="submitForm">{{ $t('common.submit') }}</el-button>
  40 + </span>
  41 + </el-dialog>
  42 +</template>
  43 +
  44 +<script>
  45 +import { updateOwnerRepair,listRepairSettings } from '@/api/work/ownerRepairManageApi'
  46 +import { getCommunityId } from '@/api/community/communityApi'
  47 +
  48 +export default {
  49 + name: 'EditOwnerRepair',
  50 + data() {
  51 + return {
  52 + visible: false,
  53 + formData: {
  54 + repairId: '',
  55 + repairType: '',
  56 + repairName: '',
  57 + tel: '',
  58 + appointmentTime: '',
  59 + context: '',
  60 + repairObjType: '',
  61 + repairObjId: '',
  62 + repairObjName: ''
  63 + },
  64 + repairSettings: []
  65 + }
  66 + },
  67 + methods: {
  68 + open(repair) {
  69 + this.formData = { ...repair }
  70 + this.changeRepairObjType()
  71 + this.listRepairSettings()
  72 + this.visible = true
  73 + },
  74 +
  75 + async listRepairSettings() {
  76 + try {
  77 + const publicArea = this.formData.repairObjType === '004' ? 'F' : 'T'
  78 + const params = {
  79 + page: 1,
  80 + row: 50,
  81 + communityId: getCommunityId(),
  82 + publicArea
  83 + }
  84 +
  85 + const res = await listRepairSettings(params)
  86 + this.repairSettings = res.data || []
  87 + } catch (error) {
  88 + console.error('Failed to fetch repair settings:', error)
  89 + }
  90 + },
  91 +
  92 + changeRepairObjType() {
  93 + // 根据报修对象类型设置公共区域标志
  94 + this.listRepairSettings()
  95 + },
  96 +
  97 + async submitForm() {
  98 + this.$refs.form.validate(async valid => {
  99 + if (valid) {
  100 + try {
  101 + if (this.formData.repairObjType === '001') {
  102 + this.formData.repairObjId = getCommunityId()
  103 + this.formData.repairObjName = this.$store.getters.community.name
  104 + }
  105 +
  106 + const data = {
  107 + ...this.formData,
  108 + communityId: getCommunityId()
  109 + }
  110 +
  111 + await updateOwnerRepair(data)
  112 + this.$message.success(this.$t('common.updateSuccess'))
  113 + this.visible = false
  114 + this.$emit('success')
  115 + } catch (error) {
  116 + console.error('Update owner repair failed:', error)
  117 + }
  118 + }
  119 + })
  120 + },
  121 +
  122 + resetForm() {
  123 + this.$refs.form.resetFields()
  124 + this.formData = {
  125 + repairId: '',
  126 + repairType: '',
  127 + repairName: '',
  128 + tel: '',
  129 + appointmentTime: '',
  130 + context: '',
  131 + repairObjType: '',
  132 + repairObjId: '',
  133 + repairObjName: ''
  134 + }
  135 + }
  136 + }
  137 +}
  138 +</script>
0 139 \ No newline at end of file
... ...
src/components/work/endRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairPoolManage.end')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="resetForm"
  7 + >
  8 + <el-form ref="form" :model="formData" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('repairPoolManage.endReason')"
  11 + prop="context"
  12 + :rules="[{ required: true, message: $t('repairPoolManage.endReason'), trigger: 'blur' }]"
  13 + >
  14 + <el-input
  15 + v-model="formData.context"
  16 + type="textarea"
  17 + :rows="4"
  18 + :placeholder="$t('repairPoolManage.endReason')"
  19 + />
  20 + </el-form-item>
  21 + </el-form>
  22 +
  23 + <span slot="footer" class="dialog-footer">
  24 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  25 + <el-button type="primary" @click="submitForm">{{ $t('common.submit') }}</el-button>
  26 + </span>
  27 + </el-dialog>
  28 +</template>
  29 +
  30 +<script>
  31 +import { endRepair } from '@/api/work/repairPoolManageApi'
  32 +import { getCommunityId } from '@/api/community/communityApi'
  33 +
  34 +export default {
  35 + name: 'EndRepair',
  36 + data() {
  37 + return {
  38 + visible: false,
  39 + formData: {
  40 + repairId: '',
  41 + context: ''
  42 + }
  43 + }
  44 + },
  45 + methods: {
  46 + open(repair) {
  47 + this.formData.repairId = repair.repairId
  48 + this.visible = true
  49 + },
  50 +
  51 + async submitForm() {
  52 + this.$refs.form.validate(async valid => {
  53 + if (valid) {
  54 + try {
  55 + const data = {
  56 + ...this.formData,
  57 + communityId: getCommunityId()
  58 + }
  59 +
  60 + await endRepair(data)
  61 + this.$message.success(this.$t('common.operationSuccess'))
  62 + this.visible = false
  63 + this.$emit('success')
  64 + } catch (error) {
  65 + console.error('End repair failed:', error)
  66 + }
  67 + }
  68 + })
  69 + },
  70 +
  71 + resetForm() {
  72 + this.$refs.form.resetFields()
  73 + this.formData = {
  74 + repairId: '',
  75 + context: ''
  76 + }
  77 + }
  78 + }
  79 +}
  80 +</script>
0 81 \ No newline at end of file
... ...
src/components/work/forceFinishRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('forceFinishRepair.title')" :visible.sync="visible" width="60%" @close="closeDialog">
  3 + <el-form label-width="120px">
  4 + <el-form-item v-if="form.repairObjType !== '004'" :label="$t('forceFinishRepair.useMaterial')">
  5 + <el-select v-model="form.maintenanceType" placeholder="请选择" style="width:100%">
  6 + <template v-for="item in maintenanceTypes">
  7 + <el-option :key="item.statusCd" :label="item.name" :value="item.statusCd"
  8 + v-if="item.statusCd !== '1001' && item.statusCd !== '1002'" />
  9 + </template>
  10 + </el-select>
  11 + </el-form-item>
  12 +
  13 + <el-form-item v-else :label="$t('forceFinishRepair.maintenanceType')">
  14 + <el-select v-model="form.maintenanceType" placeholder="请选择" style="width:100%">
  15 + <template v-for="item in maintenanceTypes">
  16 + <el-option :key="item.statusCd" :label="item.name" :value="item.statusCd"
  17 + v-if="item.statusCd !== '1003' && item.statusCd !== '1004'" />
  18 + </template>
  19 + </el-select>
  20 + </el-form-item>
  21 +
  22 + <template v-if="form.maintenanceType === '1001' || form.maintenanceType === '1003'">
  23 + <el-form-item :label="$t('forceFinishRepair.goodsType')">
  24 + <el-select v-model="form.rsId" placeholder="请选择" style="width:100%" @change="listSonResourceStoreType">
  25 + <el-option v-for="item in resourceStoreTypes" :key="item.rstId" :label="item.name" :value="item.rstId" />
  26 + </el-select>
  27 + </el-form-item>
  28 +
  29 + <template v-if="form.isCustom">
  30 + <el-form-item :label="$t('forceFinishRepair.goodsName')">
  31 + <el-input v-model="form.customGoodsName" :placeholder="$t('forceFinishRepair.goodsNamePlaceholder')" />
  32 + </el-form-item>
  33 +
  34 + <el-form-item v-if="form.maintenanceType === '1001'" :label="$t('forceFinishRepair.customPrice')">
  35 + <el-input v-model="form.price" placeholder="必填,请填写自定义价格" />
  36 + </el-form-item>
  37 + </template>
  38 +
  39 + <template v-else>
  40 + <el-form-item :label="$t('forceFinishRepair.secondaryCategory')">
  41 + <el-select v-model="form.rstId" placeholder="请选择" style="width:100%" @change="choseGoods">
  42 + <el-option v-for="item in sonResourceStoreTypes" :key="item.rstId" :label="item.name" :value="item.rstId" />
  43 + </el-select>
  44 + </el-form-item>
  45 +
  46 + <el-form-item v-if="form.rstId" :label="$t('forceFinishRepair.goods')">
  47 + <el-select v-model="form.resId" placeholder="请选择" style="width:100%" @change="chosePrice">
  48 + <el-option v-for="item in resourceStores" :key="item.resId" :label="item.resName" :value="item.resId" />
  49 + </el-select>
  50 + </el-form-item>
  51 + </template>
  52 +
  53 + <template v-if="form.resId || form.isCustom">
  54 + <el-form-item :label="$t('forceFinishRepair.quantity')">
  55 + <el-input-number v-model="form.useNumber" :min="1" label="数量" />
  56 + </el-form-item>
  57 +
  58 + <el-form-item v-if="form.maintenanceType === '1001'" :label="$t('forceFinishRepair.paymentMethod')">
  59 + <el-select v-model="form.payType" placeholder="请选择" style="width:100%">
  60 + <el-option v-for="item in payTypes" :key="item.statusCd" :label="item.name" :value="item.statusCd" />
  61 + </el-select>
  62 + </el-form-item>
  63 + </template>
  64 + </template>
  65 +
  66 + <el-form-item :label="$t('forceFinishRepair.explanation')">
  67 + <el-input v-model="form.context" type="textarea" :placeholder="$t('forceFinishRepair.explanationPlaceholder')"
  68 + :rows="4" />
  69 + </el-form-item>
  70 + </el-form>
  71 +
  72 + <div slot="footer" class="dialog-footer">
  73 + <el-button @click="closeDialog">{{ $t('forceFinishRepair.cancel') }}</el-button>
  74 + <el-button type="primary" @click="submitForceFinish">{{ $t('forceFinishRepair.submit') }}</el-button>
  75 + </div>
  76 + </el-dialog>
  77 +</template>
  78 +
  79 +<script>
  80 +import {
  81 + listResourceStoreTypes,
  82 + listUserStorehouses,
  83 + repairForceFinish,
  84 + getDict
  85 +} from '@/api/work/repairForceFinishManageApi'
  86 +
  87 +export default {
  88 + name: 'ForceFinishRepair',
  89 + props: {
  90 + visible: {
  91 + type: Boolean,
  92 + default: false
  93 + }
  94 + },
  95 + data() {
  96 + return {
  97 + form: {
  98 + repairId: '',
  99 + repairType: '',
  100 + repairObjType: '',
  101 + context: '',
  102 + maintenanceType: '',
  103 + resId: '',
  104 + rsId: '',
  105 + isCustom: false,
  106 + customGoodsName: '',
  107 + price: '',
  108 + useNumber: 1,
  109 + rstId: '',
  110 + payType: '',
  111 + selectedGoodsInfo: {},
  112 + payTypes: [],
  113 + resourceStores: [],
  114 + sonResourceStoreTypes: [],
  115 + resourceStoreTypes: [],
  116 + maintenanceTypes: []
  117 + },
  118 + payTypes: [],
  119 + maintenanceTypes: []
  120 + }
  121 + },
  122 + mounted() {
  123 + this.loadDictData()
  124 + },
  125 + methods: {
  126 + open(repair) {
  127 + this.form = {
  128 + ...this.form,
  129 + repairId: repair.repairId,
  130 + repairType: repair.repairType,
  131 + repairObjType: repair.repairObjType
  132 + }
  133 + this.listResourceStoreType()
  134 + },
  135 + closeDialog() {
  136 + this.$emit('update:visible', false)
  137 + },
  138 + async loadDictData() {
  139 + try {
  140 + this.maintenanceTypes = await getDict('r_repair_pool', 'maintenance_type')
  141 + this.payTypes = await getDict('r_repair_pool', 'pay_type')
  142 + } catch (error) {
  143 + console.error('获取字典数据失败:', error)
  144 + this.$message.error('获取字典数据失败')
  145 + }
  146 + },
  147 + async listResourceStoreType() {
  148 + try {
  149 + const data = await listResourceStoreTypes('0')
  150 + this.form.resourceStoreTypes = [...data, { rstId: 'custom', name: '自定义' }]
  151 + } catch (error) {
  152 + console.error('获取资源类型失败:', error)
  153 + this.$message.error('获取资源类型失败')
  154 + }
  155 + },
  156 + async listSonResourceStoreType() {
  157 + if (this.form.rsId === 'custom') {
  158 + this.form.isCustom = true
  159 + return
  160 + }
  161 +
  162 + this.form.isCustom = false
  163 + try {
  164 + const data = await listResourceStoreTypes(this.form.rsId)
  165 + this.form.sonResourceStoreTypes = data
  166 + } catch (error) {
  167 + console.error('获取子资源类型失败:', error)
  168 + this.$message.error('获取子资源类型失败')
  169 + }
  170 + },
  171 + async choseGoods() {
  172 + if (!this.form.rstId) return
  173 +
  174 + try {
  175 + const params = {
  176 + repairId: this.form.repairId,
  177 + rstId: this.form.rstId
  178 + }
  179 + const data = await listUserStorehouses(params)
  180 + this.form.resourceStores = data
  181 + } catch (error) {
  182 + console.error('获取商品失败:', error)
  183 + this.$message.error('获取商品失败')
  184 + }
  185 + },
  186 + chosePrice() {
  187 + const selected = this.form.resourceStores.find(item => item.resId === this.form.resId)
  188 + if (selected) {
  189 + this.form.selectedGoodsInfo = selected
  190 + if (selected.outLowPrice === selected.outHighPrice) {
  191 + this.form.price = selected.outLowPrice
  192 + } else {
  193 + this.form.price = ''
  194 + }
  195 + }
  196 + },
  197 + async submitForceFinish() {
  198 + if (this.validateForm()) {
  199 + try {
  200 + await repairForceFinish(this.form)
  201 + this.$message.success('强制回单成功')
  202 + this.closeDialog()
  203 + this.$emit('success')
  204 + } catch (error) {
  205 + console.error('强制回单失败:', error)
  206 + this.$message.error('强制回单失败')
  207 + }
  208 + }
  209 + },
  210 + validateForm() {
  211 + if (!this.form.maintenanceType) {
  212 + this.$message.warning('请选择维修类型')
  213 + return false
  214 + }
  215 +
  216 + if (this.form.maintenanceType === '1001' || this.form.maintenanceType === '1003') {
  217 + if (!this.form.rsId) {
  218 + this.$message.warning('请选择商品类型')
  219 + return false
  220 + }
  221 +
  222 + if (this.form.isCustom) {
  223 + if (!this.form.customGoodsName) {
  224 + this.$message.warning('请填写商品名')
  225 + return false
  226 + }
  227 + if (this.form.maintenanceType === '1001' && !this.form.price) {
  228 + this.$message.warning('请填写价格')
  229 + return false
  230 + }
  231 + } else {
  232 + if (!this.form.rstId) {
  233 + this.$message.warning('请选择二级分类')
  234 + return false
  235 + }
  236 + if (!this.form.resId) {
  237 + this.$message.warning('请选择商品')
  238 + return false
  239 + }
  240 + }
  241 +
  242 + if (this.form.maintenanceType === '1001' && !this.form.payType) {
  243 + this.$message.warning('请选择支付方式')
  244 + return false
  245 + }
  246 + }
  247 +
  248 + if (!this.form.context) {
  249 + this.$message.warning('请填写说明')
  250 + return false
  251 + }
  252 +
  253 + return true
  254 + }
  255 + }
  256 +}
  257 +</script>
0 258 \ No newline at end of file
... ...
src/components/work/repairDetailEvent.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table :data="events" border style="width: 100%">
  4 + <el-table-column prop="eventTypeName" :label="$t('repairDetailEvent.eventType')" align="center" />
  5 + <el-table-column prop="staffName" :label="$t('repairDetailEvent.staff')" align="center" />
  6 + <el-table-column prop="remark" :label="$t('repairDetailEvent.description')" align="center" />
  7 + <el-table-column prop="createTime" :label="$t('repairDetailEvent.createTime')" align="center" />
  8 + </el-table>
  9 + </div>
  10 +</template>
  11 +
  12 +<script>
  13 +import { getRepairEvents } from '@/api/work/repairDetailApi'
  14 +
  15 +export default {
  16 + name: 'RepairDetailEvent',
  17 + props: {
  18 + repairId: {
  19 + type: String,
  20 + required: true
  21 + }
  22 + },
  23 + data() {
  24 + return {
  25 + events: []
  26 + }
  27 + },
  28 + methods: {
  29 + async loadData() {
  30 + try {
  31 + this.events = await getRepairEvents(this.repairId)
  32 + } catch (error) {
  33 + this.$message.error(error.message)
  34 + }
  35 + }
  36 + }
  37 +}
  38 +</script>
0 39 \ No newline at end of file
... ...
src/components/work/repairDetailPhotos.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <div v-if="photos.length > 0" class="row padding">
  4 + <div class="text-title">{{ $t('repairDetail.orderPhotos') }}</div>
  5 + <div v-for="(item, index) in photos" :key="index" class="form-group margin-left">
  6 + <el-image style="width: 120px; height: 120px;" :src="item.url" :preview-src-list="[item.url]" fit="cover"
  7 + @click="openFile(item)"></el-image>
  8 + </div>
  9 + </div>
  10 +
  11 + <div v-if="beforePhotos.length > 0" class="row padding">
  12 + <div class="text-title">{{ $t('repairDetail.beforeRepairPhotos') }}</div>
  13 + <div v-for="(item, index) in beforePhotos" :key="index" class="form-group margin-left">
  14 + <el-image style="width: 120px; height: 120px;" :src="item.url" :preview-src-list="[item.url]" fit="cover"
  15 + @click="openFile(item)"></el-image>
  16 + </div>
  17 + </div>
  18 +
  19 + <div v-if="afterPhotos.length > 0" class="row padding">
  20 + <div class="text-title">{{ $t('repairDetail.afterRepairPhotos') }}</div>
  21 + <div v-for="(item, index) in afterPhotos" :key="index" class="form-group margin-left">
  22 + <el-image style="width: 120px; height: 120px;" :src="item.url" :preview-src-list="[item.url]" fit="cover"
  23 + @click="openFile(item)"></el-image>
  24 + </div>
  25 + </div>
  26 + </div>
  27 +</template>
  28 +
  29 +<script>
  30 +import { getRepairPhotos } from '@/api/work/repairDetailApi'
  31 +
  32 +export default {
  33 + name: 'RepairDetailPhotos',
  34 + props: {
  35 + repairId: {
  36 + type: String,
  37 + required: true
  38 + }
  39 + },
  40 + data() {
  41 + return {
  42 + photos: [],
  43 + beforePhotos: [],
  44 + afterPhotos: []
  45 + }
  46 + },
  47 + methods: {
  48 + async loadData() {
  49 + try {
  50 + console.log(this.repairId)
  51 + const data = await getRepairPhotos(this.repairId)
  52 + this.photos = data.photos
  53 + this.beforePhotos = data.beforePhotos
  54 + this.afterPhotos = data.afterPhotos
  55 + } catch (error) {
  56 + this.$message.error(error.message)
  57 + }
  58 + },
  59 + openFile(item) {
  60 + this.$emit('show-image', item)
  61 + }
  62 + }
  63 +}
  64 +</script>
  65 +
  66 +<style scoped>
  67 +.padding {
  68 + padding: 10px 0;
  69 +}
  70 +
  71 +.text-title {
  72 + font-size: 16px;
  73 + font-weight: bold;
  74 + margin-bottom: 10px;
  75 +}
  76 +
  77 +.margin-left {
  78 + margin-left: 10px;
  79 + display: inline-block;
  80 +}
  81 +</style>
0 82 \ No newline at end of file
... ...
src/components/work/repairDetailResource.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table :data="resources" border style="width: 100%">
  4 + <el-table-column prop="resId" :label="$t('repairDetailResource.itemCode')" align="center" />
  5 + <el-table-column :label="$t('repairDetailResource.itemType')" align="center">
  6 + <template slot-scope="scope">
  7 + {{ scope.row.parentRstName }} > {{ scope.row.rstName }}
  8 + </template>
  9 + </el-table-column>
  10 + <el-table-column prop="resourceStoreName" :label="$t('repairDetailResource.itemName')" align="center" />
  11 + <el-table-column :label="$t('repairDetailResource.specification')" align="center">
  12 + <template slot-scope="scope">
  13 + {{ scope.row.specName || '-' }}
  14 + </template>
  15 + </el-table-column>
  16 + <el-table-column :label="$t('repairDetailResource.quantity')" align="center">
  17 + <template slot-scope="scope">
  18 + {{ scope.row.quantity }}{{ scope.row.miniUnitCodeName }}
  19 + </template>
  20 + </el-table-column>
  21 + <el-table-column :label="$t('repairDetailResource.price')" align="center">
  22 + <template slot-scope="scope">
  23 + {{ scope.row.unitPrice || '-' }}
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column prop="createUserName" :label="$t('repairDetailResource.user')" align="center" />
  27 + <el-table-column prop="createTime" :label="$t('repairDetailResource.time')" align="center" />
  28 + </el-table>
  29 + </div>
  30 +</template>
  31 +
  32 +<script>
  33 +import { getRepairResources } from '@/api/work/repairDetailApi'
  34 +
  35 +export default {
  36 + name: 'RepairDetailResource',
  37 + props: {
  38 + repairId: {
  39 + type: String,
  40 + required: true
  41 + }
  42 + },
  43 + data() {
  44 + return {
  45 + resources: []
  46 + }
  47 + },
  48 + methods: {
  49 + async loadData() {
  50 + try {
  51 + this.resources = await getRepairResources(this.repairId)
  52 + } catch (error) {
  53 + this.$message.error(error.message)
  54 + }
  55 + }
  56 + }
  57 +}
  58 +</script>
0 59 \ No newline at end of file
... ...
src/components/work/repairDetailUser.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table :data="users" border style="width: 100%">
  4 + <el-table-column :label="$t('repairDetailUser.serial')" align="center" width="80">
  5 + <template slot-scope="scope">
  6 + {{ scope.$index + 1 }}
  7 + </template>
  8 + </el-table-column>
  9 + <el-table-column prop="staffName" :label="$t('repairDetailUser.handler')" align="center" />
  10 + <el-table-column :label="$t('repairDetailUser.status')" align="center">
  11 + <template slot-scope="scope">
  12 + <template v-if="(scope.row.state === '10009' || scope.row.state === '12000') && scope.row.payTypeName">
  13 + {{ scope.row.stateName }}({{ scope.row.payTypeName }})
  14 + </template>
  15 + <template v-else>
  16 + {{ scope.row.stateName }}
  17 + <span v-if="scope.row.state === '10007'">
  18 + (<a href="javascript:void(0)" @click="openRepairAppraise(scope.row)">{{ $t('repairDetailUser.reply') }}</a>)
  19 + </span>
  20 + </template>
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column prop="startTime" :label="$t('repairDetailUser.startTime')" align="center" />
  24 + <el-table-column prop="endTime" :label="$t('repairDetailUser.endTime')" align="center" />
  25 + <el-table-column prop="duration" :label="$t('repairDetailUser.duration')" align="center" />
  26 + <el-table-column prop="context" :label="$t('repairDetailUser.opinion')" align="center" />
  27 + </el-table>
  28 + </div>
  29 +</template>
  30 +
  31 +<script>
  32 +import { getRepairFlow } from '@/api/work/repairDetailApi'
  33 +
  34 +export default {
  35 + name: 'RepairDetailUser',
  36 + props: {
  37 + repairId: {
  38 + type: String,
  39 + required: true
  40 + }
  41 + },
  42 + data() {
  43 + return {
  44 + users: []
  45 + }
  46 + },
  47 + methods: {
  48 + async loadData() {
  49 + try {
  50 + this.users = await getRepairFlow(this.repairId)
  51 + } catch (error) {
  52 + this.$message.error(error.message)
  53 + }
  54 + },
  55 + openRepairAppraise(row) {
  56 + this.$emit('open-appraise', row)
  57 + }
  58 + }
  59 +}
  60 +</script>
0 61 \ No newline at end of file
... ...
src/components/work/visitOwnerRepair.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairReturnVisit.visitTitle')"
  4 + :visible.sync="visible"
  5 + width="600px"
  6 + @close="resetForm"
  7 + >
  8 + <el-form
  9 + ref="visitForm"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="100px"
  13 + label-position="right"
  14 + >
  15 + <el-form-item
  16 + :label="$t('repairReturnVisit.satisfaction')"
  17 + prop="visitType"
  18 + >
  19 + <el-select
  20 + v-model="formData.visitType"
  21 + :placeholder="$t('repairReturnVisit.satisfactionPlaceholder')"
  22 + style="width:100%"
  23 + >
  24 + <el-option
  25 + :label="$t('repairReturnVisit.satisfied')"
  26 + value="1001"
  27 + />
  28 + <el-option
  29 + :label="$t('repairReturnVisit.unsatisfied')"
  30 + value="2002"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 +
  35 + <el-form-item
  36 + :label="$t('repairReturnVisit.visitContent')"
  37 + prop="context"
  38 + >
  39 + <el-input
  40 + v-model="formData.context"
  41 + type="textarea"
  42 + :rows="4"
  43 + :placeholder="$t('repairReturnVisit.visitContentPlaceholder')"
  44 + />
  45 + </el-form-item>
  46 + </el-form>
  47 +
  48 + <div slot="footer" class="dialog-footer">
  49 + <el-button @click="visible = false">
  50 + {{ $t('common.cancel') }}
  51 + </el-button>
  52 + <el-button type="primary" @click="submitVisit">
  53 + {{ $t('common.submit') }}
  54 + </el-button>
  55 + </div>
  56 + </el-dialog>
  57 +</template>
  58 +
  59 +<script>
  60 +import { saveRepairReturnVisit } from '@/api/work/repairReturnVisitApi'
  61 +
  62 +export default {
  63 + name: 'VisitOwnerRepair',
  64 + data() {
  65 + return {
  66 + visible: false,
  67 + formData: {
  68 + repairId: '',
  69 + visitType: '',
  70 + context: ''
  71 + },
  72 + rules: {
  73 + visitType: [
  74 + { required: true, message: this.$t('repairReturnVisit.satisfactionRequired'), trigger: 'change' }
  75 + ],
  76 + context: [
  77 + { required: true, message: this.$t('repairReturnVisit.visitContentRequired'), trigger: 'blur' },
  78 + { max: 1000, message: this.$t('repairReturnVisit.visitContentMaxLength'), trigger: 'blur' }
  79 + ]
  80 + }
  81 + }
  82 + },
  83 + methods: {
  84 + open(repairPool) {
  85 + this.formData = {
  86 + repairId: repairPool.repairId,
  87 + visitType: '',
  88 + context: '',
  89 + communityId: this.$store.getters.communityId
  90 + }
  91 + this.visible = true
  92 + },
  93 + resetForm() {
  94 + this.$refs.visitForm.resetFields()
  95 + },
  96 + submitVisit() {
  97 + this.$refs.visitForm.validate(async valid => {
  98 + if (valid) {
  99 + try {
  100 + await saveRepairReturnVisit(this.formData)
  101 + this.$message.success(this.$t('common.submitSuccess'))
  102 + this.visible = false
  103 + this.$emit('success')
  104 + } catch (error) {
  105 + console.error('保存回访记录失败:', error)
  106 + }
  107 + }
  108 + })
  109 + }
  110 + }
  111 +}
  112 +</script>
0 113 \ No newline at end of file
... ...
src/i18n/commonLang.js
... ... @@ -44,7 +44,8 @@ export const messages = {
44 44 hour:'hour',
45 45 more:'More',
46 46 tip:'Tip',
47   - selectFile:'Select File'
  47 + selectFile:'Select File',
  48 + change:'Change'
48 49 }
49 50 },
50 51 zh: {
... ... @@ -92,7 +93,8 @@ export const messages = {
92 93 hour:'时',
93 94 more:'更多',
94 95 tip:'提示',
95   - selectFile:'选择文件'
  96 + selectFile:'选择文件',
  97 + change:'变更'
96 98 }
97 99 }
98 100 }
99 101 \ No newline at end of file
... ...
src/i18n/index.js
... ... @@ -163,6 +163,14 @@ import { messages as listCarFeeMessages } from &#39;../views/fee/listCarFeeLang&#39;
163 163 import { messages as repairSettingMessages } from '../views/work/repairSettingLang'
164 164 import { messages as repairTypeUserMessages } from '../views/work/repairTypeUserLang'
165 165  
  166 +import { messages as ownerRepairManageMessages } from '../views/work/ownerRepairManageLang'
  167 +import { messages as repairPoolManageMessages } from '../views/work/repairPoolManageLang'
  168 +import { messages as repairDetailMessages } from '../views/work/repairDetailLang'
  169 +import { messages as repairDispatchManageMessages } from '../views/work/repairDispatchManageLang'
  170 +import { messages as myRepairDispatchManageMessages } from '../views/work/myRepairDispatchManageLang'
  171 +import { messages as repairReturnVisitMessages } from '../views/work/repairReturnVisitLang'
  172 +import { messages as repairForceFinishManageMessages } from '../views/work/repairForceFinishManageLang'
  173 +
166 174 Vue.use(VueI18n)
167 175  
168 176 // 合并所有语言配置
... ... @@ -328,6 +336,14 @@ const messages = {
328 336 ...listCarFeeMessages.en,
329 337 ...repairSettingMessages.en,
330 338 ...repairTypeUserMessages.en,
  339 +
  340 + ...ownerRepairManageMessages.en,
  341 + ...repairPoolManageMessages.en,
  342 + ...repairDetailMessages.en,
  343 + ...repairDispatchManageMessages.en,
  344 + ...myRepairDispatchManageMessages.en,
  345 + ...repairReturnVisitMessages.en,
  346 + ...repairForceFinishManageMessages.en,
331 347 },
332 348 zh: {
333 349 ...loginMessages.zh,
... ... @@ -490,6 +506,14 @@ const messages = {
490 506 ...listCarFeeMessages.zh,
491 507 ...repairSettingMessages.zh,
492 508 ...repairTypeUserMessages.zh,
  509 +
  510 + ...ownerRepairManageMessages.zh,
  511 + ...repairPoolManageMessages.zh,
  512 + ...repairDetailMessages.zh,
  513 + ...repairDispatchManageMessages.zh,
  514 + ...myRepairDispatchManageMessages.zh,
  515 + ...repairReturnVisitMessages.zh,
  516 + ...repairForceFinishManageMessages.zh,
493 517 }
494 518 }
495 519  
... ...
src/router/index.js
... ... @@ -802,10 +802,45 @@ const routes = [
802 802 component: () => import('@/views/work/repairSettingList.vue')
803 803 },
804 804 {
805   - path:'/views/work/repairTypeUser',
806   - name:'/views/work/repairTypeUser',
  805 + path: '/views/work/repairTypeUser',
  806 + name: '/views/work/repairTypeUser',
807 807 component: () => import('@/views/work/repairTypeUserList.vue')
808   - },
  808 + },
  809 + {
  810 + path: '/pages/property/ownerRepairManage',
  811 + name: '/pages/property/ownerRepairManage',
  812 + component: () => import('@/views/work/ownerRepairManageList.vue')
  813 + },
  814 + {
  815 + path: '/pages/property/repairPoolManage',
  816 + name: '/pages/property/repairPoolManage',
  817 + component: () => import('@/views/work/repairPoolManageList.vue')
  818 + },
  819 + {
  820 + path: '/views/work/repairDetail',
  821 + name: '/views/work/repairDetail',
  822 + component: () => import('@/views/work/repairDetailList.vue')
  823 + },
  824 + {
  825 + path: '/pages/property/repairDispatchManage',
  826 + name: '/pages/property/repairDispatchManage',
  827 + component: () => import('@/views/work/repairDispatchManageList.vue')
  828 + },
  829 + {
  830 + path: '/pages/property/myRepairDispatchManage',
  831 + name: '/pages/property/myRepairDispatchManage',
  832 + component: () => import('@/views/work/myRepairDispatchManageList.vue')
  833 + },
  834 + {
  835 + path: '/pages/property/repairReturnVisit',
  836 + name: '/pages/property/repairReturnVisit',
  837 + component: () => import('@/views/work/repairReturnVisitList.vue')
  838 + },
  839 + {
  840 + path: '/pages/property/repairForceFinishManage',
  841 + name: '/pages/property/repairForceFinishManage',
  842 + component: () => import('@/views/work/repairForceFinishManageList.vue')
  843 + },
809 844 // 其他子路由可以在这里添加
810 845 ]
811 846 },
... ...
src/views/work/myRepairDispatchManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + myRepairDispatchManage: {
  4 + queryCondition: 'Query Conditions',
  5 + selectMaintenanceType: 'Select Maintenance Type',
  6 + inputRepairName: 'Enter Reporter Name',
  7 + inputRepairTel: 'Enter Reporter Phone',
  8 + selectRepairType: 'Select Repair Type',
  9 + selectRepairState: 'Select Repair State',
  10 + inputRepairId: 'Enter Work Order ID',
  11 + repairDispatch: 'Repair Dispatch',
  12 + repairId: 'Work Order ID',
  13 + location: 'Location',
  14 + repairType: 'Repair Type',
  15 + maintenanceType: 'Maintenance Type',
  16 + repairPerson: 'Reporter',
  17 + contact: 'Contact',
  18 + appointmentTime: 'Appointment Time',
  19 + state: 'Status',
  20 + operation: 'Operation',
  21 + detail: 'Detail',
  22 + scheduledTask: 'Scheduled Task',
  23 + paidService: 'Paid Service',
  24 + freeService: 'Free Service',
  25 + needMaterial: 'Need Material',
  26 + noMaterial: 'No Material'
  27 + },
  28 + closeOrder: {
  29 + closeOrderInfo: 'Close Order Information',
  30 + closeStatus: 'Close Status',
  31 + selectCloseStatus: 'Please select',
  32 + closeOrder: 'Close Order',
  33 + returnOrder: 'Return Order',
  34 + reason: 'Reason',
  35 + reasonPlaceholder: 'Optional, please fill in the reason',
  36 + processed: 'Processed'
  37 + }
  38 + },
  39 + zh: {
  40 + myRepairDispatchManage: {
  41 + queryCondition: '查询条件',
  42 + selectMaintenanceType: '请选择维修类型',
  43 + inputRepairName: '请输入报修人',
  44 + inputRepairTel: '请输入报修电话',
  45 + selectRepairType: '请选择报修类型',
  46 + selectRepairState: '请选择报修状态',
  47 + inputRepairId: '请输入工单编号',
  48 + repairDispatch: '报修已办',
  49 + repairId: '工单编号',
  50 + location: '位置',
  51 + repairType: '报修类型',
  52 + maintenanceType: '维修类型',
  53 + repairPerson: '报修人',
  54 + contact: '联系方式',
  55 + appointmentTime: '预约时间',
  56 + state: '状态',
  57 + operation: '操作',
  58 + detail: '详情',
  59 + scheduledTask: '定时任务处理',
  60 + paidService: '有偿服务',
  61 + freeService: '无偿服务',
  62 + needMaterial: '需要用料',
  63 + noMaterial: '无需用料'
  64 + },
  65 + closeOrder: {
  66 + closeOrderInfo: '结单信息',
  67 + closeStatus: '结单状态',
  68 + selectCloseStatus: '请选择',
  69 + closeOrder: '结单',
  70 + returnOrder: '退单',
  71 + reason: '原因',
  72 + reasonPlaceholder: '选填,请填写原因',
  73 + processed: '已处理'
  74 + }
  75 + }
  76 + }
0 77 \ No newline at end of file
... ...
src/views/work/myRepairDispatchManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="padding">
  3 + <el-row>
  4 + <el-col :span="24">
  5 + <el-card>
  6 + <div slot="header" class="flex justify-between">
  7 + <div>{{ $t('myRepairDispatchManage.queryCondition') }}</div>
  8 + <div class="ibox-tools" style="top:10px;">
  9 + <el-button type="text" style="margin-right:10px;" @click="_moreCondition()">
  10 + {{ myRepairDispatchInfo.moreCondition ? $t('common.hide') : $t('common.more') }}
  11 + </el-button>
  12 + </div>
  13 + </div>
  14 + <div class="">
  15 + <el-row :gutter="20">
  16 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  17 + <el-select v-model="myRepairDispatchInfo.conditions.maintenanceType"
  18 + :placeholder="$t('myRepairDispatchManage.selectMaintenanceType')" style="width:100%;">
  19 + <el-option v-for="(item, index) in myRepairDispatchInfo.maintenanceTypes" :key="index" :label="item.name"
  20 + :value="item.statusCd" />
  21 + </el-select>
  22 + </el-col>
  23 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  24 + <el-input v-model.trim="myRepairDispatchInfo.conditions.repairName"
  25 + :placeholder="$t('myRepairDispatchManage.inputRepairName')" clearable />
  26 + </el-col>
  27 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  28 + <el-input v-model.trim="myRepairDispatchInfo.conditions.tel"
  29 + :placeholder="$t('myRepairDispatchManage.inputRepairTel')" clearable />
  30 + </el-col>
  31 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  32 + <el-select v-model="myRepairDispatchInfo.conditions.repairType"
  33 + :placeholder="$t('myRepairDispatchManage.selectRepairType')" style="width:100%;">
  34 + <el-option v-for="(item, index) in myRepairDispatchInfo.repairTypes" :key="index"
  35 + :label="item.repairTypeName" :value="item.repairType" />
  36 + </el-select>
  37 + </el-col>
  38 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  39 + <el-select v-model="myRepairDispatchInfo.conditions.state"
  40 + :placeholder="$t('myRepairDispatchManage.selectRepairState')" style="width:100%;">
  41 + <el-option v-for="(item, index) in myRepairDispatchInfo.states" :key="index" :label="item.name"
  42 + :value="item.statusCd" />
  43 + </el-select>
  44 + </el-col>
  45 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  46 + <el-button type="primary" icon="el-icon-search" @click="_queryMyRepairDispatchMethod">
  47 + {{ $t('common.search') }}
  48 + </el-button>
  49 + <el-button icon="el-icon-refresh" @click="_resetMyRepairDispatchMethod">
  50 + {{ $t('common.reset') }}
  51 + </el-button>
  52 + </el-col>
  53 + </el-row>
  54 + <el-row v-show="myRepairDispatchInfo.moreCondition" :gutter="20" style="margin-top:15px;">
  55 + <el-col :xs="24" :sm="12" :md="6" :lg="4">
  56 + <el-input v-model.trim="myRepairDispatchInfo.conditions.repairId"
  57 + :placeholder="$t('myRepairDispatchManage.inputRepairId')" clearable />
  58 + </el-col>
  59 + </el-row>
  60 + </div>
  61 + </el-card>
  62 + </el-col>
  63 + </el-row>
  64 +
  65 + <el-row style="margin-top:20px;">
  66 + <el-col :span="24">
  67 + <el-card>
  68 + <div slot="header" class="flex justify-between">
  69 + <div>
  70 + <span>{{ myRepairDispatchInfo.conditions.roomName }}</span>
  71 + <span>{{ $t('myRepairDispatchManage.repairDispatch') }}</span>
  72 + </div>
  73 + </div>
  74 + <div class="">
  75 + <el-table :data="myRepairDispatchInfo.ownerRepairs" border style="width: 100%">
  76 + <el-table-column prop="repairId" :label="$t('myRepairDispatchManage.repairId')" align="center" />
  77 + <el-table-column prop="repairObjName" :label="$t('myRepairDispatchManage.location')" align="center" />
  78 + <el-table-column prop="repairTypeName" :label="$t('myRepairDispatchManage.repairType')" align="center" />
  79 + <el-table-column :label="$t('myRepairDispatchManage.maintenanceType')" align="center">
  80 + <template slot-scope="scope">
  81 + {{ getMaintenanceTypeName(scope.row.maintenanceType) }}
  82 + </template>
  83 + </el-table-column>
  84 + <el-table-column prop="repairName" :label="$t('myRepairDispatchManage.repairPerson')" align="center" />
  85 + <el-table-column prop="tel" :label="$t('myRepairDispatchManage.contact')" align="center" />
  86 + <el-table-column prop="appointmentTime" :label="$t('myRepairDispatchManage.appointmentTime')"
  87 + align="center" />
  88 + <el-table-column :label="$t('myRepairDispatchManage.state')" align="center">
  89 + <template slot-scope="scope">
  90 + <span
  91 + v-if="scope.row.state == '1800' && (scope.row.returnVisitFlag == '001' || scope.row.returnVisitFlag == '002')">
  92 + {{ scope.row.stateName }}({{ $t('myRepairDispatchManage.scheduledTask') }})
  93 + </span>
  94 + <span v-else>
  95 + {{ scope.row.stateName }}
  96 + </span>
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column :label="$t('common.operation')" align="center" width="120">
  100 + <template slot-scope="scope">
  101 + <el-button size="mini" type="primary" @click="_openRepairDetail(scope.row)">
  102 + {{ $t('common.detail') }}
  103 + </el-button>
  104 + </template>
  105 + </el-table-column>
  106 + </el-table>
  107 +
  108 + <el-pagination background layout="total, sizes, prev, pager, next, jumper"
  109 + :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  110 + :total="pagination.total" @size-change="handleSizeChange" @current-change="handleCurrentChange"
  111 + style="margin-top: 20px;" />
  112 + </div>
  113 + </el-card>
  114 + </el-col>
  115 + </el-row>
  116 +
  117 + <close-order ref="closeOrderModal" @success="handleCloseOrderSuccess" />
  118 + </div>
  119 +</template>
  120 +
  121 +<script>
  122 +import { listStaffFinishRepairs, listRepairSettings, closeRepairDispatch } from '@/api/work/myRepairDispatchManageApi'
  123 +import { getDict } from '@/api/community/communityApi'
  124 +import CloseOrder from '@/components/work/closeOrder'
  125 +
  126 +export default {
  127 + name: 'MyRepairDispatchManageList',
  128 + components: {
  129 + CloseOrder
  130 + },
  131 + data() {
  132 + return {
  133 + myRepairDispatchInfo: {
  134 + ownerRepairs: [],
  135 + moreCondition: false,
  136 + currentRepairId: '',
  137 + repairTypes: [],
  138 + states: [],
  139 + maintenanceTypes: [],
  140 + conditions: {
  141 + pageFlag: 'myRepairDispatch',
  142 + repairId: '',
  143 + repairName: '',
  144 + tel: '',
  145 + repairType: '',
  146 + roomId: '',
  147 + roomName: '',
  148 + ownerId: '',
  149 + state: '',
  150 + maintenanceType: '',
  151 + page: 1,
  152 + row: 10,
  153 + communityId: ''
  154 + }
  155 + },
  156 + pagination: {
  157 + current: 1,
  158 + size: 10,
  159 + total: 0
  160 + }
  161 + }
  162 + },
  163 + created() {
  164 + this.initData()
  165 + },
  166 + methods: {
  167 + async initData() {
  168 + try {
  169 + this.myRepairDispatchInfo.conditions.communityId = this.getCommunityId()
  170 + await this.getDictData()
  171 + this._listRepairTypes()
  172 + this._listOwnerRepairs(1, this.pagination.size)
  173 + } catch (error) {
  174 + console.error('初始化数据失败:', error)
  175 + }
  176 + },
  177 +
  178 + async getDictData() {
  179 + try {
  180 + const stateData = await getDict('r_repair_pool', 'state')
  181 + this.myRepairDispatchInfo.states = stateData
  182 +
  183 + const maintenanceTypeData = await getDict('r_repair_pool', 'maintenance_type')
  184 + this.myRepairDispatchInfo.maintenanceTypes = maintenanceTypeData
  185 + } catch (error) {
  186 + console.error('获取字典数据失败:', error)
  187 + }
  188 + },
  189 +
  190 + async _listOwnerRepairs(page, size) {
  191 + try {
  192 + this.myRepairDispatchInfo.conditions.page = page
  193 + this.myRepairDispatchInfo.conditions.row = size
  194 +
  195 + const params = {
  196 + ...this.myRepairDispatchInfo.conditions,
  197 + repairId: this.myRepairDispatchInfo.conditions.repairId.trim(),
  198 + repairName: this.myRepairDispatchInfo.conditions.repairName.trim(),
  199 + tel: this.myRepairDispatchInfo.conditions.tel.trim()
  200 + }
  201 +
  202 + const res = await listStaffFinishRepairs(params)
  203 + this.myRepairDispatchInfo.ownerRepairs = res.data
  204 + this.pagination.total = res.total
  205 + this.pagination.current = page
  206 + } catch (error) {
  207 + console.error('获取报修列表失败:', error)
  208 + }
  209 + },
  210 +
  211 + async _listRepairTypes() {
  212 + try {
  213 + const params = {
  214 + page: 1,
  215 + row: 100,
  216 + communityId: this.getCommunityId()
  217 + }
  218 +
  219 + const res = await listRepairSettings(params)
  220 + this.myRepairDispatchInfo.repairTypes = res.data
  221 + } catch (error) {
  222 + console.error('获取报修类型失败:', error)
  223 + }
  224 + },
  225 +
  226 + _moreCondition() {
  227 + this.myRepairDispatchInfo.moreCondition = !this.myRepairDispatchInfo.moreCondition
  228 + },
  229 +
  230 + _openRepairDetail(repairPool) {
  231 + this.$router.push({
  232 + path: '/views/work/repairDetail',
  233 + query: { repairId: repairPool.repairId }
  234 + })
  235 + },
  236 +
  237 + _openDealRepair(ownerRepair) {
  238 + this.myRepairDispatchInfo.currentRepairId = ownerRepair.repairId
  239 + this.$refs.closeOrderModal.open()
  240 + },
  241 +
  242 + async handleCloseOrderSuccess(orderInfo) {
  243 + try {
  244 + const params = {
  245 + repairId: this.myRepairDispatchInfo.currentRepairId,
  246 + context: orderInfo.remark,
  247 + communityId: this.$store.getters.communityId,
  248 + state: orderInfo.state === '1100' ? '10002' : '10003'
  249 + }
  250 +
  251 + await closeRepairDispatch(params)
  252 + this.$message.success(this.$t('common.operateSuccess'))
  253 + this._listOwnerRepairs(this.pagination.current, this.pagination.size)
  254 + } catch (error) {
  255 + console.error('结单操作失败:', error)
  256 + }
  257 + },
  258 +
  259 + _queryMyRepairDispatchMethod() {
  260 + this._listOwnerRepairs(1, this.pagination.size)
  261 + },
  262 +
  263 + _resetMyRepairDispatchMethod() {
  264 + this.myRepairDispatchInfo.conditions = {
  265 + ...this.myRepairDispatchInfo.conditions,
  266 + repairId: '',
  267 + repairName: '',
  268 + tel: '',
  269 + repairType: '',
  270 + state: '',
  271 + maintenanceType: ''
  272 + }
  273 + this._listOwnerRepairs(1, this.pagination.size)
  274 + },
  275 +
  276 + getMaintenanceTypeName(type) {
  277 + const mapping = {
  278 + '1001': this.$t('myRepairDispatchManage.paidService'),
  279 + '1002': this.$t('myRepairDispatchManage.freeService'),
  280 + '1003': this.$t('myRepairDispatchManage.needMaterial'),
  281 + '1004': this.$t('myRepairDispatchManage.noMaterial')
  282 + }
  283 + return mapping[type] || '--'
  284 + },
  285 +
  286 + handleSizeChange(size) {
  287 + this.pagination.size = size
  288 + this._listOwnerRepairs(1, size)
  289 + },
  290 +
  291 + handleCurrentChange(page) {
  292 + this._listOwnerRepairs(page, this.pagination.size)
  293 + }
  294 + }
  295 +}
  296 +</script>
  297 +
  298 +<style scoped>
  299 +.ibox-content {
  300 + padding: 15px 20px 20px 20px;
  301 +}
  302 +
  303 +.ibox-tools {
  304 + position: absolute;
  305 + right: 15px;
  306 + top: 15px;
  307 +}
  308 +</style>
0 309 \ No newline at end of file
... ...
src/views/work/ownerRepairManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerRepairManage: {
  4 + queryCondition: 'Query Condition',
  5 + phoneRepair: 'Phone Repair',
  6 + register: 'Register',
  7 + placeholder: {
  8 + repairId: 'Please input repair id',
  9 + repairName: 'Please input repair name',
  10 + tel: 'Please input tel',
  11 + repairType: 'Please select repair type',
  12 + state: 'Please select state'
  13 + },
  14 + table: {
  15 + repairId: 'Repair Id',
  16 + location: 'Location',
  17 + repairType: 'Repair Type',
  18 + repairName: 'Repair Name',
  19 + tel: 'Tel',
  20 + appointmentTime: 'Appointment Time',
  21 + timeout: 'Timeout',
  22 + createTime: 'Create Time',
  23 + state: 'State',
  24 + operation: 'Operation',
  25 + scheduledTask: '(Scheduled Task)'
  26 + },
  27 + tip1: 'Note: Before using this function, please go to Repair Management;',
  28 + tip2: 'For general owner housing repairs, we must add a non-public area type to report repairs normally.',
  29 +
  30 + },
  31 + addOwnerRepair: {
  32 + title: 'Repair Registration',
  33 + repairScope: 'Repair Scope',
  34 + belongBuilding: 'Belong Building',
  35 + belongUnit: 'Belong Unit',
  36 + belongRoom: 'Belong Room',
  37 + repairType: 'Repair Type',
  38 + repairName: 'Repair Name',
  39 + tel: 'Contact',
  40 + appointmentTime: 'Appointment Time',
  41 + context: 'Repair Content',
  42 + placeholder: {
  43 + appointmentTime: 'Please select appointment time'
  44 + },
  45 + community: 'Community',
  46 + building: 'Building',
  47 + unit: 'Unit',
  48 + room: 'Room',
  49 + buildingSuffix: ' Building',
  50 + unitSuffix: ' Unit',
  51 + roomSuffix: ' Room'
  52 + },
  53 + editOwnerRepair: {
  54 + title: 'Edit Owner Repair',
  55 + repairType: 'Repair Type',
  56 + repairName: 'Repair Name',
  57 + tel: 'Contact',
  58 + appointmentTime: 'Appointment Time',
  59 + context: 'Repair Content',
  60 + placeholder: {
  61 + appointmentTime: 'Please select appointment time'
  62 + }
  63 + },
  64 + deleteOwnerRepair: {
  65 + title: 'Confirm Operation',
  66 + confirmText: 'Are you sure to delete this repair record?'
  67 + },
  68 + },
  69 + zh: {
  70 + ownerRepairManage: {
  71 + queryCondition: '查询条件',
  72 + phoneRepair: '电话报修',
  73 + register: '登记',
  74 + placeholder: {
  75 + repairId: '请输入工单编号',
  76 + repairName: '请输入报修人',
  77 + tel: '请输入报修电话',
  78 + repairType: '请选择报修类型',
  79 + state: '请选择报修状态'
  80 + },
  81 + table: {
  82 + repairId: '工单编号',
  83 + location: '位置',
  84 + repairType: '报修类型',
  85 + repairName: '报修人',
  86 + tel: '联系方式',
  87 + appointmentTime: '预约时间',
  88 + timeout: '超时时间',
  89 + createTime: '提交时间',
  90 + state: '状态',
  91 + operation: '操作',
  92 + scheduledTask: '(定时任务处理)'
  93 + },
  94 + tip1: '注意:此功能使用前 请先到 报修管理;',
  95 + tip2: '一般业主房屋报修 我们必须要添加一个非公共区域的类型才能正常报修'
  96 + },
  97 + addOwnerRepair: {
  98 + title: '报修登记',
  99 + repairScope: '报修范围',
  100 + belongBuilding: '归属楼栋',
  101 + belongUnit: '归属单元',
  102 + belongRoom: '归属房屋',
  103 + repairType: '报修类型',
  104 + repairName: '报修人',
  105 + tel: '联系方式',
  106 + appointmentTime: '预约时间',
  107 + context: '报修内容',
  108 + placeholder: {
  109 + appointmentTime: '请选择预约时间'
  110 + },
  111 + community: '小区',
  112 + building: '楼栋',
  113 + unit: '单元',
  114 + room: '房屋',
  115 + buildingSuffix: '栋',
  116 + unitSuffix: '单元',
  117 + roomSuffix: '室'
  118 + },
  119 + editOwnerRepair: {
  120 + title: '修改业主报修',
  121 + repairType: '报修类型',
  122 + repairName: '报修人',
  123 + tel: '联系方式',
  124 + appointmentTime: '预约时间',
  125 + context: '报修内容',
  126 + placeholder: {
  127 + appointmentTime: '请选择预约时间'
  128 + }
  129 + },
  130 + deleteOwnerRepair: {
  131 + title: '请确认您的操作',
  132 + confirmText: '确定删除业主报修?'
  133 + },
  134 + }
  135 +}
0 136 \ No newline at end of file
... ...
src/views/work/ownerRepairManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="animated fadeInRight">
  3 + <el-card shadow="hover">
  4 + <div slot="header" class="flex justify-between">
  5 + <span>{{ $t('ownerRepairManage.queryCondition') }}</span>
  6 + </div>
  7 + <div class="search-content">
  8 + <el-row :gutter="20">
  9 + <el-col :span="4">
  10 + <el-input v-model.trim="ownerRepairManageInfo.conditions.repairId"
  11 + :placeholder="$t('ownerRepairManage.placeholder.repairId')" clearable />
  12 + </el-col>
  13 + <el-col :span="4">
  14 + <el-input v-model.trim="ownerRepairManageInfo.conditions.repairName"
  15 + :placeholder="$t('ownerRepairManage.placeholder.repairName')" clearable />
  16 + </el-col>
  17 + <el-col :span="4">
  18 + <el-input v-model.trim="ownerRepairManageInfo.conditions.tel"
  19 + :placeholder="$t('ownerRepairManage.placeholder.tel')" clearable />
  20 + </el-col>
  21 + <el-col :span="4">
  22 + <el-select v-model="ownerRepairManageInfo.conditions.repairType"
  23 + :placeholder="$t('ownerRepairManage.placeholder.repairType')" style="width:100%" clearable>
  24 + <el-option v-for="(item, index) in ownerRepairManageInfo.repairTypes" :key="index"
  25 + :label="item.repairTypeName" :value="item.repairType" />
  26 + </el-select>
  27 + </el-col>
  28 + <el-col :span="4">
  29 + <el-select v-model="ownerRepairManageInfo.conditions.state"
  30 + :placeholder="$t('ownerRepairManage.placeholder.state')" style="width:100%" clearable>
  31 + <el-option v-for="(item, index) in ownerRepairManageInfo.states" :key="index" :label="item.name"
  32 + :value="item.statusCd" />
  33 + </el-select>
  34 + </el-col>
  35 + <el-col :span="4">
  36 + <el-button type="primary" icon="el-icon-search" @click="_queryOwnerRepairMethod">{{ $t('common.search')
  37 + }}</el-button>
  38 + <el-button type="info" icon="el-icon-refresh" @click="_resetOwnerRepairMethod" style="margin-left: 20px">{{
  39 + $t('common.reset') }}</el-button>
  40 + </el-col>
  41 + </el-row>
  42 + </div>
  43 + </el-card>
  44 +
  45 + <el-card shadow="hover" style="margin-top: 20px">
  46 + <div slot="header" class="flex justify-between">
  47 + <span>{{ $t('ownerRepairManage.phoneRepair') }}</span>
  48 + <el-button v-if="ownerRepairManageInfo.conditions.roomId != ''" size="small" type="primary" icon="el-icon-plus"
  49 + style="float:right" @click="_openAddOwnerRepairModal">{{ $t('ownerRepairManage.register') }}</el-button>
  50 + </div>
  51 + <el-table :data="ownerRepairManageInfo.ownerRepairs" border style="width: 100%">
  52 + <el-table-column prop="repairId" :label="$t('ownerRepairManage.table.repairId')" align="center" />
  53 + <el-table-column prop="repairObjName" :label="$t('ownerRepairManage.table.location')" align="center" />
  54 + <el-table-column prop="repairTypeName" :label="$t('ownerRepairManage.table.repairType')" align="center" />
  55 + <el-table-column prop="repairName" :label="$t('ownerRepairManage.table.repairName')" align="center" />
  56 + <el-table-column prop="tel" :label="$t('ownerRepairManage.table.tel')" align="center" />
  57 + <el-table-column prop="appointmentTime" :label="$t('ownerRepairManage.table.appointmentTime')" align="center" />
  58 + <el-table-column prop="timeout" :label="$t('ownerRepairManage.table.timeout')" align="center" />
  59 + <el-table-column prop="createTime" :label="$t('ownerRepairManage.table.createTime')" align="center" />
  60 + <el-table-column :label="$t('ownerRepairManage.table.state')" align="center">
  61 + <template slot-scope="scope">
  62 + <span
  63 + v-if="scope.row.state == '1800' && (scope.row.returnVisitFlag == '001' || scope.row.returnVisitFlag == '002')">
  64 + {{ scope.row.stateName }}{{ $t('ownerRepairManage.table.scheduledTask') }}
  65 + </span>
  66 + <span v-else>{{ scope.row.stateName }}</span>
  67 + </template>
  68 + </el-table-column>
  69 + <el-table-column :label="$t('common.operation')" align="center" fixed="right" width="200">
  70 + <template slot-scope="scope">
  71 + <el-button
  72 + v-if="hasPrivilege('502021012067300023') && (scope.row.state == '1000' || scope.row.state == '1200')"
  73 + size="mini" type="primary" @click="_openEditOwnerRepairModel(scope.row)">{{ $t('common.edit') }}</el-button>
  74 + <el-button
  75 + v-if="hasPrivilege('502021012051410024') && (scope.row.state == '1000' || scope.row.state == '1200')"
  76 + size="mini" type="danger" @click="_openDeleteOwnerRepairModel(scope.row)">{{ $t('common.delete')
  77 + }}</el-button>
  78 + </template>
  79 + </el-table-column>
  80 + </el-table>
  81 + <!-- 分页 -->
  82 + <div style="margin-top: 20px">
  83 + <el-row>
  84 + <el-col :span="18" class="text-left">
  85 + <div>
  86 + {{ $t('ownerRepairManage.tip1') }}
  87 + </div>
  88 + <div>
  89 + {{ $t('ownerRepairManage.tip2') }}
  90 + </div>
  91 + </el-col>
  92 + <el-col :span="6">
  93 + <el-pagination :current-page="ownerRepairManageInfo.page" :page-sizes="[10, 20, 30, 50]"
  94 + :page-size="ownerRepairManageInfo.rows" layout="total, sizes, prev, pager, next, jumper"
  95 + :total="ownerRepairManageInfo.total" @size-change="handleSizeChange"
  96 + @current-change="handleCurrentChange" />
  97 + </el-col>
  98 + </el-row>
  99 + </div>
  100 + </el-card>
  101 +
  102 + <!-- 添加报修模态框 -->
  103 + <add-owner-repair ref="addOwnerRepair" @success="_queryOwnerRepairMethod" />
  104 + <!-- 修改报修模态框 -->
  105 + <edit-owner-repair ref="editOwnerRepair" @success="_queryOwnerRepairMethod" />
  106 + <!-- 删除报修模态框 -->
  107 + <delete-owner-repair ref="deleteOwnerRepair" @success="_queryOwnerRepairMethod" />
  108 + </div>
  109 +</template>
  110 +
  111 +<script>
  112 +import * as ownerRepairManageApi from '@/api/work/ownerRepairManageApi'
  113 +import AddOwnerRepair from '@/components/work/addOwnerRepair'
  114 +import EditOwnerRepair from '@/components/work/editOwnerRepair'
  115 +import DeleteOwnerRepair from '@/components/work/deleteOwnerRepair'
  116 +import { getDict } from '@/api/community/communityApi'
  117 +
  118 +export default {
  119 + name: 'OwnerRepairManageList',
  120 + components: {
  121 + AddOwnerRepair,
  122 + EditOwnerRepair,
  123 + DeleteOwnerRepair
  124 + },
  125 + data() {
  126 + return {
  127 + ownerRepairManageInfo: {
  128 + ownerRepairs: [],
  129 + total: 0,
  130 + page: 1,
  131 + rows: 10,
  132 + moreCondition: false,
  133 + repairTypes: [],
  134 + states: [],
  135 + conditions: {
  136 + repairId: '',
  137 + repairName: '',
  138 + tel: '',
  139 + repairType: '',
  140 + state: '',
  141 + reqSource: 'pc_mobile'
  142 + }
  143 + }
  144 + }
  145 + },
  146 + created() {
  147 + this._listOwnerRepairs(1, this.ownerRepairManageInfo.rows)
  148 + this._listRepairTypes(1, 50)
  149 + this._loadStates()
  150 + },
  151 + methods: {
  152 + _loadStates() {
  153 + getDict('r_repair_pool', 'state').then(data => {
  154 + this.ownerRepairManageInfo.states = data
  155 + })
  156 + },
  157 + async _listRepairTypes(page, rows) {
  158 + const param = {
  159 + page: page,
  160 + row: rows,
  161 + communityId: this.getCommunityId()
  162 + }
  163 + const { data } = await ownerRepairManageApi.listRepairSettings(param)
  164 + this.ownerRepairManageInfo.repairTypes = data
  165 +
  166 + },
  167 + _listOwnerRepairs(page, rows) {
  168 + this.ownerRepairManageInfo.conditions.page = page
  169 + this.ownerRepairManageInfo.conditions.row = rows
  170 + this.ownerRepairManageInfo.conditions.communityId = this.getCommunityId()
  171 + ownerRepairManageApi.listOwnerRepairs(this.ownerRepairManageInfo.conditions).then(res => {
  172 + if (res.code === 0) {
  173 + this.ownerRepairManageInfo.ownerRepairs = res.data
  174 + this.ownerRepairManageInfo.total = res.total
  175 + this.ownerRepairManageInfo.page = page
  176 + this.ownerRepairManageInfo.rows = rows
  177 + }
  178 + })
  179 + },
  180 + _resetListOwnerRepairs() {
  181 + this.ownerRepairManageInfo.conditions = {
  182 + repairId: '',
  183 + repairName: '',
  184 + tel: '',
  185 + repairType: '',
  186 + state: '',
  187 + reqSource: 'pc_mobile'
  188 + }
  189 + this._listOwnerRepairs(1, this.ownerRepairManageInfo.rows)
  190 + },
  191 + _openAddOwnerRepairModal() {
  192 + this.$refs.addOwnerRepair.open()
  193 + },
  194 + _openEditOwnerRepairModel(row) {
  195 + this.$refs.editOwnerRepair.open(row)
  196 + },
  197 + _openDeleteOwnerRepairModel(row) {
  198 + this.$refs.deleteOwnerRepair.open(row)
  199 + },
  200 + _queryOwnerRepairMethod() {
  201 + this._listOwnerRepairs(1, this.ownerRepairManageInfo.rows)
  202 + },
  203 + _resetOwnerRepairMethod() {
  204 + this._resetListOwnerRepairs()
  205 + },
  206 + handleSizeChange(val) {
  207 + this.ownerRepairManageInfo.rows = val
  208 + this._listOwnerRepairs(this.ownerRepairManageInfo.page, val)
  209 + },
  210 + handleCurrentChange(val) {
  211 + this.ownerRepairManageInfo.page = val
  212 + this._listOwnerRepairs(val, this.ownerRepairManageInfo.rows)
  213 + }
  214 + }
  215 +}
  216 +</script>
  217 +
  218 +<style lang="scss" scoped>
  219 +.animated {
  220 + padding: 20px;
  221 +}
  222 +
  223 +.search-content {
  224 + padding: 20px;
  225 +}
  226 +</style>
0 227 \ No newline at end of file
... ...
src/views/work/repairDetailLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairDetail: {
  4 + title: 'Work Order Details',
  5 + print: 'Print',
  6 + back: 'Back',
  7 + orderCode: 'Work Order Code:',
  8 + repairType: 'Repair Type:',
  9 + repairer: 'Repairer:',
  10 + contact: 'Contact:',
  11 + location: 'Location:',
  12 + appointmentStart: 'Appointment Start:',
  13 + appointmentEnd: 'Appointment End:',
  14 + submitDuration: 'Submission Duration:',
  15 + finishTime: 'Completion Time:',
  16 + status: 'Status:',
  17 + content: 'Content:',
  18 + maintenanceType: 'Maintenance Type:',
  19 + materials: 'Materials:',
  20 + costDetail: 'Cost Details:',
  21 + yuan: 'Yuan (Unit Price * Quantity)',
  22 + avgScore: 'Average Score:',
  23 + comprehensiveScore: 'Comprehensive Score:',
  24 + doorSpeedScore: 'Door Speed Score:',
  25 + serviceScore: 'Service Score:',
  26 + points: 'Points',
  27 + visitSatisfaction: 'Visit Satisfaction:',
  28 + visitContent: 'Visit Content:',
  29 + orderPhotos: 'Order Photos',
  30 + orderFlow: 'Order Flow',
  31 + orderEvents: 'Order Events',
  32 + repairItems: 'Repair Items',
  33 + paidService: 'Paid Service',
  34 + freeService: 'Free Service',
  35 + needMaterials: 'Need Materials',
  36 + noMaterials: 'No Materials'
  37 + },
  38 + repairDetailResource: {
  39 + itemCode: 'Item Code',
  40 + itemType: 'Item Type',
  41 + itemName: 'Item Name',
  42 + specification: 'Specification',
  43 + quantity: 'Quantity',
  44 + price: 'Price',
  45 + user: 'User',
  46 + time: 'Time'
  47 + },
  48 + repairDetailUser: {
  49 + serial: 'Serial',
  50 + handler: 'Handler',
  51 + status: 'Status',
  52 + startTime: 'Start Time',
  53 + endTime: 'End Time',
  54 + duration: 'Duration',
  55 + opinion: 'Opinion',
  56 + reply: 'Reply'
  57 + },
  58 + repairDetailEvent: {
  59 + eventType: 'Event Type',
  60 + staff: 'Staff',
  61 + description: 'Description',
  62 + createTime: 'Create Time'
  63 + },
  64 + replyRepairAppraise: {
  65 + title: 'Reply Evaluation',
  66 + content: 'Content',
  67 + submit: 'Submit',
  68 + cancel: 'Cancel',
  69 + placeholder: 'Required, please fill in reply content'
  70 + }
  71 + },
  72 + zh: {
  73 + repairDetail: {
  74 + title: '工单详情',
  75 + print: '打印',
  76 + back: '返回',
  77 + orderCode: '工单编码:',
  78 + repairType: '报修类型:',
  79 + repairer: '报修人:',
  80 + contact: '联系方式:',
  81 + location: '位置:',
  82 + appointmentStart: '预约开始时间:',
  83 + appointmentEnd: '预约结束时间:',
  84 + submitDuration: '提单时长:',
  85 + finishTime: '完成时间:',
  86 + status: '状态:',
  87 + content: '报修内容:',
  88 + maintenanceType: '维修类型:',
  89 + materials: '用料:',
  90 + costDetail: '费用明细:',
  91 + yuan: '元(单价*数量)',
  92 + avgScore: '平均分:',
  93 + comprehensiveScore: '综合评价得分:',
  94 + doorSpeedScore: '上门速度评分:',
  95 + serviceScore: '维修员服务评分:',
  96 + points: '分',
  97 + visitSatisfaction: '回访满意度:',
  98 + visitContent: '回访内容:',
  99 + orderPhotos: '工单图片',
  100 + orderFlow: '工单流转',
  101 + orderEvents: '工单事件',
  102 + repairItems: '维修物品',
  103 + paidService: '有偿服务',
  104 + freeService: '无偿服务',
  105 + needMaterials: '需要用料',
  106 + noMaterials: '无需用料'
  107 + },
  108 + repairDetailResource: {
  109 + itemCode: '物品资源编号',
  110 + itemType: '物品资源类型',
  111 + itemName: '物品资源名称',
  112 + specification: '物品资源规格',
  113 + quantity: '物品使用数量',
  114 + price: '物品价格',
  115 + user: '使用人',
  116 + time: '时间'
  117 + },
  118 + repairDetailUser: {
  119 + serial: '序号',
  120 + handler: '处理人',
  121 + status: '状态',
  122 + startTime: '处理开始时间',
  123 + endTime: '处理结束时间',
  124 + duration: '耗时',
  125 + opinion: '意见',
  126 + reply: '回复'
  127 + },
  128 + repairDetailEvent: {
  129 + eventType: '事件类型',
  130 + staff: '员工',
  131 + description: '事件说明',
  132 + createTime: '创建时间'
  133 + },
  134 + replyRepairAppraise: {
  135 + title: '回复评价',
  136 + content: '内容',
  137 + submit: '提交',
  138 + cancel: '取消',
  139 + placeholder: '必填,请填写回复内容'
  140 + }
  141 + }
  142 +}
0 143 \ No newline at end of file
... ...
src/views/work/repairDetailList.vue 0 → 100644
  1 +<template>
  2 + <el-card class="repair-detail-container">
  3 + <div class="flex justify-between">
  4 + <div class="text-title">{{ $t('repairDetail.title') }}</div>
  5 + <div>
  6 + <el-button type="primary" size="small" @click="printRepairDetail">
  7 + {{ $t('repairDetail.print') }}
  8 + </el-button>
  9 + <el-button type="primary" size="small" @click="goBack">
  10 + {{ $t('repairDetail.back') }}
  11 + </el-button>
  12 + </div>
  13 + </div>
  14 +
  15 + <div class="margin-top">
  16 + <el-form :model="repairDetailInfo" label-width="auto" class="text-left">
  17 + <el-row :gutter="20">
  18 + <el-col :sm="8" :xs="24">
  19 + <el-form-item :label="$t('repairDetail.orderCode')">
  20 + <span>{{ repairDetailInfo.repairId }}</span>
  21 + </el-form-item>
  22 + </el-col>
  23 + <el-col :sm="8" :xs="24">
  24 + <el-form-item :label="$t('repairDetail.repairType')">
  25 + <span>{{ repairDetailInfo.repairTypeName }}</span>
  26 + </el-form-item>
  27 + </el-col>
  28 + <el-col :sm="8" :xs="24">
  29 + <el-form-item :label="$t('repairDetail.repairer')">
  30 + <span>{{ repairDetailInfo.repairName }}</span>
  31 + </el-form-item>
  32 + </el-col>
  33 +
  34 + <el-col :sm="8" :xs="24">
  35 + <el-form-item :label="$t('repairDetail.contact')">
  36 + <span>{{ repairDetailInfo.tel }}</span>
  37 + </el-form-item>
  38 + </el-col>
  39 + <el-col :sm="8" :xs="24">
  40 + <el-form-item :label="$t('repairDetail.location')">
  41 + <span>{{ repairDetailInfo.repairObjName }}</span>
  42 + </el-form-item>
  43 + </el-col>
  44 + <el-col :sm="8" :xs="24">
  45 + <el-form-item :label="$t('repairDetail.appointmentStart')">
  46 + <span>{{ repairDetailInfo.appointmentTime }}</span>
  47 + </el-form-item>
  48 + </el-col>
  49 + <el-col :sm="8" :xs="24">
  50 + <el-form-item :label="$t('repairDetail.appointmentEnd')">
  51 + <span>{{ repairDetailInfo.timeout }}</span>
  52 + </el-form-item>
  53 + </el-col>
  54 + <el-col :sm="8" :xs="24">
  55 + <el-form-item :label="$t('repairDetail.submitDuration')">
  56 + <span>{{ repairDetailInfo.submitHours || '0' }}</span>
  57 + </el-form-item>
  58 + </el-col>
  59 + <el-col :sm="8" :xs="24">
  60 + <el-form-item :label="$t('repairDetail.finishTime')">
  61 + <span>{{ repairDetailInfo.finishTime || '-' }}</span>
  62 + </el-form-item>
  63 + </el-col>
  64 + <el-col :sm="8" :xs="24">
  65 + <el-form-item :label="$t('repairDetail.status')">
  66 + <span>{{ repairDetailInfo.stateName }}</span>
  67 + </el-form-item>
  68 + </el-col>
  69 + <el-col :sm="8" :xs="24">
  70 + <el-form-item :label="$t('repairDetail.content')">
  71 + <span>{{ repairDetailInfo.context }}</span>
  72 + </el-form-item>
  73 + </el-col>
  74 + <el-col v-if="repairDetailInfo.maintenanceType" :sm="8" :xs="24">
  75 + <el-form-item :label="$t('repairDetail.maintenanceType')">
  76 + <span>
  77 + <template v-if="repairDetailInfo.maintenanceType === '1001'">
  78 + {{ $t('repairDetail.paidService') }}
  79 + </template>
  80 + <template v-else-if="repairDetailInfo.maintenanceType === '1002'">
  81 + {{ $t('repairDetail.freeService') }}
  82 + </template>
  83 + <template v-else-if="repairDetailInfo.maintenanceType === '1003'">
  84 + {{ $t('repairDetail.needMaterials') }}
  85 + </template>
  86 + <template v-else-if="repairDetailInfo.maintenanceType === '1004'">
  87 + {{ $t('repairDetail.noMaterials') }}
  88 + </template>
  89 + </span>
  90 + </el-form-item>
  91 + </el-col>
  92 +
  93 + <el-col v-if="repairDetailInfo.maintenanceType === '1001' || repairDetailInfo.maintenanceType === '1003'" :sm="8"
  94 + :xs="24">
  95 + <el-form-item :label="$t('repairDetail.materials')">
  96 + <span>{{ repairDetailInfo.repairMaterials }}</span>
  97 + </el-form-item>
  98 + </el-col>
  99 + <el-col v-if="repairDetailInfo.maintenanceType === '1001'" :sm="8" :xs="24">
  100 + <el-form-item :label="$t('repairDetail.costDetail')">
  101 + <span>
  102 + {{ repairDetailInfo.repairFee }}
  103 + <span>{{ $t('repairDetail.yuan') }}</span>
  104 + </span>
  105 + </el-form-item>
  106 + </el-col>
  107 + <el-col v-if="repairDetailInfo.appraiseScore !== '0'" :sm="8" :xs="24">
  108 + <el-form-item :label="$t('repairDetail.comprehensiveScore')">
  109 + <span>
  110 + {{ repairDetailInfo.appraiseScore }}
  111 + <span>{{ $t('repairDetail.points') }}</span>
  112 + </span>
  113 + </el-form-item>
  114 + </el-col>
  115 +
  116 + <el-col v-if="repairDetailInfo.doorSpeedScore !== '0'" :sm="8" :xs="24">
  117 + <el-form-item :label="$t('repairDetail.doorSpeedScore')">
  118 + <span>
  119 + {{ repairDetailInfo.doorSpeedScore }}
  120 + <span>{{ $t('repairDetail.points') }}</span>
  121 + </span>
  122 + </el-form-item>
  123 + </el-col>
  124 + <el-col v-if="repairDetailInfo.repairmanServiceScore !== '0'" :sm="8" :xs="24">
  125 + <el-form-item :label="$t('repairDetail.serviceScore')">
  126 + <span>
  127 + {{ repairDetailInfo.repairmanServiceScore }}
  128 + <span>{{ $t('repairDetail.points') }}</span>
  129 + </span>
  130 + </el-form-item>
  131 + </el-col>
  132 + <el-col v-if="repairDetailInfo.average !== '0.0'" :sm="8" :xs="24">
  133 + <el-form-item :label="$t('repairDetail.avgScore')">
  134 + <span>
  135 + {{ repairDetailInfo.average }}
  136 + {{ $t('repairDetail.points') }}
  137 + </span>
  138 + </el-form-item>
  139 + </el-col>
  140 + </el-row>
  141 +
  142 + <el-row v-if="repairDetailInfo.visitType" :gutter="20">
  143 + <el-col :sm="8" :xs="24">
  144 + <el-form-item :label="$t('repairDetail.visitSatisfaction')">
  145 + <span>{{ repairDetailInfo.visitType === '1001' ? $t('repairDetail.satisfied') :
  146 + $t('repairDetail.notSatisfied') }}</span>
  147 + </el-form-item>
  148 + </el-col>
  149 + <el-col :sm="8" :xs="24">
  150 + <el-form-item :label="$t('repairDetail.visitContent')">
  151 + <span>{{ repairDetailInfo.visitContext }}</span>
  152 + </el-form-item>
  153 + </el-col>
  154 + </el-row>
  155 + </el-form>
  156 + </div>
  157 +
  158 + <divider></divider>
  159 +
  160 + <div class="margin-top-sm">
  161 + <el-tabs v-model="currentTab" @tab-click="changeTab(currentTab)">
  162 + <el-tab-pane :label="$t('repairDetail.orderPhotos')" name="repairDetailPhotos"></el-tab-pane>
  163 + <el-tab-pane :label="$t('repairDetail.repairItems')" name="repairDetailResource"></el-tab-pane>
  164 + <el-tab-pane :label="$t('repairDetail.orderFlow')" name="repairDetailUser"></el-tab-pane>
  165 + <el-tab-pane :label="$t('repairDetail.orderEvents')" name="repairDetailEvent"></el-tab-pane>
  166 + </el-tabs>
  167 + </div>
  168 +
  169 + <div v-if="currentTab === 'repairDetailPhotos'">
  170 + <repair-detail-photos ref="repairDetailPhotos" :repair-id="repairDetailInfo.repairId"></repair-detail-photos>
  171 + </div>
  172 + <div v-if="currentTab === 'repairDetailResource'">
  173 + <repair-detail-resource ref="repairDetailResource" :repair-id="repairDetailInfo.repairId"></repair-detail-resource>
  174 + </div>
  175 + <div v-if="currentTab === 'repairDetailUser'">
  176 + <repair-detail-user ref="repairDetailUser" :repair-id="repairDetailInfo.repairId"></repair-detail-user>
  177 + </div>
  178 + <div v-if="currentTab === 'repairDetailEvent'">
  179 + <repair-detail-event ref="repairDetailEvent" :repair-id="repairDetailInfo.repairId"></repair-detail-event>
  180 + </div>
  181 +
  182 + <view-image ref="viewImage"></view-image>
  183 + <reply-repair-appraise ref="replyAppraise"></reply-repair-appraise>
  184 + </el-card>
  185 +</template>
  186 +
  187 +<script>
  188 +import { getRepairDetail } from '@/api/work/repairDetailApi'
  189 +import RepairDetailPhotos from '@/components/work/repairDetailPhotos'
  190 +import RepairDetailResource from '@/components/work/repairDetailResource'
  191 +import RepairDetailUser from '@/components/work/repairDetailUser'
  192 +import RepairDetailEvent from '@/components/work/repairDetailEvent'
  193 +import ViewImage from '@/components/work/viewImage'
  194 +import ReplyRepairAppraise from '@/components/work/ReplyRepairAppraise'
  195 +import divider from '@/components/system/divider'
  196 +
  197 +export default {
  198 + name: 'RepairDetailList',
  199 + components: {
  200 + RepairDetailPhotos,
  201 + RepairDetailResource,
  202 + RepairDetailUser,
  203 + RepairDetailEvent,
  204 + ViewImage,
  205 + ReplyRepairAppraise,
  206 + divider
  207 + },
  208 + data() {
  209 + return {
  210 + currentTab: 'repairDetailPhotos',
  211 + repairDetailInfo: {
  212 + repairId: '',
  213 + repairType: '',
  214 + repairTypeName: '',
  215 + repairName: '',
  216 + tel: '',
  217 + roomId: '',
  218 + roomName: '',
  219 + repairObjName: '',
  220 + appointmentTime: '',
  221 + submitHours: '',
  222 + timeout: '',
  223 + finishTime: '',
  224 + context: '',
  225 + stateName: '',
  226 + userId: '',
  227 + userName: '',
  228 + photos: [],
  229 + visitType: '',
  230 + visitContext: '',
  231 + maintenanceType: '',
  232 + repairMaterials: '',
  233 + repairFee: '',
  234 + appraiseScore: 0,
  235 + doorSpeedScore: 0,
  236 + repairmanServiceScore: 0,
  237 + average: 0.0
  238 + }
  239 + }
  240 + },
  241 + created() {
  242 + const repairId = this.$route.query.repairId
  243 + this.repairDetailInfo.repairId = repairId
  244 + this.loadRepairDetail()
  245 + },
  246 + methods: {
  247 + async loadRepairDetail() {
  248 + try {
  249 + const data = await getRepairDetail(this.repairDetailInfo.repairId)
  250 + Object.assign(this.repairDetailInfo, data)
  251 + } catch (error) {
  252 + this.$message.error(error.message)
  253 + }
  254 + },
  255 + goBack() {
  256 + this.$router.go(-1)
  257 + },
  258 + printRepairDetail() {
  259 + window.open(`/print.html#/pages/property/printRepairDetail?repairId=${this.repairDetailInfo.repairId}&repairType=${this.repairDetailInfo.repairType}`)
  260 + },
  261 + changeTab(tab) {
  262 + this.currentTab = tab
  263 + setTimeout(() => {
  264 + if (this.$refs[`${tab}`]) {
  265 + this.$refs[`${tab}`].loadData()
  266 + }
  267 + },500)
  268 + }
  269 + }
  270 +}
  271 +</script>
  272 +
  273 +<style scoped>
  274 +.repair-detail-container {
  275 + padding: 20px;
  276 +}
  277 +
  278 +.text-title {
  279 + font-size: 18px;
  280 + font-weight: bold;
  281 + margin-bottom: 20px;
  282 +}
  283 +
  284 +.margin-top {
  285 + margin-top: 20px;
  286 +}
  287 +
  288 +.margin-top-sm {
  289 + margin-top: 10px;
  290 +}
  291 +
  292 +.flex {
  293 + display: flex;
  294 +}
  295 +
  296 +.justify-between {
  297 + justify-content: space-between;
  298 +}
  299 +
  300 +.el-divider {
  301 + margin: 20px 0;
  302 +}
  303 +
  304 +.el-form-item {
  305 + margin-bottom: 15px;
  306 +}
  307 +</style>
0 308 \ No newline at end of file
... ...
src/views/work/repairDispatchManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairDispatchManage: {
  4 + searchConditions: 'Search Conditions',
  5 + repairBacklog: 'Repair Backlog',
  6 + placeholder: {
  7 + repairId: 'Please enter work order number',
  8 + repairName: 'Please enter reporter name',
  9 + tel: 'Please enter reporter phone',
  10 + selectRepairType: 'Please select repair type',
  11 + selectStatus: 'Please select status'
  12 + },
  13 + table: {
  14 + location: 'Location',
  15 + repairType: 'Repair Type',
  16 + repairPerson: 'Reporter',
  17 + repairPhone: 'Reporter Phone',
  18 + appointmentTime: 'Appointment Time',
  19 + status: 'Status',
  20 + operation: 'Operation'
  21 + },
  22 + transferOrder: 'Transfer Order',
  23 + returnOrder: 'Return Order',
  24 + complete: 'Complete',
  25 + returnVisit: 'Return Visit',
  26 + pause: 'Pause',
  27 + start: 'Start',
  28 + detail: 'Detail',
  29 + scheduledTask: 'Scheduled Task',
  30 + dispatchRepair: 'Dispatch Repair',
  31 + previousHandler: 'Previous Handler',
  32 + requiredPreviousHandler: 'Required, please fill in the previous handler',
  33 + repairMaster: 'Repair Master',
  34 + requiredRepairMaster: 'Required, please select repair master',
  35 + handlingOpinions: 'Handling Opinions',
  36 + requiredHandlingOpinions: 'Required, please fill in handling opinions',
  37 + returnVisitSuggestion: 'Return Visit Suggestion',
  38 + requiredReturnVisitSuggestion: 'Required, please fill in return visit suggestion',
  39 + pauseReason: 'Pause Reason',
  40 + requiredPauseReason: 'Required, please fill in pause reason',
  41 + confirmOperation: 'Confirm Operation',
  42 + confirmStartRepair: 'Confirm to start the repair?',
  43 + cannotTransferToSelf: 'Cannot transfer the order to yourself',
  44 + fetchRepairListFailed: 'Failed to get repair list',
  45 + fetchRepairTypesFailed: 'Failed to get repair types',
  46 + fetchRepairMasterFailed: 'Failed to get repair masters',
  47 + dispatchFailed: 'Dispatch failed',
  48 + returnVisitFailed: 'Return visit failed',
  49 + pauseFailed: 'Pause failed',
  50 + startFailed: 'Start failed'
  51 + }
  52 + },
  53 + zh: {
  54 + repairDispatchManage: {
  55 + searchConditions: '查询条件',
  56 + repairBacklog: '报修待办',
  57 + placeholder: {
  58 + repairId: '请输入工单编号',
  59 + repairName: '请输入报修人',
  60 + tel: '请输入报修人电话',
  61 + selectRepairType: '请选择报修类型',
  62 + selectStatus: '请选择报修状态'
  63 + },
  64 + table: {
  65 + location: '位置',
  66 + repairType: '报修类型',
  67 + repairPerson: '报修人',
  68 + repairPhone: '报修人电话',
  69 + appointmentTime: '预约时间',
  70 + status: '状态',
  71 + operation: '操作'
  72 + },
  73 + transferOrder: '转单',
  74 + returnOrder: '退单',
  75 + complete: '办结',
  76 + returnVisit: '回访',
  77 + pause: '暂停',
  78 + start: '启动',
  79 + detail: '详情',
  80 + scheduledTask: '定时任务处理',
  81 + dispatchRepair: '报修派单',
  82 + previousHandler: '上级处理人',
  83 + requiredPreviousHandler: '必填,请填写上级处理人',
  84 + repairMaster: '报修师傅',
  85 + requiredRepairMaster: '必填,请选择报修师傅',
  86 + handlingOpinions: '处理意见',
  87 + requiredHandlingOpinions: '必填,请填写处理意见',
  88 + returnVisitSuggestion: '回访建议',
  89 + requiredReturnVisitSuggestion: '必填,请填写回访建议',
  90 + pauseReason: '暂停原因',
  91 + requiredPauseReason: '必填,请填写暂停原因',
  92 + confirmOperation: '确认操作',
  93 + confirmStartRepair: '确定启动报修?',
  94 + cannotTransferToSelf: '不能转单给自己',
  95 + fetchRepairListFailed: '获取报修列表失败',
  96 + fetchRepairTypesFailed: '获取报修类型失败',
  97 + fetchRepairMasterFailed: '获取维修师傅列表失败',
  98 + dispatchFailed: '派单失败',
  99 + returnVisitFailed: '回访失败',
  100 + pauseFailed: '暂停失败',
  101 + startFailed: '启动失败'
  102 + }
  103 + }
  104 +}
0 105 \ No newline at end of file
... ...
src/views/work/repairDispatchManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="padding">
  3 + <el-row :gutter="20">
  4 + <el-col :span="24">
  5 + <el-card>
  6 + <div slot="header" class="flex justify-between">
  7 + <div>{{ $t('repairDispatchManage.searchConditions') }}</div>
  8 + </div>
  9 + <div class="">
  10 + <el-row :gutter="15">
  11 + <el-col :span="4">
  12 + <el-input :placeholder="$t('repairDispatchManage.placeholder.repairId')"
  13 + v-model.trim="repairDispatchManageInfo.conditions.repairId" clearable />
  14 + </el-col>
  15 + <el-col :span="4">
  16 + <el-input :placeholder="$t('repairDispatchManage.placeholder.repairName')"
  17 + v-model.trim="repairDispatchManageInfo.conditions.repairName" clearable />
  18 + </el-col>
  19 + <el-col :span="4">
  20 + <el-input :placeholder="$t('repairDispatchManage.placeholder.tel')"
  21 + v-model.trim="repairDispatchManageInfo.conditions.tel" clearable />
  22 + </el-col>
  23 + <el-col :span="4">
  24 + <el-select v-model="repairDispatchManageInfo.conditions.repairType" style="width:100%">
  25 + <el-option :label="$t('repairDispatchManage.placeholder.selectRepairType')" value="" />
  26 + <el-option v-for="(item, index) in repairDispatchManageInfo.repairTypes" :key="index"
  27 + :label="item.repairTypeName" :value="item.repairType" />
  28 + </el-select>
  29 + </el-col>
  30 + <el-col :span="4">
  31 + <el-select v-model="repairDispatchManageInfo.conditions.state" style="width:100%">
  32 + <el-option :label="$t('repairDispatchManage.placeholder.selectStatus')" value="" />
  33 + <el-option v-for="(item, index) in repairDispatchManageInfo.states" :key="index" :label="item.name"
  34 + :value="item.statusCd" />
  35 + </el-select>
  36 + </el-col>
  37 + <el-col :span="4">
  38 + <el-button type="primary" @click="_queryOwnerRepairMethod">
  39 + <i class="el-icon-search"></i>
  40 + {{ $t('common.search') }}
  41 + </el-button>
  42 + <el-button type="default" @click="_resetOwnerRepairMethod">
  43 + <i class="el-icon-refresh"></i>
  44 + {{ $t('common.reset') }}
  45 + </el-button>
  46 + </el-col>
  47 + </el-row>
  48 + </div>
  49 + </el-card>
  50 + </el-col>
  51 + </el-row>
  52 +
  53 + <el-row :gutter="20" class="margin-top">
  54 + <el-col :span="24">
  55 + <el-card>
  56 + <div slot="header" class="flex justify-between">
  57 + <div>
  58 + <span>{{ repairDispatchManageInfo.conditions.roomName }}</span>
  59 + <span>{{ $t('repairDispatchManage.repairBacklog') }}</span>
  60 + </div>
  61 + </div>
  62 + <div class="">
  63 + <el-table :data="repairDispatchManageInfo.ownerRepairs" border style="width:100%">
  64 + <el-table-column prop="repairObjName" :label="$t('repairDispatchManage.table.location')" align="center" />
  65 + <el-table-column prop="repairTypeName" :label="$t('repairDispatchManage.table.repairType')"
  66 + align="center" />
  67 + <el-table-column prop="repairName" :label="$t('repairDispatchManage.table.repairPerson')" align="center" />
  68 + <el-table-column prop="tel" :label="$t('repairDispatchManage.table.repairPhone')" align="center" />
  69 + <el-table-column prop="appointmentTime" :label="$t('repairDispatchManage.table.appointmentTime')"
  70 + align="center" />
  71 + <el-table-column :label="$t('repairDispatchManage.table.status')" align="center">
  72 + <template slot-scope="scope">
  73 + <span
  74 + v-if="scope.row.state == '1800' && (scope.row.returnVisitFlag == '001' || scope.row.returnVisitFlag == '002')">
  75 + {{ scope.row.stateName }}({{ $t('repairDispatchManage.scheduledTask') }})
  76 + </span>
  77 + <span v-else>
  78 + {{ scope.row.stateName }}
  79 + </span>
  80 + </template>
  81 + </el-table-column>
  82 + <el-table-column :label="$t('common.operation')" align="center" width="300">
  83 + <template slot-scope="scope">
  84 + <el-button-group>
  85 + <el-button
  86 + v-if="(scope.row.state == '1100' || scope.row.state == '1200' || scope.row.state == '1300') && scope.row.state != '2001'"
  87 + size="mini" @click="_openDispatchRepairModel(scope.row)">
  88 + {{ $t('repairDispatchManage.transferOrder') }}
  89 + </el-button>
  90 + <el-button
  91 + v-if="scope.row.preStaffId != '-1' && scope.row.ruId != scope.row.preRuId && scope.row.state != '2001'"
  92 + size="mini" @click="_openBackRepairModel(scope.row)">
  93 + {{ $t('repairDispatchManage.returnOrder') }}
  94 + </el-button>
  95 + <el-button
  96 + v-if="(scope.row.state == '1100' || scope.row.state == '1200' || scope.row.state == '1300') && scope.row.state != '2001'"
  97 + size="mini" @click="_openFinishRepair(scope.row)">
  98 + {{ $t('repairDispatchManage.complete') }}
  99 + </el-button>
  100 + <el-button
  101 + v-if="$store.getters.hasPrivilege('502021040151320003') && scope.row.state == '1800' && scope.row.returnVisitFlag == '003' && scope.row.state != '2001'"
  102 + size="mini" @click="_openAppraiseRepair(scope.row)">
  103 + {{ $t('repairDispatchManage.returnVisit') }}
  104 + </el-button>
  105 + <el-button v-if="scope.row.state == '1100' || scope.row.state == '1200' || scope.row.state == '1300'"
  106 + size="mini" @click="_openStopRepair(scope.row)">
  107 + {{ $t('repairDispatchManage.pause') }}
  108 + </el-button>
  109 + <el-button v-if="scope.row.state == '2001'" size="mini" @click="_openStartRepair(scope.row)">
  110 + {{ $t('repairDispatchManage.start') }}
  111 + </el-button>
  112 + <el-button size="mini" @click="_openDispatchRepairDetail(scope.row)">
  113 + {{ $t('common.detail') }}
  114 + </el-button>
  115 + </el-button-group>
  116 + </template>
  117 + </el-table-column>
  118 + </el-table>
  119 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  120 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  121 + @current-change="handleCurrentChange" class="pagination" />
  122 + </div>
  123 + </el-card>
  124 + </el-col>
  125 + </el-row>
  126 +
  127 + <dispatch-repair ref="dispatchRepair" @success="handleSuccess" />
  128 + <appraise-repair ref="appraiseRepair" @success="handleSuccess" />
  129 + <stop-repair ref="stopRepair" @success="handleSuccess" />
  130 + <start-repair ref="startRepair" @success="handleSuccess" />
  131 + </div>
  132 +</template>
  133 +
  134 +<script>
  135 +import { listStaffRepairs, listRepairSettings } from '@/api/work/repairDispatchManageApi'
  136 +import { getDict } from '@/api/community/communityApi'
  137 +import { getCommunityId } from '@/api/community/communityApi'
  138 +import DispatchRepair from '@/components/work/dispatchRepair'
  139 +import AppraiseRepair from '@/components/work/AppraiseRepair'
  140 +import StopRepair from '@/components/work/StopRepair'
  141 +import StartRepair from '@/components/work/StartRepair'
  142 +
  143 +export default {
  144 + name: 'RepairDispatchManageList',
  145 + components: {
  146 + DispatchRepair,
  147 + AppraiseRepair,
  148 + StopRepair,
  149 + StartRepair
  150 + },
  151 + data() {
  152 + return {
  153 + repairDispatchManageInfo: {
  154 + ownerRepairs: [],
  155 + total: 0,
  156 + records: 1,
  157 + moreCondition: false,
  158 + repairTypes: [],
  159 + states: [],
  160 + conditions: {
  161 + repairId: '',
  162 + repairName: '',
  163 + tel: '',
  164 + repairType: '',
  165 + roomId: '',
  166 + roomName: '',
  167 + ownerId: '',
  168 + userId: '',
  169 + userName: '',
  170 + state: ''
  171 + }
  172 + },
  173 + page: {
  174 + current: 1,
  175 + size: 10,
  176 + total: 0
  177 + }
  178 + }
  179 + },
  180 + created() {
  181 + this.communityId = getCommunityId()
  182 + this._initData()
  183 + },
  184 + methods: {
  185 + async _initData() {
  186 + try {
  187 + // 获取报修类型字典
  188 + this.repairDispatchManageInfo.states = await getDict('r_repair_pool', 'state')
  189 + this._listRepairTypes()
  190 + this._listOwnerRepairs()
  191 + } catch (error) {
  192 + console.error('初始化数据失败:', error)
  193 + this.$message.error(this.$t('common.initFailed'))
  194 + }
  195 + },
  196 + async _listOwnerRepairs() {
  197 + try {
  198 + const params = {
  199 + ...this.repairDispatchManageInfo.conditions,
  200 + page: this.page.current,
  201 + row: this.page.size,
  202 + communityId: this.communityId
  203 + }
  204 +
  205 + const res = await listStaffRepairs(params)
  206 + this.repairDispatchManageInfo.ownerRepairs = res.data
  207 + this.page.total = res.total
  208 + } catch (error) {
  209 + console.error('获取报修列表失败:', error)
  210 + this.$message.error(this.$t('repairDispatchManage.fetchRepairListFailed'))
  211 + }
  212 + },
  213 + async _listRepairTypes() {
  214 + try {
  215 + const params = {
  216 + page: 1,
  217 + row: 50,
  218 + communityId: this.communityId
  219 + }
  220 +
  221 + const res = await listRepairSettings(params)
  222 + this.repairDispatchManageInfo.repairTypes = res.data
  223 + } catch (error) {
  224 + console.error('获取报修类型失败:', error)
  225 + this.$message.error(this.$t('repairDispatchManage.fetchRepairTypesFailed'))
  226 + }
  227 + },
  228 + _queryOwnerRepairMethod() {
  229 + this.page.current = 1
  230 + this._listOwnerRepairs()
  231 + },
  232 + _resetOwnerRepairMethod() {
  233 + this.repairDispatchManageInfo.conditions.repairId = ''
  234 + this.repairDispatchManageInfo.conditions.repairName = ''
  235 + this.repairDispatchManageInfo.conditions.tel = ''
  236 + this.repairDispatchManageInfo.conditions.repairType = ''
  237 + this.repairDispatchManageInfo.conditions.state = ''
  238 + this._listOwnerRepairs()
  239 + },
  240 + _openDispatchRepairModel(row) {
  241 + this.$refs.dispatchRepair.open({ ...row, action: 'TRANSFER' })
  242 + },
  243 + _openBackRepairModel(row) {
  244 + this.$refs.dispatchRepair.open({ ...row, action: 'BACK' })
  245 + },
  246 + _openFinishRepair(row) {
  247 + this.$router.push({
  248 + path: '/property/finishRepair',
  249 + query: {
  250 + repairType: row.repairType,
  251 + repairId: row.repairId,
  252 + repairObjType: row.repairObjType,
  253 + publicArea: row.publicArea,
  254 + repairChannel: row.repairChannel
  255 + }
  256 + })
  257 + },
  258 + _openDispatchRepairDetail(row) {
  259 + this.$router.push({
  260 + path: '/property/ownerRepairDetail',
  261 + query: { repairId: row.repairId }
  262 + })
  263 + },
  264 + _openAppraiseRepair(row) {
  265 + this.$refs.appraiseRepair.open(row)
  266 + },
  267 + _openStopRepair(row) {
  268 + this.$refs.stopRepair.open(row)
  269 + },
  270 + _openStartRepair(row) {
  271 + this.$refs.startRepair.open(row)
  272 + },
  273 + handleSizeChange(size) {
  274 + this.page.size = size
  275 + this._listOwnerRepairs()
  276 + },
  277 + handleCurrentChange(current) {
  278 + this.page.current = current
  279 + this._listOwnerRepairs()
  280 + },
  281 + handleSuccess() {
  282 + this._listOwnerRepairs()
  283 + }
  284 + }
  285 +}
  286 +</script>
  287 +
  288 +<style scoped>
  289 +.ibox-content {
  290 + padding: 15px 20px 20px 20px;
  291 +}
  292 +
  293 +.pagination {
  294 + margin-top: 15px;
  295 + text-align: right;
  296 +}
  297 +</style>
0 298 \ No newline at end of file
... ...
src/views/work/repairForceFinishManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairForceFinishManage: {
  4 + searchCondition: 'Search Conditions',
  5 + repairTypePlaceholder: 'Select Repair Type',
  6 + repairPersonPlaceholder: 'Enter Repair Person',
  7 + repairPhonePlaceholder: 'Enter Repair Phone',
  8 + search: 'Search',
  9 + reset: 'Reset',
  10 + forceFinish: 'Force Finish',
  11 + repairId: 'Work Order ID',
  12 + location: 'Location',
  13 + repairType: 'Repair Type',
  14 + repairPerson: 'Repair Person',
  15 + contact: 'Contact',
  16 + appointmentTime: 'Appointment Time',
  17 + submitTime: 'Submit Time',
  18 + status: 'Status',
  19 + operation: 'Operation',
  20 + detail: 'Detail',
  21 + description: 'Description: This function is mainly used to solve the scenario where the maintenance master is too old to use the mobile phone operation, and the customer service personnel need to confirm the maintenance completion and force the order back'
  22 + },
  23 + forceFinishRepair: {
  24 + title: 'Force Finish',
  25 + useMaterial: 'Use Material?',
  26 + maintenanceType: 'Maintenance Type',
  27 + goodsType: 'Goods Type',
  28 + goodsName: 'Goods Name',
  29 + customPrice: 'Custom Price',
  30 + secondaryCategory: 'Secondary Category',
  31 + goods: 'Goods',
  32 + goodsPrice: 'Goods Price',
  33 + priceRange: 'Price Range',
  34 + specification: 'Specification',
  35 + quantity: 'Quantity',
  36 + paymentMethod: 'Payment Method',
  37 + explanation: 'Explanation',
  38 + submit: 'Submit',
  39 + cancel: 'Cancel'
  40 + },
  41 + chooseSingleResource: {
  42 + title: 'Select Item',
  43 + goodsType: 'Goods Type',
  44 + secondaryCategory: 'Secondary Category',
  45 + goods: 'Goods',
  46 + goodsPrice: 'Goods Price',
  47 + priceRange: 'Price Range',
  48 + specification: 'Specification',
  49 + quantity: 'Quantity',
  50 + confirm: 'Confirm',
  51 + cancel: 'Cancel'
  52 + }
  53 + },
  54 + zh: {
  55 + repairForceFinishManage: {
  56 + searchCondition: '查询条件',
  57 + repairTypePlaceholder: '请选择报修类型',
  58 + repairPersonPlaceholder: '请输入报修人',
  59 + repairPhonePlaceholder: '请输入报修电话',
  60 + search: '查询',
  61 + reset: '重置',
  62 + forceFinish: '强制回单',
  63 + repairId: '工单编号',
  64 + location: '位置',
  65 + repairType: '报修类型',
  66 + repairPerson: '报修人',
  67 + contact: '联系方式',
  68 + appointmentTime: '预约时间',
  69 + submitTime: '提交时间',
  70 + status: '状态',
  71 + operation: '操作',
  72 + detail: '详情',
  73 + description: '说明:此功能主要为了解决维修师傅年龄大不会使用手机操作,需要客服人员确认维修完后强制回单场景'
  74 + },
  75 + forceFinishRepair: {
  76 + title: '强制回单',
  77 + useMaterial: '是否用料',
  78 + maintenanceType: '维修类型',
  79 + goodsType: '商品类型',
  80 + goodsName: '商品名',
  81 + customPrice: '自定义价格',
  82 + secondaryCategory: '二级分类',
  83 + goods: '商品',
  84 + goodsPrice: '商品价格',
  85 + priceRange: '价格范围',
  86 + specification: '规格',
  87 + quantity: '商品数量',
  88 + paymentMethod: '支付方式',
  89 + explanation: '说明',
  90 + submit: '提交',
  91 + cancel: '取消'
  92 + },
  93 + chooseSingleResource: {
  94 + title: '选择物品',
  95 + goodsType: '商品类型',
  96 + secondaryCategory: '二级分类',
  97 + goods: '商品',
  98 + goodsPrice: '商品价格',
  99 + priceRange: '价格范围',
  100 + specification: '规格',
  101 + quantity: '商品数量',
  102 + confirm: '确定',
  103 + cancel: '取消'
  104 + }
  105 + }
  106 +}
0 107 \ No newline at end of file
... ...
src/views/work/repairForceFinishManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="repair-force-finish-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-card">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('repairForceFinishManage.searchCondition') }}</span>
  7 + </div>
  8 +
  9 + <el-row :gutter="20">
  10 + <el-col :span="6">
  11 + <el-select v-model="searchForm.repairType" :placeholder="$t('repairForceFinishManage.repairTypePlaceholder')"
  12 + clearable style="width:100%">
  13 + <el-option v-for="item in repairSettings" :key="item.repairType" :label="item.repairTypeName"
  14 + :value="item.repairType" />
  15 + </el-select>
  16 + </el-col>
  17 +
  18 + <el-col :span="6">
  19 + <el-input v-model="searchForm.repairName" :placeholder="$t('repairForceFinishManage.repairPersonPlaceholder')"
  20 + clearable />
  21 + </el-col>
  22 +
  23 + <el-col :span="6">
  24 + <el-input v-model="searchForm.tel" :placeholder="$t('repairForceFinishManage.repairPhonePlaceholder')"
  25 + clearable />
  26 + </el-col>
  27 +
  28 + <el-col :span="6">
  29 + <el-button type="primary" @click="queryRepairPool">
  30 + <i class="el-icon-search"></i>
  31 + {{ $t('repairForceFinishManage.search') }}
  32 + </el-button>
  33 + <el-button @click="resetRepairPool" style="margin-left:10px">
  34 + <i class="el-icon-refresh"></i>
  35 + {{ $t('repairForceFinishManage.reset') }}
  36 + </el-button>
  37 + </el-col>
  38 + </el-row>
  39 + </el-card>
  40 +
  41 + <!-- 报修列表 -->
  42 + <el-card class="list-card">
  43 + <div slot="header" class="flex justify-between">
  44 + <span>{{ searchForm.roomName }} {{ $t('repairForceFinishManage.forceFinish') }}</span>
  45 + </div>
  46 +
  47 + <el-table :data="repairPools" border v-loading="loading">
  48 + <el-table-column prop="repairId" :label="$t('repairForceFinishManage.repairId')" align="center" />
  49 + <el-table-column prop="repairObjName" :label="$t('repairForceFinishManage.location')" align="center" />
  50 + <el-table-column prop="repairTypeName" :label="$t('repairForceFinishManage.repairType')" align="center" />
  51 + <el-table-column prop="repairName" :label="$t('repairForceFinishManage.repairPerson')" align="center" />
  52 + <el-table-column prop="tel" :label="$t('repairForceFinishManage.contact')" align="center" />
  53 + <el-table-column prop="appointmentTime" :label="$t('repairForceFinishManage.appointmentTime')" align="center" />
  54 + <el-table-column prop="createTime" :label="$t('repairForceFinishManage.submitTime')" align="center" />
  55 + <el-table-column prop="stateName" :label="$t('repairForceFinishManage.status')" align="center" />
  56 + <el-table-column :label="$t('repairForceFinishManage.operation')" align="center" width="200">
  57 + <template slot-scope="scope">
  58 + <el-button size="mini" type="primary" @click="openForceFinishRepair(scope.row)">
  59 + {{ $t('repairForceFinishManage.forceFinish') }}
  60 + </el-button>
  61 + <el-button size="mini" @click="openRepairDetail(scope.row)">
  62 + {{ $t('repairForceFinishManage.detail') }}
  63 + </el-button>
  64 + </template>
  65 + </el-table-column>
  66 + </el-table>
  67 +
  68 + <el-row class="footer-row">
  69 + <el-col :span="18">
  70 + <div class="description">
  71 + {{ $t('repairForceFinishManage.description') }}
  72 + </div>
  73 + </el-col>
  74 + <el-col :span="6">
  75 + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  76 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  77 + @current-change="handleCurrentChange" />
  78 + </el-col>
  79 + </el-row>
  80 + </el-card>
  81 +
  82 + <!-- 强制回单弹窗 -->
  83 + <force-finish-repair ref="forceFinishDialog" :visible.sync="forceFinishVisible" @success="handleForceFinishSuccess" />
  84 + </div>
  85 +</template>
  86 +
  87 +<script>
  88 +import {
  89 + listRepairSettings,
  90 + listOwnerRepairs,
  91 + getDict
  92 +} from '@/api/work/repairForceFinishManageApi'
  93 +import ForceFinishRepair from '@/components/work/forceFinishRepair'
  94 +
  95 +export default {
  96 + name: 'RepairForceFinishManageList',
  97 + components: {
  98 + ForceFinishRepair
  99 + },
  100 + data() {
  101 + return {
  102 + searchForm: {
  103 + repairType: '',
  104 + repairName: '',
  105 + tel: '',
  106 + roomId: '',
  107 + roomName: '',
  108 + state: '1100'
  109 + },
  110 + repairPools: [],
  111 + repairSettings: [],
  112 + states: [],
  113 + loading: false,
  114 + forceFinishVisible: false,
  115 + pagination: {
  116 + current: 1,
  117 + size: 10,
  118 + total: 0
  119 + }
  120 + }
  121 + },
  122 + mounted() {
  123 + this.loadRepairSettings()
  124 + this.loadDictData()
  125 + this.listRepairPools()
  126 + },
  127 + methods: {
  128 + async loadRepairSettings() {
  129 + try {
  130 + this.repairSettings = await listRepairSettings()
  131 + } catch (error) {
  132 + console.error('获取报修设置失败:', error)
  133 + this.$message.error('获取报修设置失败')
  134 + }
  135 + },
  136 + async loadDictData() {
  137 + try {
  138 + this.states = await getDict('r_repair_pool', 'state')
  139 + } catch (error) {
  140 + console.error('获取状态字典失败:', error)
  141 + this.$message.error('获取状态字典失败')
  142 + }
  143 + },
  144 + async listRepairPools() {
  145 + this.loading = true
  146 + try {
  147 + const params = {
  148 + ...this.searchForm,
  149 + page: this.pagination.current,
  150 + row: this.pagination.size
  151 + }
  152 +
  153 + // 清理空值
  154 + Object.keys(params).forEach(key => {
  155 + if (params[key] === '') delete params[key]
  156 + })
  157 +
  158 + const { data, total } = await listOwnerRepairs(params)
  159 + this.repairPools = data
  160 + this.pagination.total = total
  161 + } catch (error) {
  162 + console.error('获取报修列表失败:', error)
  163 + this.$message.error('获取报修列表失败')
  164 + } finally {
  165 + this.loading = false
  166 + }
  167 + },
  168 + queryRepairPool() {
  169 + this.pagination.current = 1
  170 + this.listRepairPools()
  171 + },
  172 + resetRepairPool() {
  173 + this.searchForm = {
  174 + repairType: '',
  175 + repairName: '',
  176 + tel: '',
  177 + state: '1100'
  178 + }
  179 + this.queryRepairPool()
  180 + },
  181 + openForceFinishRepair(repair) {
  182 + this.forceFinishVisible = true
  183 + this.$nextTick(() => {
  184 + this.$refs.forceFinishDialog.open(repair)
  185 + })
  186 + },
  187 + openRepairDetail(repair) {
  188 + this.$router.push(`/work/repairDetail/${repair.repairId}`)
  189 + },
  190 + handleForceFinishSuccess() {
  191 + this.listRepairPools()
  192 + },
  193 + handleSizeChange(size) {
  194 + this.pagination.size = size
  195 + this.listRepairPools()
  196 + },
  197 + handleCurrentChange(current) {
  198 + this.pagination.current = current
  199 + this.listRepairPools()
  200 + }
  201 + }
  202 +}
  203 +</script>
  204 +
  205 +<style lang="scss" scoped>
  206 +.repair-force-finish-container {
  207 + padding: 20px;
  208 +
  209 + .search-card {
  210 + margin-bottom: 20px;
  211 + }
  212 +
  213 + .list-card {
  214 + margin-bottom: 20px;
  215 + }
  216 +
  217 + .footer-row {
  218 + margin-top: 20px;
  219 + display: flex;
  220 + align-items: center;
  221 +
  222 + .description {
  223 + font-size: 14px;
  224 + color: #999;
  225 + }
  226 + }
  227 +
  228 + .el-pagination {
  229 + display: flex;
  230 + justify-content: flex-end;
  231 + }
  232 +}
  233 +</style>
0 234 \ No newline at end of file
... ...
src/views/work/repairPoolManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairPoolManage: {
  4 + queryConditions: 'Query Conditions',
  5 + repairOrderPool: 'Repair Order Pool',
  6 + workOrderCode: 'Work Order Code',
  7 + location: 'Location',
  8 + repairType: 'Repair Type',
  9 + maintenanceType: 'Maintenance Type',
  10 + repairPerson: 'Repair Person',
  11 + contact: 'Contact',
  12 + appointmentTime: 'Appointment Time',
  13 + submissionTime: 'Submission Time',
  14 + submissionDuration: 'Submission Duration',
  15 + completionTime: 'Completion Time',
  16 + status: 'Status',
  17 + operation: 'Operation',
  18 + modify: 'Modify',
  19 + dispatch: 'Dispatch',
  20 + grabOrder: 'Grab Order',
  21 + end: 'End',
  22 + details: 'Details',
  23 + delete: 'Delete',
  24 + search: 'Search',
  25 + reset: 'Reset',
  26 + more: 'More',
  27 + hide: 'Hide',
  28 + all: 'All',
  29 + timeoutOrders: 'Timeout Orders',
  30 + workOrderNumber: 'Work Order Number',
  31 + repairPersonName: 'Repair Person Name',
  32 + repairPhone: 'Repair Phone',
  33 + selectRepairType: 'Select Repair Type',
  34 + selectRepairSettingType: 'Select Repair Setting Type',
  35 + repairLocation: 'Repair Location',
  36 + selectMaintenanceType: 'Select Maintenance Type',
  37 + startTime: 'Start Time',
  38 + endTime: 'End Time',
  39 + repairSettingType: 'Repair Setting Type',
  40 + repairContent: 'Repair Content',
  41 + operationSuggestions: 'Operation Suggestions',
  42 + endReason: 'End Reason',
  43 + }
  44 + },
  45 + zh: {
  46 + repairPoolManage: {
  47 + queryConditions: '查询条件',
  48 + repairOrderPool: '报修工单池',
  49 + workOrderCode: '工单编码',
  50 + location: '位置',
  51 + repairType: '报修类型',
  52 + maintenanceType: '维修类型',
  53 + repairPerson: '报修人',
  54 + contact: '联系方式',
  55 + appointmentTime: '预约时间',
  56 + submissionTime: '提交时间',
  57 + submissionDuration: '提单时长',
  58 + completionTime: '完成时间',
  59 + status: '状态',
  60 + operation: '操作',
  61 + modify: '修改',
  62 + dispatch: '派单',
  63 + grabOrder: '抢单',
  64 + end: '结束',
  65 + details: '详情',
  66 + delete: '删除',
  67 + search: '查询',
  68 + reset: '重置',
  69 + more: '更多',
  70 + hide: '隐藏',
  71 + all: '全部',
  72 + timeoutOrders: '超时工单',
  73 + workOrderNumber: '工单编号',
  74 + repairPersonName: '报修人',
  75 + repairPhone: '报修电话',
  76 + selectRepairType: '请选择报修类型',
  77 + selectRepairSettingType: '请选择报修设置类型',
  78 + repairLocation: '报修位置',
  79 + selectMaintenanceType: '请选择维修类型',
  80 + startTime: '开始时间',
  81 + endTime: '结束时间',
  82 + repairSettingType: '报修设置类型',
  83 + repairContent: '报修内容',
  84 + operationSuggestions: '说明',
  85 + endReason: '结束原因',
  86 + }
  87 + }
  88 +}
0 89 \ No newline at end of file
... ...
src/views/work/repairPoolManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <el-row :gutter="20">
  4 + <!-- 左侧状态栏 -->
  5 + <el-col :span="3">
  6 + <el-card>
  7 + <div class="status-list">
  8 + <div v-for="(item, index) in states" :key="index" class="status-item"
  9 + :class="{ 'status-active': conditions.state === item.statusCd }" @click="switchRepairState(item)">
  10 + {{ item.name }}
  11 + </div>
  12 + </div>
  13 + </el-card>
  14 + </el-col>
  15 +
  16 + <!-- 右侧内容 -->
  17 + <el-col :span="21">
  18 + <!-- 查询条件 -->
  19 + <el-card class="box-card">
  20 + <div slot="header" class="flex justify-between">
  21 + <span>{{ $t('repairPoolManage.queryConditions') }}</span>
  22 + <el-button style="float: right; padding: 3px 0" type="text" @click="toggleMoreCondition">
  23 + {{ moreCondition ? $t('repairPoolManage.hide') : $t('repairPoolManage.more') }}
  24 + </el-button>
  25 + </div>
  26 +
  27 + <el-form :model="conditions" label-width="auto">
  28 + <el-row :gutter="20">
  29 + <el-col :span="4">
  30 + <el-form-item>
  31 + <el-input v-model="conditions.repairId" :placeholder="$t('repairPoolManage.workOrderNumber')" />
  32 + </el-form-item>
  33 + </el-col>
  34 +
  35 + <el-col :span="4">
  36 + <el-form-item>
  37 + <el-input v-model="conditions.repairName" :placeholder="$t('repairPoolManage.repairPersonName')" />
  38 + </el-form-item>
  39 + </el-col>
  40 +
  41 + <el-col :span="4">
  42 + <el-form-item>
  43 + <el-input v-model="conditions.tel" :placeholder="$t('repairPoolManage.repairPhone')" />
  44 + </el-form-item>
  45 + </el-col>
  46 +
  47 + <el-col :span="4">
  48 + <el-form-item>
  49 + <el-select v-model="conditions.repairType" :placeholder="$t('repairPoolManage.selectRepairType')"
  50 + style="width:100%">
  51 + <el-option v-for="(item, index) in repairSettings" :key="index" :label="item.repairTypeName"
  52 + :value="item.repairType" />
  53 + </el-select>
  54 + </el-form-item>
  55 + </el-col>
  56 + <el-col :span="4">
  57 + <el-form-item>
  58 + <el-input v-model="conditions.repairObjName" :placeholder="$t('repairPoolManage.repairLocation')" />
  59 + </el-form-item>
  60 + </el-col>
  61 +
  62 + <el-col :span="4">
  63 + <el-form-item>
  64 + <el-select v-model="conditions.maintenanceType"
  65 + :placeholder="$t('repairPoolManage.selectMaintenanceType')" style="width:100%">
  66 + <el-option v-for="(item, index) in maintenanceTypes" :key="index" :label="item.name"
  67 + :value="item.statusCd" />
  68 + </el-select>
  69 + </el-form-item>
  70 + </el-col>
  71 +
  72 + <el-col :span="4">
  73 + <el-form-item>
  74 + <el-date-picker v-model="conditions.startTime" type="datetime" style="width:100%"
  75 + :placeholder="$t('repairPoolManage.startTime')" value-format="yyyy-MM-dd HH:mm:ss" />
  76 + </el-form-item>
  77 + </el-col>
  78 +
  79 + <el-col :span="4">
  80 + <el-form-item>
  81 + <el-date-picker v-model="conditions.endTime" type="datetime" style="width:100%"
  82 + :placeholder="$t('repairPoolManage.endTime')" value-format="yyyy-MM-dd HH:mm:ss" />
  83 + </el-form-item>
  84 + </el-col>
  85 + <el-col :span="4" >
  86 + <el-button type="primary" @click="queryRepairPool">{{ $t('repairPoolManage.search') }}</el-button>
  87 + <el-button @click="resetRepairPool">{{ $t('repairPoolManage.reset') }}</el-button>
  88 + </el-col>
  89 + </el-row>
  90 + </el-form>
  91 + </el-card>
  92 +
  93 + <!-- 报修工单池 -->
  94 + <el-card class="box-card">
  95 + <div slot="header" class="clearfix flex justify-between">
  96 + <span>{{ $t('repairPoolManage.repairOrderPool') }}</span>
  97 + </div>
  98 +
  99 + <el-table v-loading="loading" :data="repairPools" border style="width: 100%">
  100 + <el-table-column prop="repairId" :label="$t('repairPoolManage.workOrderCode')" align="center" />
  101 + <el-table-column prop="repairObjName" :label="$t('repairPoolManage.location')" align="center" />
  102 + <el-table-column prop="repairTypeName" :label="$t('repairPoolManage.repairType')" align="center" />
  103 + <el-table-column :label="$t('repairPoolManage.maintenanceType')" align="center">
  104 + <template slot-scope="scope">
  105 + {{ formatMaintenanceType(scope.row.maintenanceType) }}
  106 + </template>
  107 + </el-table-column>
  108 + <el-table-column prop="repairName" :label="$t('repairPoolManage.repairPerson')" align="center" />
  109 + <el-table-column prop="tel" :label="$t('repairPoolManage.contact')" align="center" />
  110 + <el-table-column :label="$t('repairPoolManage.appointmentTime')" align="center">
  111 + <template slot-scope="scope">
  112 + <div>{{ scope.row.appointmentTime }}</div>
  113 + <div>~{{ scope.row.timeout }}</div>
  114 + </template>
  115 + </el-table-column>
  116 + <el-table-column prop="createTime" :label="$t('repairPoolManage.submissionTime')" align="center" />
  117 + <el-table-column prop="submitHours" :label="$t('repairPoolManage.submissionDuration')" align="center">
  118 + <template slot-scope="scope">
  119 + {{ scope.row.submitHours || '0' }}
  120 + </template>
  121 + </el-table-column>
  122 + <el-table-column prop="finishTime" :label="$t('repairPoolManage.completionTime')" align="center">
  123 + <template slot-scope="scope">
  124 + {{ scope.row.finishTime || '-' }}
  125 + </template>
  126 + </el-table-column>
  127 + <el-table-column :label="$t('repairPoolManage.status')" align="center">
  128 + <template slot-scope="scope">
  129 + <span v-if="scope.row.state === '1800' && ['001', '002'].includes(scope.row.returnVisitFlag)">
  130 + {{ scope.row.stateName }}({{ $t('repairPoolManage.timedTaskProcessing') }})
  131 + </span>
  132 + <span v-else>{{ scope.row.stateName }}</span>
  133 + </template>
  134 + </el-table-column>
  135 + <el-table-column :label="$t('repairPoolManage.operation')" align="center" width="300">
  136 + <template slot-scope="scope">
  137 + <el-button v-if="hasPrivilege('502021012067300023') && ['1000', '1200'].includes(scope.row.state)"
  138 + size="mini" @click="openEditModal(scope.row)">
  139 + {{ $t('repairPoolManage.modify') }}
  140 + </el-button>
  141 +
  142 + <el-button v-if="hasPrivilege('502019101946430010') && scope.row.state === '1000'" size="mini"
  143 + type="primary" @click="openDispatchModal(scope.row)">
  144 + {{ $t('repairPoolManage.dispatch') }}
  145 + </el-button>
  146 +
  147 + <el-button
  148 + v-if="hasPrivilege('502021012099350016') && scope.row.state === '1000' && scope.row.repairWay === '100'"
  149 + size="mini" type="success" @click="grabOrder(scope.row)">
  150 + {{ $t('repairPoolManage.grabOrder') }}
  151 + </el-button>
  152 +
  153 + <el-button
  154 + v-if="hasPrivilege('502019101946430010') && !['1900', '1700', '1800'].includes(scope.row.state)"
  155 + size="mini" type="warning" @click="openEndModal(scope.row)">
  156 + {{ $t('repairPoolManage.end') }}
  157 + </el-button>
  158 +
  159 + <el-button size="mini" type="info" @click="openDetail(scope.row)">
  160 + {{ $t('repairPoolManage.details') }}
  161 + </el-button>
  162 +
  163 + <el-button v-if="hasPrivilege('502021012051410024') && ['1000', '1200'].includes(scope.row.state)"
  164 + size="mini" type="danger" @click="openDeleteModal(scope.row.repairId)">
  165 + {{ $t('repairPoolManage.delete') }}
  166 + </el-button>
  167 + </template>
  168 + </el-table-column>
  169 + </el-table>
  170 +
  171 + <!-- 分页 -->
  172 + <el-pagination background layout="total, sizes, prev, pager, next, jumper" :current-page="page.current"
  173 + :page-sizes="[10, 20, 30, 50]" :page-size="page.size" :total="page.total" @size-change="handleSizeChange"
  174 + @current-change="handleCurrentChange" />
  175 + </el-card>
  176 + </el-col>
  177 + </el-row>
  178 +
  179 + <!-- 组件 -->
  180 + <dispatch-repair ref="dispatchRepair" @success="fetchData" />
  181 + <end-repair ref="endRepair" @success="fetchData" />
  182 + <edit-owner-repair ref="editOwnerRepair" @success="fetchData" />
  183 + <delete-owner-repair ref="deleteOwnerRepair" @success="fetchData" />
  184 + </div>
  185 +</template>
  186 +
  187 +<script>
  188 +import { listRepairPools, grabbingRepair } from '@/api/work/repairPoolManageApi'
  189 +import { getDict } from '@/api/community/communityApi'
  190 +import { getCommunityId } from '@/api/community/communityApi'
  191 +import DispatchRepair from '@/components/work/dispatchRepair'
  192 +import EndRepair from '@/components/work/endRepair'
  193 +import EditOwnerRepair from '@/components/work/editOwnerRepair'
  194 +import DeleteOwnerRepair from '@/components/work/deleteOwnerRepair'
  195 +import {listRepairSettings} from '@/api/work/ownerRepairManageApi'
  196 +
  197 +export default {
  198 + name: 'RepairPoolManage',
  199 + components: {
  200 + DispatchRepair,
  201 + EndRepair,
  202 + EditOwnerRepair,
  203 + DeleteOwnerRepair
  204 + },
  205 + data() {
  206 + return {
  207 + loading: false,
  208 + repairPools: [],
  209 + repairSettings: [],
  210 + states: [],
  211 + repairSettingTypes: [],
  212 + maintenanceTypes: [],
  213 + moreCondition: false,
  214 + conditions: {
  215 + repairId: '',
  216 + repairName: '',
  217 + tel: '',
  218 + repairType: '',
  219 + repairSettingType: '',
  220 + roomId: '',
  221 + roomName: '',
  222 + ownerId: '',
  223 + state: '',
  224 + maintenanceType: '',
  225 + startTime: '',
  226 + endTime: '',
  227 + repairObjName: ''
  228 + },
  229 + page: {
  230 + current: 1,
  231 + size: 10,
  232 + total: 0
  233 + }
  234 + }
  235 + },
  236 + created() {
  237 + this.fetchData()
  238 + this.fetchRepairSettings()
  239 + this.loadDictData()
  240 + },
  241 + methods: {
  242 + async fetchData() {
  243 + this.loading = true
  244 + try {
  245 + const params = {
  246 + ...this.conditions,
  247 + page: this.page.current,
  248 + row: this.page.size
  249 + }
  250 +
  251 + const res = await listRepairPools(params)
  252 + this.repairPools = res.data || []
  253 + this.page.total = res.total || 0
  254 + } catch (error) {
  255 + console.error('Failed to fetch repair pools:', error)
  256 + } finally {
  257 + this.loading = false
  258 + }
  259 + },
  260 +
  261 + async fetchRepairSettings() {
  262 + try {
  263 + const params = {
  264 + page: 1,
  265 + row: 50,
  266 + communityId: getCommunityId()
  267 + }
  268 +
  269 + const res = await listRepairSettings(params)
  270 + this.repairSettings = res.data || []
  271 + } catch (error) {
  272 + console.error('Failed to fetch repair settings:', error)
  273 + }
  274 + },
  275 +
  276 + async loadDictData() {
  277 + try {
  278 + // 获取状态字典
  279 + const stateData = await getDict('r_repair_pool', 'state')
  280 + this.states = [
  281 + { statusCd: '', name: this.$t('repairPoolManage.all') },
  282 + { statusCd: 'TIMEOUT', name: this.$t('repairPoolManage.timeoutOrders') },
  283 + ...(stateData || [])
  284 + ]
  285 +
  286 + // 获取报修设置类型字典
  287 + this.repairSettingTypes = await getDict('r_repair_setting', 'repair_setting_type')
  288 +
  289 + // 获取维修类型字典
  290 + this.maintenanceTypes = await getDict('r_repair_pool', 'maintenance_type')
  291 + } catch (error) {
  292 + console.error('Failed to load dict data:', error)
  293 + }
  294 + },
  295 +
  296 + formatMaintenanceType(type) {
  297 + const types = {
  298 + '1001': this.$t('repairPoolManage.paidService'),
  299 + '1002': this.$t('repairPoolManage.freeService'),
  300 + '1003': this.$t('repairPoolManage.needMaterials'),
  301 + '1004': this.$t('repairPoolManage.noMaterialsNeeded')
  302 + }
  303 + return types[type] || '--'
  304 + },
  305 +
  306 + switchRepairState(item) {
  307 + this.conditions.state = item.statusCd
  308 + this.fetchData()
  309 + },
  310 +
  311 + toggleMoreCondition() {
  312 + this.moreCondition = !this.moreCondition
  313 + },
  314 +
  315 + queryRepairPool() {
  316 + this.page.current = 1
  317 + this.fetchData()
  318 + },
  319 +
  320 + resetRepairPool() {
  321 + this.conditions = {
  322 + repairId: '',
  323 + repairName: '',
  324 + tel: '',
  325 + repairType: '',
  326 + repairSettingType: '',
  327 + repairObjName: '',
  328 + maintenanceType: '',
  329 + startTime: '',
  330 + endTime: '',
  331 + state: this.conditions.state // 保持当前状态
  332 + }
  333 + this.fetchData()
  334 + },
  335 +
  336 + openEditModal(repair) {
  337 + this.$refs.editOwnerRepair.open(repair)
  338 + },
  339 +
  340 + openDispatchModal(repair) {
  341 + this.$refs.dispatchRepair.open(repair)
  342 + },
  343 +
  344 + async grabOrder(repair) {
  345 + try {
  346 + const data = {
  347 + communityId: getCommunityId(),
  348 + repairId: repair.repairId
  349 + }
  350 +
  351 + await grabbingRepair(data)
  352 + this.$message.success(this.$t('common.operationSuccess'))
  353 + this.fetchData()
  354 + } catch (error) {
  355 + console.error('Grab order failed:', error)
  356 + }
  357 + },
  358 +
  359 + openEndModal(repair) {
  360 + this.$refs.endRepair.open(repair)
  361 + },
  362 +
  363 + openDetail(repair) {
  364 + this.$router.push(`/views/work/repairDetail?repairId=${repair.repairId}`)
  365 + },
  366 +
  367 + openDeleteModal(repairId) {
  368 + this.$refs.deleteOwnerRepair.open(repairId)
  369 + },
  370 +
  371 + handleSizeChange(size) {
  372 + this.page.size = size
  373 + this.fetchData()
  374 + },
  375 +
  376 + handleCurrentChange(current) {
  377 + this.page.current = current
  378 + this.fetchData()
  379 + },
  380 +
  381 + }
  382 +}
  383 +</script>
  384 +
  385 +<style scoped>
  386 +.status-list {
  387 + display: flex;
  388 + flex-direction: column;
  389 +}
  390 +
  391 +.status-item {
  392 + padding: 12px;
  393 + margin-bottom: 8px;
  394 + border-radius: 4px;
  395 + cursor: pointer;
  396 + text-align: center;
  397 + transition: all 0.3s;
  398 +}
  399 +
  400 +.status-item:hover {
  401 + background-color: #f5f7fa;
  402 +}
  403 +
  404 +.status-active {
  405 + background-color: #409eff;
  406 + color: white;
  407 +}
  408 +
  409 +.box-card {
  410 + margin-bottom: 20px;
  411 +}
  412 +</style>
0 413 \ No newline at end of file
... ...
src/views/work/repairReturnVisitLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairReturnVisit: {
  4 + queryTitle: 'Query Conditions',
  5 + listTitle: 'Repair Return Visit',
  6 + repairId: 'Work Order No.',
  7 + location: 'Location',
  8 + repairType: 'Repair Type',
  9 + repairName: 'Repair Person',
  10 + contact: 'Contact',
  11 + appointmentTime: 'Appointment Time',
  12 + operation: 'Operation',
  13 + visit: 'Visit',
  14 + detail: 'Detail',
  15 + repairIdPlaceholder: 'Please enter work order number',
  16 + repairTypePlaceholder: 'Please select repair type',
  17 + repairNamePlaceholder: 'Please enter repair person',
  18 + telPlaceholder: 'Please enter repair phone',
  19 + statePlaceholder: 'Please select visit status',
  20 + waiting: 'Pending Visit',
  21 + finish: 'Visited'
  22 + }
  23 + },
  24 + zh: {
  25 + repairReturnVisit: {
  26 + queryTitle: '查询条件',
  27 + listTitle: '报修回访',
  28 + repairId: '工单编码',
  29 + location: '位置',
  30 + repairType: '报修类型',
  31 + repairName: '报修人',
  32 + contact: '联系方式',
  33 + appointmentTime: '预约时间',
  34 + operation: '操作',
  35 + visit: '回访',
  36 + detail: '详情',
  37 + repairIdPlaceholder: '请输入工单编号',
  38 + repairTypePlaceholder: '请选择报修类型',
  39 + repairNamePlaceholder: '请输入报修人',
  40 + telPlaceholder: '请输入报修电话',
  41 + statePlaceholder: '请选择回访状态',
  42 + waiting: '待回访',
  43 + finish: '已回访'
  44 + }
  45 + }
  46 +}
0 47 \ No newline at end of file
... ...
src/views/work/repairReturnVisitList.vue 0 → 100644
  1 +<template>
  2 + <div class="padding">
  3 + <el-row :gutter="20">
  4 + <el-col :span="24">
  5 + <el-card>
  6 + <div slot="header" class="flex justify-between">
  7 + <span>{{ $t('repairReturnVisit.queryTitle') }}</span>
  8 + </div>
  9 + <el-form :model="searchForm" label-width="0">
  10 + <el-row :gutter="15">
  11 + <el-col :sm="6" :md="4">
  12 + <el-input v-model.trim="searchForm.repairId" :placeholder="$t('repairReturnVisit.repairIdPlaceholder')"
  13 + clearable />
  14 + </el-col>
  15 + <el-col :sm="6" :md="4">
  16 + <el-select v-model="searchForm.repairType" :placeholder="$t('repairReturnVisit.repairTypePlaceholder')"
  17 + clearable style="width:100%">
  18 + <el-option v-for="item in repairSettings" :key="item.repairType" :label="item.repairTypeName"
  19 + :value="item.repairType" />
  20 + </el-select>
  21 + </el-col>
  22 + <el-col :sm="6" :md="4">
  23 + <el-input v-model.trim="searchForm.repairName"
  24 + :placeholder="$t('repairReturnVisit.repairNamePlaceholder')" clearable />
  25 + </el-col>
  26 + <el-col :sm="6" :md="4">
  27 + <el-input v-model.trim="searchForm.tel" :placeholder="$t('repairReturnVisit.telPlaceholder')" clearable />
  28 + </el-col>
  29 + <el-col :sm="6" :md="4">
  30 + <el-select v-model="searchForm.state" :placeholder="$t('repairReturnVisit.statePlaceholder')" clearable
  31 + style="width:100%">
  32 + <el-option v-for="item in states" :key="item.value" :label="item.label" :value="item.value" />
  33 + </el-select>
  34 + </el-col>
  35 + <el-col :sm="6" :md="4">
  36 + <el-button type="primary" icon="el-icon-search" @click="queryRepairPool">
  37 + {{ $t('common.search') }}
  38 + </el-button>
  39 + <el-button icon="el-icon-refresh" @click="resetRepairPool">
  40 + {{ $t('common.reset') }}
  41 + </el-button>
  42 + </el-col>
  43 + </el-row>
  44 + </el-form>
  45 + </el-card>
  46 + </el-col>
  47 + </el-row>
  48 +
  49 + <el-row :gutter="20" class="mt-20">
  50 + <el-col :span="24">
  51 + <el-card>
  52 + <div slot="header" class="flex justify-between">
  53 + <span>{{ $t('repairReturnVisit.listTitle') }}</span>
  54 + </div>
  55 + <el-table v-loading="loading" :data="repairPools" border stripe style="width: 100%">
  56 + <el-table-column prop="repairId" :label="$t('repairReturnVisit.repairId')" align="center" />
  57 + <el-table-column prop="repairObjName" :label="$t('repairReturnVisit.location')" align="center" />
  58 + <el-table-column prop="repairTypeName" :label="$t('repairReturnVisit.repairType')" align="center" />
  59 + <el-table-column prop="repairName" :label="$t('repairReturnVisit.repairName')" align="center" />
  60 + <el-table-column prop="tel" :label="$t('repairReturnVisit.contact')" align="center" />
  61 + <el-table-column prop="appointmentTime" :label="$t('repairReturnVisit.appointmentTime')" align="center" />
  62 + <el-table-column :label="$t('common.operation')" align="center" width="180">
  63 + <template slot-scope="scope">
  64 + <el-button v-if="!scope.row.visitId" type="primary" size="mini" @click="openEditOwnerRepair(scope.row)">
  65 + {{ $t('repairReturnVisit.visit') }}
  66 + </el-button>
  67 + <el-button size="mini" @click="openRepairDetail(scope.row)">
  68 + {{ $t('repairReturnVisit.detail') }}
  69 + </el-button>
  70 + </template>
  71 + </el-table-column>
  72 + </el-table>
  73 + <el-pagination class="mt-20" :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]"
  74 + :page-size="pagination.size" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
  75 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  76 + </el-card>
  77 + </el-col>
  78 + </el-row>
  79 +
  80 + <visit-owner-repair ref="visitModal" @success="listRepairPools" />
  81 + </div>
  82 +</template>
  83 +
  84 +<script>
  85 +import { getRepairReturnVisitList, listRepairSettings } from '@/api/work/repairReturnVisitApi'
  86 +import VisitOwnerRepair from '@/components/work/visitOwnerRepair'
  87 +
  88 +export default {
  89 + name: 'RepairReturnVisitList',
  90 + components: { VisitOwnerRepair },
  91 + data() {
  92 + return {
  93 + loading: false,
  94 + searchForm: {
  95 + repairId: '',
  96 + repairType: '',
  97 + repairName: '',
  98 + tel: '',
  99 + state: 'waiting'
  100 + },
  101 + repairPools: [],
  102 + repairSettings: [],
  103 + states: [],
  104 + pagination: {
  105 + current: 1,
  106 + size: 10,
  107 + total: 0
  108 + }
  109 + }
  110 + },
  111 + async created() {
  112 + await this.loadDictData()
  113 + this.listRepairPools()
  114 + this.listRepairSettings()
  115 + },
  116 + methods: {
  117 + async loadDictData() {
  118 + try {
  119 + this.states = [{
  120 + value: 'waiting',
  121 + label: '待回访'
  122 + },{
  123 + value: 'finish',
  124 + label: '已回访'
  125 + }]
  126 + } catch (error) {
  127 + console.error('获取字典数据失败:', error)
  128 + }
  129 + },
  130 + async listRepairPools() {
  131 + try {
  132 + this.loading = true
  133 + const params = {
  134 + ...this.searchForm,
  135 + page: this.pagination.current,
  136 + row: this.pagination.size,
  137 + communityId: this.getCommunityId()
  138 + }
  139 +
  140 + // 清理空值
  141 + Object.keys(params).forEach(key => {
  142 + if (params[key] === '') delete params[key]
  143 + })
  144 +
  145 + const { data, total } = await getRepairReturnVisitList(params)
  146 + this.repairPools = data
  147 + this.pagination.total = total
  148 + } catch (error) {
  149 + console.error('查询报修回访列表失败:', error)
  150 + } finally {
  151 + this.loading = false
  152 + }
  153 + },
  154 + async listRepairSettings() {
  155 + try {
  156 + const { data } = await listRepairSettings({
  157 + page: 1,
  158 + row: 50,
  159 + communityId: this.getCommunityId()
  160 + })
  161 + this.repairSettings = data
  162 + } catch (error) {
  163 + console.error('查询报修类型设置失败:', error)
  164 + }
  165 + },
  166 + queryRepairPool() {
  167 + this.pagination.current = 1
  168 + this.listRepairPools()
  169 + },
  170 + resetRepairPool() {
  171 + this.searchForm = {
  172 + repairId: '',
  173 + repairType: '',
  174 + repairName: '',
  175 + tel: '',
  176 + state: ''
  177 + }
  178 + this.queryRepairPool()
  179 + },
  180 + openRepairDetail(repairPool) {
  181 + this.$router.push({
  182 + path: '/pages/property/ownerRepairDetail',
  183 + query: { repairId: repairPool.repairId }
  184 + })
  185 + },
  186 + openEditOwnerRepair(repairPool) {
  187 + this.$refs.visitModal.open(repairPool)
  188 + },
  189 + handleSizeChange(size) {
  190 + this.pagination.size = size
  191 + this.listRepairPools()
  192 + },
  193 + handleCurrentChange(current) {
  194 + this.pagination.current = current
  195 + this.listRepairPools()
  196 + }
  197 + }
  198 +}
  199 +</script>
  200 +
  201 +<style scoped>
  202 +.mt-20 {
  203 + margin-top: 20px;
  204 +}
  205 +</style>
0 206 \ No newline at end of file
... ...
src/views/work/repairSettingList.vue
... ... @@ -102,7 +102,7 @@
102 102 </el-table>
103 103  
104 104 <!-- 分页和说明 -->
105   - <el-row :gutter="20" class="margin-top-xs">
  105 + <el-row :gutter="20" class="margin-top-xs text-left">
106 106 <el-col :span="18">
107 107 <div class="explanation-section">
108 108 <p><strong>{{ $t('repairSetting.dispatchExplanation') }}</strong></p>
... ... @@ -276,14 +276,9 @@ export default {
276 276 }
277 277  
278 278 .explanation-section {
279   - background-color: #f8f9fa;
280   - padding: 15px;
281   - border-radius: 4px;
282 279 font-size: 14px;
283   - line-height: 1.6;
284   -
285 280 p {
286   - margin-bottom: 8px;
  281 + margin-bottom: 2px;
287 282 }
288 283 }
289 284 }
... ...
src/views/work/repairTypeUserList.vue
... ... @@ -43,7 +43,7 @@
43 43 </el-col>
44 44 </el-row>
45 45  
46   - <SelectStaff ref="selectStaff" />
  46 + <SelectStaff ref="selectStaff" @selectStaff="handleSelectStaff"/>
47 47 <DeleteRepairTypeUser ref="deleteRepairTypeUser" @success="handleDeleteSuccess" />
48 48 <EditRepairTypeUser ref="editRepairTypeUser" @success="handleEditSuccess" />
49 49 </div>
... ... @@ -52,7 +52,7 @@
52 52 <script>
53 53 import { listRepairTypeUsers, saveRepairTypeUser } from '@/api/work/repairTypeUserApi'
54 54 import { getCommunityId } from '@/api/community/communityApi'
55   -import SelectStaff from '@/components/work/SelectStaff'
  55 +import SelectStaff from '@/components/staff/SelectStaff'
56 56 import DeleteRepairTypeUser from '@/components/work/DeleteRepairTypeUser'
57 57 import EditRepairTypeUser from '@/components/work/EditRepairTypeUser'
58 58  
... ... @@ -116,11 +116,7 @@ export default {
116 116 this._listRepairTypeUsers(val, this.pageSize)
117 117 },
118 118 _openAddRepairTypeUserModal() {
119   - this.$refs.selectStaff.open({
120   - call: (staff) => {
121   - this.saveRepairTypeUserInfo(staff)
122   - }
123   - })
  119 + this.$refs.selectStaff.open()
124 120 },
125 121 _openEditrepairTypeUserModel(row) {
126 122 this.$refs.editRepairTypeUser.open(row)
... ... @@ -131,6 +127,9 @@ export default {
131 127 _goBack() {
132 128 this.$router.go(-1)
133 129 },
  130 + handleSelectStaff(staff) {
  131 + this.saveRepairTypeUserInfo(staff)
  132 + },
134 133 async saveRepairTypeUserInfo(staff) {
135 134 try {
136 135 const communityId = await getCommunityId()
... ...