Commit e5d4300992114f97527a90f8aab29f38e5edecbf

Authored by wuxw
1 parent caba9d96

测试投诉待办

src/api/oa/complaintDetailApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取投诉详情
  5 +export function getComplaintDetail(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/complaint.listComplaints',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 获取工单流转记录
  24 +export function listComplaintEvent(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/complaint.listComplaintEvent',
  28 + method: 'get',
  29 + params: {
  30 + ...params,
  31 + communityId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 获取工单评价列表
  43 +export function listComplaintAppraise(params) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/complaintAppraise.listComplaintAppraise',
  47 + method: 'get',
  48 + params: {
  49 + ...params,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 回复工单评价
  62 +export function replyComplaintAppraise(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/complaintAppraise.replyComplaintAppraise',
  66 + method: 'post',
  67 + data: {
  68 + ...data,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
  79 +
  80 +// 获取工单类型列表
  81 +export function listComplaintType(params) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/complaintType.listComplaintType',
  85 + method: 'get',
  86 + params: {
  87 + ...params,
  88 + communityId: getCommunityId()
  89 + }
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
0 98 \ No newline at end of file
... ...
src/api/oa/uodoComplaintsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取待办投诉单列表
  5 +export function listAuditComplaints(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/auditUser.listAuditComplaints',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 办理投诉单
  24 +export function auditComplaint(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/complaint.auditComplaint',
  28 + method: 'post',
  29 + data: {
  30 + ...data,
  31 + communityId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 获取投诉单详情
  43 +export function getComplaintDetail(params) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/complaint.getComplaint',
  47 + method: 'get',
  48 + params
  49 + }).then(response => {
  50 + const res = response.data
  51 + resolve(res)
  52 + }).catch(error => {
  53 + reject(error)
  54 + })
  55 + })
  56 +}
0 57 \ No newline at end of file
... ...
src/components/oa/ComplaintDetailAppraise.vue 0 → 100644
  1 +<template>
  2 + <div class="complaint-detail-appraise">
  3 + <el-table
  4 + :data="appraises"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading"
  8 + >
  9 + <el-table-column
  10 + prop="createUserName"
  11 + :label="$t('complaintDetailAppraise.userName')"
  12 + align="center"
  13 + />
  14 + <el-table-column
  15 + prop="context"
  16 + :label="$t('complaintDetailAppraise.content')"
  17 + align="center"
  18 + />
  19 + <el-table-column
  20 + prop="score"
  21 + :label="$t('complaintDetailAppraise.score')"
  22 + align="center"
  23 + />
  24 + <el-table-column
  25 + prop="state"
  26 + :label="$t('complaintDetailAppraise.status')"
  27 + align="center"
  28 + >
  29 + <template slot-scope="scope">
  30 + <span>{{ scope.row.state === 'W' ? $t('complaintDetailAppraise.waitReply') : $t('complaintDetailAppraise.replied') }}</span>
  31 + </template>
  32 + </el-table-column>
  33 + <el-table-column
  34 + prop="createTime"
  35 + :label="$t('complaintDetailAppraise.time')"
  36 + align="center"
  37 + />
  38 + <el-table-column
  39 + prop="replyUserName"
  40 + :label="$t('complaintDetailAppraise.replyUser')"
  41 + align="center"
  42 + />
  43 + <el-table-column
  44 + prop="replyContext"
  45 + :label="$t('complaintDetailAppraise.replyContent')"
  46 + align="center"
  47 + />
  48 + <el-table-column
  49 + :label="$t('common.operation')"
  50 + align="center"
  51 + >
  52 + <template slot-scope="scope">
  53 + <el-button
  54 + v-if="scope.row.state === 'W'"
  55 + type="text"
  56 + size="small"
  57 + @click="openReplyModal(scope.row)"
  58 + >
  59 + {{ $t('complaintDetailAppraise.reply') }}
  60 + </el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 +
  65 + <reply-complaint-appraise
  66 + ref="replyComplaintAppraise"
  67 + @success="handleSuccess"
  68 + />
  69 + </div>
  70 +</template>
  71 +
  72 +<script>
  73 +import { getCommunityId } from '@/api/community/communityApi'
  74 +import { listComplaintAppraise } from '@/api/oa/complaintDetailApi'
  75 +import ReplyComplaintAppraise from './ReplyComplaintAppraise'
  76 +
  77 +export default {
  78 + name: 'ComplaintDetailAppraise',
  79 + components: {
  80 + ReplyComplaintAppraise
  81 + },
  82 + data() {
  83 + return {
  84 + appraises: [],
  85 + loading: false,
  86 + complaintId: '',
  87 + communityId: ''
  88 + }
  89 + },
  90 + methods: {
  91 + async initData(params) {
  92 + this.communityId = getCommunityId()
  93 + this.complaintId = params.complaintId
  94 + await this.loadData()
  95 + },
  96 + async loadData() {
  97 + try {
  98 + this.loading = true
  99 + const params = {
  100 + communityId: this.communityId,
  101 + complaintId: this.complaintId,
  102 + page: 1,
  103 + row: 100
  104 + }
  105 + const { data } = await listComplaintAppraise(params)
  106 + this.appraises = data || []
  107 + } catch (error) {
  108 + console.error('获取工单评价数据失败:', error)
  109 + } finally {
  110 + this.loading = false
  111 + }
  112 + },
  113 + openReplyModal(row) {
  114 + this.$refs.replyComplaintAppraise.open(row)
  115 + },
  116 + handleSuccess() {
  117 + this.loadData()
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style lang="scss" scoped>
  124 +.complaint-detail-appraise {
  125 + margin-top: 20px;
  126 +}
  127 +</style>
0 128 \ No newline at end of file
... ...
src/components/oa/ComplaintDetailEvent.vue 0 → 100644
  1 +<template>
  2 + <div class="complaint-detail-event">
  3 + <el-table :data="events" border style="width: 100%" v-loading="loading">
  4 + <el-table-column prop="eventType" :label="$t('complaintDetailEvent.type')" align="center">
  5 + <template slot-scope="scope">
  6 + <span v-if="scope.row.eventType === '1000'">{{ $t('complaintDetailEvent.submit') }}</span>
  7 + <span v-else-if="scope.row.eventType === '1001'">{{ $t('complaintDetailEvent.process') }}</span>
  8 + <span v-else-if="scope.row.eventType === '2002'">{{ $t('complaintDetailEvent.evaluate') }}</span>
  9 + <span v-else>{{ $t('complaintDetailEvent.reply') }}</span>
  10 + </template>
  11 + </el-table-column>
  12 + <el-table-column prop="createUserName" :label="$t('complaintDetailEvent.operator')" align="center" />
  13 + <el-table-column prop="remark" :label="$t('complaintDetailEvent.remark')" align="center" />
  14 + <el-table-column prop="createTime" :label="$t('complaintDetailEvent.time')" align="center" />
  15 + </el-table>
  16 + </div>
  17 +</template>
  18 +
  19 +<script>
  20 +import { getCommunityId } from '@/api/community/communityApi'
  21 +import { listComplaintEvent } from '@/api/oa/complaintDetailApi'
  22 +
  23 +export default {
  24 + name: 'ComplaintDetailEvent',
  25 + data() {
  26 + return {
  27 + events: [],
  28 + loading: false,
  29 + complaintId: '',
  30 + communityId: ''
  31 + }
  32 + },
  33 + methods: {
  34 + async initData(params) {
  35 + this.communityId = getCommunityId()
  36 + this.complaintId = params.complaintId
  37 + await this.loadData()
  38 + },
  39 + async loadData() {
  40 + try {
  41 + this.loading = true
  42 + const params = {
  43 + communityId: this.communityId,
  44 + complaintId: this.complaintId,
  45 + page: 1,
  46 + row: 100
  47 + }
  48 + const { data } = await listComplaintEvent(params)
  49 + this.events = data || []
  50 + } catch (error) {
  51 + console.error('获取工单流转数据失败:', error)
  52 + } finally {
  53 + this.loading = false
  54 + }
  55 + }
  56 + }
  57 +}
  58 +</script>
  59 +
  60 +<style lang="scss" scoped>
  61 +.complaint-detail-event {
  62 + margin-top: 20px;
  63 +}
  64 +</style>
0 65 \ No newline at end of file
... ...
src/components/oa/ComplaintDetailType.vue 0 → 100644
  1 +<template>
  2 + <div class="complaint-detail-type">
  3 + <el-table
  4 + :data="complaintTypes"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading"
  8 + >
  9 + <el-table-column
  10 + prop="typeName"
  11 + :label="$t('complaintDetailType.typeName')"
  12 + align="center"
  13 + />
  14 + <el-table-column
  15 + prop="notifyWay"
  16 + :label="$t('complaintDetailType.notifyWay')"
  17 + align="center"
  18 + >
  19 + <template slot-scope="scope">
  20 + <span>{{ scope.row.notifyWay === 'SMS' ? $t('complaintDetailType.sms') : $t('complaintDetailType.wechat') }}</span>
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="appraiseReply"
  25 + :label="$t('complaintDetailType.appraiseReply')"
  26 + align="center"
  27 + >
  28 + <template slot-scope="scope">
  29 + <span>{{ scope.row.appraiseReply === 'Y' ? $t('complaintDetailType.autoReply') : $t('complaintDetailType.manualReply') }}</span>
  30 + </template>
  31 + </el-table-column>
  32 + <el-table-column
  33 + :label="$t('complaintDetailType.handler')"
  34 + align="center"
  35 + >
  36 + <template slot-scope="scope">
  37 + <div v-for="(item, index) in scope.row.staffs" :key="index">
  38 + {{ item.staffName }}
  39 + </div>
  40 + </template>
  41 + </el-table-column>
  42 + <el-table-column
  43 + prop="createTime"
  44 + :label="$t('complaintDetailType.createTime')"
  45 + align="center"
  46 + />
  47 + </el-table>
  48 + </div>
  49 +</template>
  50 +
  51 +<script>
  52 +import { getCommunityId } from '@/api/community/communityApi'
  53 +import { listComplaintType } from '@/api/oa/complaintDetailApi'
  54 +
  55 +export default {
  56 + name: 'ComplaintDetailType',
  57 + data() {
  58 + return {
  59 + complaintTypes: [],
  60 + loading: false,
  61 + typeCd: '',
  62 + communityId: ''
  63 + }
  64 + },
  65 + methods: {
  66 + async initData(params) {
  67 + this.communityId = getCommunityId()
  68 + this.typeCd = params.typeCd
  69 + await this.loadData()
  70 + },
  71 + async loadData() {
  72 + try {
  73 + this.loading = true
  74 + const params = {
  75 + communityId: this.communityId,
  76 + typeCd: this.typeCd,
  77 + page: 1,
  78 + row: 100
  79 + }
  80 + const { data } = await listComplaintType(params)
  81 + this.complaintTypes = data || []
  82 + } catch (error) {
  83 + console.error('获取工单类型数据失败:', error)
  84 + } finally {
  85 + this.loading = false
  86 + }
  87 + }
  88 + }
  89 +}
  90 +</script>
  91 +
  92 +<style lang="scss" scoped>
  93 +.complaint-detail-type {
  94 + margin-top: 20px;
  95 +}
  96 +</style>
0 97 \ No newline at end of file
... ...
src/components/oa/ReplyComplaintAppraise.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('replyComplaintAppraise.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="resetForm"
  7 + >
  8 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  9 + <el-form-item :label="$t('replyComplaintAppraise.content')" prop="replyContext">
  10 + <el-input
  11 + type="textarea"
  12 + :rows="5"
  13 + v-model="form.replyContext"
  14 + :placeholder="$t('replyComplaintAppraise.placeholder')"
  15 + />
  16 + </el-form-item>
  17 + </el-form>
  18 +
  19 + <span slot="footer" class="dialog-footer">
  20 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  21 + <el-button type="primary" @click="submitForm" :loading="submitting">
  22 + {{ $t('common.submit') }}
  23 + </el-button>
  24 + </span>
  25 + </el-dialog>
  26 +</template>
  27 +
  28 +<script>
  29 +import { getCommunityId } from '@/api/community/communityApi'
  30 +import { replyComplaintAppraise } from '@/api/oa/complaintDetailApi'
  31 +
  32 +export default {
  33 + name: 'ReplyComplaintAppraise',
  34 + data() {
  35 + return {
  36 + visible: false,
  37 + submitting: false,
  38 + form: {
  39 + appraiseId: '',
  40 + replyContext: '',
  41 + communityId: ''
  42 + },
  43 + rules: {
  44 + replyContext: [
  45 + { required: true, message: this.$t('replyComplaintAppraise.required'), trigger: 'blur' },
  46 + { max: 512, message: this.$t('replyComplaintAppraise.maxLength'), trigger: 'blur' }
  47 + ]
  48 + }
  49 + }
  50 + },
  51 + methods: {
  52 + open(row) {
  53 + this.form.appraiseId = row.appraiseId
  54 + this.form.communityId = getCommunityId()
  55 + this.visible = true
  56 + this.$nextTick(() => {
  57 + this.$refs.form && this.$refs.form.clearValidate()
  58 + })
  59 + },
  60 + async submitForm() {
  61 + try {
  62 + const valid = await this.$refs.form.validate()
  63 + if (!valid) return
  64 +
  65 + this.submitting = true
  66 + await replyComplaintAppraise(this.form)
  67 + this.$message.success(this.$t('replyComplaintAppraise.success'))
  68 + this.visible = false
  69 + this.$emit('success')
  70 + } catch (error) {
  71 + console.error('回复评价失败:', error)
  72 + } finally {
  73 + this.submitting = false
  74 + }
  75 + },
  76 + resetForm() {
  77 + this.form.replyContext = ''
  78 + this.$refs.form && this.$refs.form.clearValidate()
  79 + }
  80 + }
  81 +}
  82 +</script>
0 83 \ No newline at end of file
... ...
src/components/oa/doingComplaint.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('doingComplaint.title')"
  4 + :visible.sync="visible"
  5 + width="60%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="formData" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('doingComplaint.description')"
  11 + prop="context"
  12 + :rules="[
  13 + { required: true, message: $t('doingComplaint.required'), trigger: 'blur' },
  14 + { max: 512, message: $t('doingComplaint.maxLength'), trigger: 'blur' }
  15 + ]"
  16 + >
  17 + <el-input
  18 + v-model="formData.context"
  19 + type="textarea"
  20 + :rows="4"
  21 + :placeholder="$t('doingComplaint.placeholder')"
  22 + />
  23 + </el-form-item>
  24 + </el-form>
  25 +
  26 + <span slot="footer" class="dialog-footer">
  27 + <el-button @click="visible = false">{{ $t('doingComplaint.cancel') }}</el-button>
  28 + <el-button type="primary" @click="handleSubmit">{{ $t('doingComplaint.submit') }}</el-button>
  29 + </span>
  30 + </el-dialog>
  31 +</template>
  32 +
  33 +<script>
  34 +import { auditComplaint } from '@/api/oa/uodoComplaintsApi'
  35 +import { getCommunityId } from '@/api/community/communityApi'
  36 +
  37 +export default {
  38 + name: 'DoingComplaint',
  39 + data() {
  40 + return {
  41 + visible: false,
  42 + formData: {
  43 + complaintId: '',
  44 + context: '',
  45 + communityId: ''
  46 + }
  47 + }
  48 + },
  49 + methods: {
  50 + open(data) {
  51 + this.formData.complaintId = data.complaintId
  52 + this.formData.communityId = getCommunityId()
  53 + this.visible = true
  54 + this.$nextTick(() => {
  55 + this.$refs.form && this.$refs.form.resetFields()
  56 + })
  57 + },
  58 + handleClose() {
  59 + this.$refs.form.resetFields()
  60 + },
  61 + async handleSubmit() {
  62 + try {
  63 + const valid = await this.$refs.form.validate()
  64 + if (!valid) return
  65 +
  66 + await auditComplaint(this.formData)
  67 + this.$emit('success')
  68 + this.visible = false
  69 + this.$message.success(this.$t('doingComplaint.success'))
  70 + } catch (error) {
  71 + console.error(error)
  72 + this.$message.error(this.$t('doingComplaint.error'))
  73 + }
  74 + }
  75 + }
  76 +}
  77 +</script>
  78 +
  79 +<style scoped>
  80 +.el-textarea {
  81 + width: 100%;
  82 +}
  83 +</style>
0 84 \ No newline at end of file
... ...
src/i18n/oaI18n.js
... ... @@ -50,6 +50,8 @@ import { messages as newOaWorkflowMessages } from &#39;../views/oa/newOaWorkflowLang
50 50 import { messages as newOaWorkflowDetailMessages } from '../views/oa/newOaWorkflowDetailLang'
51 51 import { messages as newOaWorkflowFormEditMessages } from '../views/oa/newOaWorkflowFormEditLang'
52 52 import { messages as simplifyNotepadManageMessages } from '../views/oa/simplifyNotepadManageLang'
  53 +import { messages as uodoComplaintsMessages } from '../views/oa/uodoComplaintsLang'
  54 +import { messages as complaintDetailMessages } from '../views/oa/complaintDetailLang'
53 55  
54 56  
55 57 export const messages ={
... ... @@ -105,6 +107,8 @@ export const messages ={
105 107 ...newOaWorkflowDetailMessages.en,
106 108 ...newOaWorkflowFormEditMessages.en,
107 109 ...simplifyNotepadManageMessages.en,
  110 + ...uodoComplaintsMessages.en,
  111 + ...complaintDetailMessages.en,
108 112 },
109 113 zh:{
110 114 ...activitiesTypeManageMessages.zh,
... ... @@ -158,5 +162,7 @@ export const messages ={
158 162 ...newOaWorkflowDetailMessages.zh,
159 163 ...newOaWorkflowFormEditMessages.zh,
160 164 ...simplifyNotepadManageMessages.zh,
  165 + ...uodoComplaintsMessages.zh,
  166 + ...complaintDetailMessages.zh,
161 167 }
162 168 }
163 169 \ No newline at end of file
... ...
src/router/oaRouter.js
... ... @@ -239,4 +239,14 @@ export default [
239 239 name: '/pages/property/simplifyNotepadManage',
240 240 component: () => import('@/views/oa/simplifyNotepadManageList.vue')
241 241 },
  242 + {
  243 + path: '/pages/complaint/uodoComplaints',
  244 + name: '/pages/complaint/uodoComplaints',
  245 + component: () => import('@/views/oa/uodoComplaintsList.vue')
  246 + },
  247 + {
  248 + path: '/pages/complaint/complaintDetail',
  249 + name: '/pages/complaint/complaintDetail',
  250 + component: () => import('@/views/oa/complaintDetailList.vue')
  251 + },
242 252 ]
243 253 \ No newline at end of file
... ...
src/views/oa/complaintDetailLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + complaintDetail: {
  4 + title: 'Complaint Details',
  5 + workflow: 'Workflow',
  6 + evaluation: 'Evaluation',
  7 + type: 'Type'
  8 + },
  9 + complaintDetailInfo: {
  10 + orderNo: 'Order No:',
  11 + type: 'Type:',
  12 + house: 'House:',
  13 + contact: 'Contact:',
  14 + phone: 'Phone:',
  15 + status: 'Status:',
  16 + createTime: 'Create Time:',
  17 + content: 'Content:'
  18 + },
  19 + complaintDetailEvent: {
  20 + type: 'Type',
  21 + operator: 'Operator',
  22 + remark: 'Remark',
  23 + time: 'Time',
  24 + submit: 'Submit',
  25 + process: 'Process',
  26 + evaluate: 'Evaluate',
  27 + reply: 'Reply'
  28 + },
  29 + complaintDetailAppraise: {
  30 + userName: 'User Name',
  31 + content: 'Content',
  32 + score: 'Score',
  33 + status: 'Status',
  34 + time: 'Time',
  35 + replyUser: 'Reply User',
  36 + replyContent: 'Reply Content',
  37 + operation: 'Operation',
  38 + reply: 'Reply',
  39 + waitReply: 'Wait Reply',
  40 + replied: 'Replied'
  41 + },
  42 + replyComplaintAppraise: {
  43 + title: 'Reply Evaluation',
  44 + content: 'Content',
  45 + placeholder: 'Required, please enter reply content',
  46 + required: 'Reply content is required',
  47 + maxLength: 'Reply content exceeds 500 characters',
  48 + success: 'Reply successfully'
  49 + },
  50 + complaintDetailType: {
  51 + typeName: 'Type Name',
  52 + notifyWay: 'Notify Way',
  53 + appraiseReply: 'Appraise Reply',
  54 + handler: 'Handler',
  55 + createTime: 'Create Time',
  56 + sms: 'SMS',
  57 + wechat: 'WeChat',
  58 + autoReply: 'Auto Reply',
  59 + manualReply: 'Manual Reply'
  60 + }
  61 + },
  62 + zh: {
  63 + complaintDetail: {
  64 + title: '投诉详情',
  65 + workflow: '工单流转',
  66 + evaluation: '工单评价',
  67 + type: '工单类型'
  68 + },
  69 + complaintDetailInfo: {
  70 + orderNo: '订单编号:',
  71 + type: '类型:',
  72 + house: '房屋:',
  73 + contact: '联系人:',
  74 + phone: '联系电话:',
  75 + status: '状态:',
  76 + createTime: '创建时间:',
  77 + content: '投诉内容:'
  78 + },
  79 + complaintDetailEvent: {
  80 + type: '类型',
  81 + operator: '操作人',
  82 + remark: '说明',
  83 + time: '时间',
  84 + submit: '提交',
  85 + process: '投诉处理',
  86 + evaluate: '评价',
  87 + reply: '评价回复'
  88 + },
  89 + complaintDetailAppraise: {
  90 + userName: '用户名称',
  91 + content: '评价内容',
  92 + score: '评价得分',
  93 + status: '评价状态',
  94 + time: '评价时间',
  95 + replyUser: '回复人',
  96 + replyContent: '回复内容',
  97 + operation: '操作',
  98 + reply: '回复',
  99 + waitReply: '待回复',
  100 + replied: '已回复'
  101 + },
  102 + replyComplaintAppraise: {
  103 + title: '回复评价',
  104 + content: '内容',
  105 + placeholder: '必填,请填写回复内容',
  106 + required: '回复内容不能为空',
  107 + maxLength: '回复内容超过500个字',
  108 + success: '回复成功'
  109 + },
  110 + complaintDetailType: {
  111 + typeName: '类型名称',
  112 + notifyWay: '通知方式',
  113 + appraiseReply: '评价回复',
  114 + handler: '处理人',
  115 + createTime: '创建时间',
  116 + sms: '短信',
  117 + wechat: '微信',
  118 + autoReply: '自动回复',
  119 + manualReply: '人工回复'
  120 + }
  121 + }
  122 +}
0 123 \ No newline at end of file
... ...
src/views/oa/complaintDetailList.vue 0 → 100644
  1 +<template>
  2 + <div class="complaint-detail-container">
  3 + <el-card class="box-card">
  4 + <div class="flex justify-between">
  5 + <div class="text-title">{{ $t('complaintDetail.title') }}</div>
  6 + <div>
  7 + <el-button type="primary" size="small" style="margin-left:10px" @click="goBack">
  8 + {{ $t('common.back') }}
  9 + </el-button>
  10 + </div>
  11 + </div>
  12 +
  13 + <!-- 业主信息 -->
  14 + <div class="margin-top">
  15 + <el-row :gutter="20" class="text-left">
  16 + <el-col :span="24">
  17 + <el-row :gutter="20">
  18 + <el-col :span="6">
  19 + <div class="form-group">
  20 + <label class="col-form-label">
  21 + {{ $t('complaintDetailInfo.orderNo') }}
  22 + </label>
  23 + <label class="">{{complaintDetailInfo.complaintId}}</label>
  24 + </div>
  25 + </el-col>
  26 + <el-col :span="6">
  27 + <div class="form-group">
  28 + <label class="col-form-label">
  29 + {{ $t('complaintDetailInfo.type') }}
  30 + </label>
  31 + <label class="">{{complaintDetailInfo.typeName}}</label>
  32 + </div>
  33 + </el-col>
  34 + <el-col :span="6">
  35 + <div class="form-group">
  36 + <label class="col-form-label">
  37 + {{ $t('complaintDetailInfo.house') }}
  38 + </label>
  39 + <label class="">
  40 + {{complaintDetailInfo.roomName}}
  41 + </label>
  42 + </div>
  43 + </el-col>
  44 + <el-col :span="6">
  45 + <div class="form-group">
  46 + <label class="col-form-label">
  47 + {{ $t('complaintDetailInfo.contact') }}
  48 + </label>
  49 + <label class="">{{complaintDetailInfo.complaintName}}</label>
  50 + </div>
  51 + </el-col>
  52 + </el-row>
  53 + <el-row :gutter="20">
  54 + <el-col :span="6">
  55 + <div class="form-group">
  56 + <label class="col-form-label">
  57 + {{ $t('complaintDetailInfo.phone') }}
  58 + </label>
  59 + <label class="">{{complaintDetailInfo.tel}}</label>
  60 + </div>
  61 + </el-col>
  62 + <el-col :span="6">
  63 + <div class="form-group">
  64 + <label class="col-form-label">
  65 + {{ $t('complaintDetailInfo.status') }}
  66 + </label>
  67 + <label class="">{{complaintDetailInfo.stateName}}</label>
  68 + </div>
  69 + </el-col>
  70 + <el-col :span="12">
  71 + <div class="form-group">
  72 + <label class="col-form-label">
  73 + {{ $t('complaintDetailInfo.createTime') }}
  74 + </label>
  75 + <label class="">{{complaintDetailInfo.createTime}}</label>
  76 + </div>
  77 + </el-col>
  78 + <el-col :span="24">
  79 + <div class="form-group">
  80 + <label class="col-form-label">
  81 + {{ $t('complaintDetailInfo.content') }}
  82 + </label>
  83 + <label class="">{{complaintDetailInfo.context}}</label>
  84 + </div>
  85 + </el-col>
  86 + </el-row>
  87 + </el-col>
  88 + </el-row>
  89 + </div>
  90 +
  91 + <divider></divider>
  92 +
  93 + <div class="margin-top-sm">
  94 + <el-tabs v-model="complaintDetailInfo._currentTab" @tab-click="changeTab(complaintDetailInfo._currentTab)">
  95 + <el-tab-pane :label="$t('complaintDetail.workflow')" name="complaintDetailEvent">
  96 + <complaint-detail-event v-if="complaintDetailInfo._currentTab === 'complaintDetailEvent'"
  97 + ref="complaintDetailEvent" />
  98 + </el-tab-pane>
  99 + <el-tab-pane :label="$t('complaintDetail.evaluation')" name="complaintDetailAppraise">
  100 + <complaint-detail-appraise v-if="complaintDetailInfo._currentTab === 'complaintDetailAppraise'"
  101 + ref="complaintDetailAppraise" />
  102 + </el-tab-pane>
  103 + <el-tab-pane :label="$t('complaintDetail.type')" name="complaintDetailType">
  104 + <complaint-detail-type v-if="complaintDetailInfo._currentTab === 'complaintDetailType'"
  105 + ref="complaintDetailType" />
  106 + </el-tab-pane>
  107 + </el-tabs>
  108 + </div>
  109 + </el-card>
  110 + </div>
  111 +</template>
  112 +
  113 +<script>
  114 +import { getCommunityId } from '@/api/community/communityApi'
  115 +import ComplaintDetailEvent from '@/components/oa/ComplaintDetailEvent'
  116 +import ComplaintDetailAppraise from '@/components/oa/ComplaintDetailAppraise'
  117 +import ComplaintDetailType from '@/components/oa/ComplaintDetailType'
  118 +import { getComplaintDetail } from '@/api/oa/complaintDetailApi'
  119 +import divider from '@/components/system/divider'
  120 +
  121 +export default {
  122 + name: 'ComplaintDetailList',
  123 + components: {
  124 + ComplaintDetailEvent,
  125 + ComplaintDetailAppraise,
  126 + ComplaintDetailType,
  127 + divider
  128 + },
  129 + data() {
  130 + return {
  131 + complaintDetailInfo: {
  132 + viewComplaintFlag: '',
  133 + complaintId: "",
  134 + typeName: '',
  135 + typeCd: '',
  136 + roomName: "",
  137 + complaintName: "",
  138 + tel: "",
  139 + stateName: "",
  140 + createTime: "",
  141 + context: '',
  142 + _currentTab: 'complaintDetailEvent',
  143 + },
  144 + communityId: ''
  145 + }
  146 + },
  147 + created() {
  148 + this.communityId = getCommunityId()
  149 + this.complaintDetailInfo.complaintId = this.$route.query.complaintId
  150 + if (!this.complaintDetailInfo.complaintId) {
  151 + return
  152 + }
  153 + const currentTab = this.$route.query.currentTab
  154 + if (currentTab) {
  155 + this.complaintDetailInfo._currentTab = currentTab
  156 + }
  157 + this.loadComplaintInfo()
  158 + },
  159 + methods: {
  160 + async loadComplaintInfo() {
  161 + try {
  162 + const params = {
  163 + complaintId: this.complaintDetailInfo.complaintId,
  164 + page: 1,
  165 + row: 1,
  166 + communityId: this.communityId,
  167 + ownerTypeCd: '1001'
  168 + }
  169 + const { data } = await getComplaintDetail(params)
  170 + if (data && data.length > 0) {
  171 + Object.assign(this.complaintDetailInfo, data[0])
  172 + }
  173 + } catch (error) {
  174 + console.error('获取投诉详情失败:', error)
  175 + }
  176 + },
  177 + changeTab(tab) {
  178 + this.complaintDetailInfo._currentTab = tab
  179 + setTimeout(() => {
  180 + if (this.$refs[tab]) {
  181 + this.$refs[tab].initData({
  182 + complaintId: this.complaintDetailInfo.complaintId,
  183 + typeCd: this.complaintDetailInfo.typeCd
  184 + })
  185 + }
  186 + }, 500)
  187 + },
  188 + goBack() {
  189 + this.$router.go(-1)
  190 + }
  191 + }
  192 +}
  193 +</script>
  194 +
  195 +<style lang="scss" scoped>
  196 +.complaint-detail-container {
  197 + padding: 20px;
  198 +
  199 + .box-card {
  200 + padding: 20px;
  201 + }
  202 +
  203 + .text-title {
  204 + font-size: 18px;
  205 + font-weight: bold;
  206 + color: #333;
  207 + }
  208 +
  209 + .margin-top {
  210 + margin-top: 20px;
  211 + }
  212 +
  213 + .margin-top-sm {
  214 + margin-top: 10px;
  215 + }
  216 +
  217 + .form-group {
  218 + margin-bottom: 15px;
  219 +
  220 + .col-form-label {
  221 + margin-bottom: 5px;
  222 + color: #606266;
  223 + }
  224 + }
  225 +}
  226 +</style>
0 227 \ No newline at end of file
... ...
src/views/oa/complaintList.vue
... ... @@ -204,7 +204,7 @@ export default {
204 204 this.$refs.deleteComplaint.open(row)
205 205 },
206 206 _openComplaintDetailModel(row) {
207   - this.$refs.complaintDetail.open(row)
  207 + this.$router.push(`/pages/complaint/complaintDetail?complaintId=${row.complaintId}`)
208 208 },
209 209 _queryComplaintMethod() {
210 210 this.page.current = 1
... ...
src/views/oa/uodoComplaintsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + uodoComplaints: {
  4 + title: 'Pending Complaints',
  5 + back: 'Back',
  6 + refresh: 'Refresh',
  7 + orderNumber: 'Order Number',
  8 + complaintType: 'Complaint Type',
  9 + house: 'House',
  10 + complainant: 'Complainant',
  11 + complaintPhone: 'Complaint Phone',
  12 + complaintStatus: 'Complaint Status',
  13 + createTime: 'Create Time',
  14 + operation: 'Operation',
  15 + process: 'Process',
  16 + detail: 'Detail',
  17 + fetchError: 'Failed to fetch complaints data'
  18 + },
  19 + doingComplaint: {
  20 + title: 'Process Complaint',
  21 + description: 'Description',
  22 + required: 'Required, please fill in the reply content',
  23 + maxLength: 'Reply content exceeds 500 characters',
  24 + placeholder: 'Required, please fill in the reply content',
  25 + cancel: 'Cancel',
  26 + submit: 'Submit',
  27 + success: 'Processed successfully',
  28 + error: 'Failed to process complaint'
  29 + }
  30 + },
  31 + zh: {
  32 + uodoComplaints: {
  33 + title: '待办投诉单',
  34 + back: '返回',
  35 + refresh: '刷新',
  36 + orderNumber: '订单编号',
  37 + complaintType: '投诉类型',
  38 + house: '房屋',
  39 + complainant: '投诉人',
  40 + complaintPhone: '投诉电话',
  41 + complaintStatus: '投诉状态',
  42 + createTime: '创建时间',
  43 + operation: '操作',
  44 + process: '办理',
  45 + detail: '详情',
  46 + fetchError: '获取投诉数据失败'
  47 + },
  48 + doingComplaint: {
  49 + title: '办理投诉',
  50 + description: '说明',
  51 + required: '必填,请填写回复内容',
  52 + maxLength: '回复内容超过500个字',
  53 + placeholder: '必填,请填写回复内容',
  54 + cancel: '取消',
  55 + submit: '提交',
  56 + success: '办理成功',
  57 + error: '办理投诉失败'
  58 + }
  59 + }
  60 +}
0 61 \ No newline at end of file
... ...
src/views/oa/uodoComplaintsList.vue 0 → 100644
  1 +<template>
  2 + <div class="uodo-complaints-container animated fadeInRight">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between ">
  5 + <span>{{ $t('uodoComplaints.title') }}</span>
  6 + <div class="card-header-actions">
  7 + <el-button size="small" @click="handleGoBack">{{ $t('uodoComplaints.back') }}</el-button>
  8 + <el-button type="primary" size="small" @click="handleRefresh">{{ $t('uodoComplaints.refresh') }}</el-button>
  9 + </div>
  10 + </div>
  11 +
  12 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  13 + <el-table-column prop="complaintId" :label="$t('uodoComplaints.orderNumber')" align="center" />
  14 + <el-table-column prop="typeName" :label="$t('uodoComplaints.complaintType')" align="center" />
  15 + <el-table-column prop="roomName" :label="$t('uodoComplaints.house')" align="center" />
  16 + <el-table-column prop="complaintName" :label="$t('uodoComplaints.complainant')" align="center" />
  17 + <el-table-column prop="tel" :label="$t('uodoComplaints.complaintPhone')" align="center" />
  18 + <el-table-column prop="stateName" :label="$t('uodoComplaints.complaintStatus')" align="center" />
  19 + <el-table-column prop="createTime" :label="$t('uodoComplaints.createTime')" align="center" />
  20 + <el-table-column :label="$t('uodoComplaints.operation')" align="center" width="180">
  21 + <template slot-scope="scope">
  22 + <el-button-group>
  23 + <el-button size="mini" @click="handleProcess(scope.row)">{{ $t('uodoComplaints.process') }}</el-button>
  24 + <el-button size="mini" @click="handleDetail(scope.row)">{{ $t('uodoComplaints.detail') }}</el-button>
  25 + </el-button-group>
  26 + </template>
  27 + </el-table-column>
  28 + </el-table>
  29 +
  30 + <el-pagination :current-page="pagination.currentPage" :page-sizes="[10, 20, 30, 50]"
  31 + :page-size="pagination.pageSize" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
  32 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  33 + </el-card>
  34 +
  35 + <doing-complaint ref="doingComplaint" @success="handleSuccess" />
  36 + </div>
  37 +</template>
  38 +
  39 +<script>
  40 +import { listAuditComplaints } from '@/api/oa/uodoComplaintsApi'
  41 +import DoingComplaint from '@/components/oa/doingComplaint'
  42 +import { getCommunityId } from '@/api/community/communityApi'
  43 +
  44 +export default {
  45 + name: 'UodoComplaintsList',
  46 + components: {
  47 + DoingComplaint
  48 + },
  49 + data() {
  50 + return {
  51 + loading: false,
  52 + tableData: [],
  53 + pagination: {
  54 + currentPage: 1,
  55 + pageSize: 10,
  56 + total: 0
  57 + },
  58 + conditions: {
  59 + communityId: '',
  60 + userName: '',
  61 + auditLink: ''
  62 + }
  63 + }
  64 + },
  65 + created() {
  66 + this.communityId = getCommunityId()
  67 + this.getList()
  68 + },
  69 + methods: {
  70 + async getList() {
  71 + try {
  72 + this.loading = true
  73 + const params = {
  74 + page: this.pagination.currentPage,
  75 + row: this.pagination.pageSize,
  76 + communityId: this.communityId,
  77 + ...this.conditions
  78 + }
  79 + const { data, total } = await listAuditComplaints(params)
  80 + this.tableData = data
  81 + this.pagination.total = total
  82 + } catch (error) {
  83 + this.$message.error(this.$t('uodoComplaints.fetchError'))
  84 + } finally {
  85 + this.loading = false
  86 + }
  87 + },
  88 + handleGoBack() {
  89 + this.$router.go(-1)
  90 + },
  91 + handleRefresh() {
  92 + this.pagination.currentPage = 1
  93 + this.getList()
  94 + },
  95 + handleProcess(row) {
  96 + this.$refs.doingComplaint.open(row)
  97 + },
  98 + handleDetail(row) {
  99 + this.$router.push(`/pages/complaint/complaintDetail?complaintId=${row.complaintId}`)
  100 + },
  101 + handleSuccess() {
  102 + this.getList()
  103 + },
  104 + handleSizeChange(val) {
  105 + this.pagination.pageSize = val
  106 + this.getList()
  107 + },
  108 + handleCurrentChange(val) {
  109 + this.pagination.currentPage = val
  110 + this.getList()
  111 + }
  112 + }
  113 +}
  114 +</script>
  115 +
  116 +<style lang="scss" scoped>
  117 +.uodo-complaints-container {
  118 + padding: 20px;
  119 +
  120 + .box-card {
  121 + margin-bottom: 20px;
  122 + }
  123 +
  124 + .card-header-actions {
  125 + float: right;
  126 + }
  127 +
  128 + .el-pagination {
  129 + margin-top: 20px;
  130 + text-align: right;
  131 + }
  132 +}
  133 +</style>
0 134 \ No newline at end of file
... ...