Commit 2e0fd29c4bee2d330d3f72a09922c2b446bf70f3

Authored by wuxw
1 parent 2c760b97

开发报修

src/api/fee/carCreateFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询车辆收费信息
  5 +export function listCarCreateFees(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const communityId = getCommunityId()
  8 + request({
  9 + url: '/owner.queryOwnerCars',
  10 + method: 'get',
  11 + params: {
  12 + ...params,
  13 + communityId
  14 + }
  15 + }).then(response => {
  16 + const res = response.data
  17 + if (res.code === 0) {
  18 + resolve(res)
  19 + } else {
  20 + reject(new Error(res.msg || '查询车辆收费信息失败'))
  21 + }
  22 + }).catch(error => {
  23 + reject(error)
  24 + })
  25 + })
  26 +}
  27 +
  28 +// 保存停车位收费信息
  29 +export function saveParkingSpaceCreateFee(data) {
  30 + return new Promise((resolve, reject) => {
  31 + const communityId = getCommunityId()
  32 + request({
  33 + url: '/fee.saveParkingSpaceCreateFee',
  34 + method: 'post',
  35 + data: {
  36 + ...data,
  37 + communityId
  38 + }
  39 + }).then(response => {
  40 + const res = response.data
  41 +
  42 + resolve(res)
  43 + }).catch(error => {
  44 + reject(error)
  45 + })
  46 + })
  47 +}
  48 +
  49 +// 查询费用配置列表
  50 +export function listFeeConfigs(params) {
  51 + return new Promise((resolve, reject) => {
  52 + const communityId = getCommunityId()
  53 + request({
  54 + url: '/feeConfig.listFeeConfigs',
  55 + method: 'get',
  56 + params: {
  57 + ...params,
  58 + communityId
  59 + }
  60 + }).then(response => {
  61 + const res = response.data
  62 + resolve(res)
  63 + }).catch(error => {
  64 + reject(error)
  65 + })
  66 + })
  67 +}
  68 +
  69 +// 查询停车场列表
  70 +export function listParkingAreas(params) {
  71 + return new Promise((resolve, reject) => {
  72 + const communityId = getCommunityId()
  73 + request({
  74 + url: '/parkingArea.listParkingAreas',
  75 + method: 'get',
  76 + params: {
  77 + ...params,
  78 + communityId
  79 + }
  80 + }).then(response => {
  81 + const res = response.data
  82 + resolve(res)
  83 + }).catch(error => {
  84 + reject(error)
  85 + })
  86 + })
  87 +}
  88 +
  89 +// 导出车辆收费Excel
  90 +export function exportCarFeeExcel(params) {
  91 + return new Promise((resolve, reject) => {
  92 + const communityId = getCommunityId()
  93 + request({
  94 + url: '/callComponent/importAndExportFee/exportData',
  95 + method: 'get',
  96 + params: {
  97 + ...params,
  98 + communityId,
  99 + type: '2002'
  100 + }
  101 + }).then(response => {
  102 + resolve(response)
  103 + }).catch(error => {
  104 + reject(error)
  105 + })
  106 + })
  107 +}
  108 +
  109 +// 导入自定义费用
  110 +export function importCustomFee(data) {
  111 + return new Promise((resolve, reject) => {
  112 + const communityId = getCommunityId()
  113 + const formData = new FormData()
  114 + formData.append('uploadFile', data.file)
  115 + formData.append('communityId', communityId)
  116 + formData.append('importAdapt', 'importCustomFee')
  117 +
  118 + request({
  119 + url: '/callComponent/upload/assetImport/importData',
  120 + method: 'post',
  121 + data: formData,
  122 + headers: {
  123 + 'Content-Type': 'multipart/form-data'
  124 + }
  125 + }).then(response => {
  126 + const res = response.data
  127 + if (res.code === 0) {
  128 + resolve(res)
  129 + } else {
  130 + reject(new Error(res.msg || '导入自定义费用失败'))
  131 + }
  132 + }).catch(error => {
  133 + reject(error)
  134 + })
  135 + })
  136 +}
0 137 \ No newline at end of file
... ...
src/api/fee/listCarFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询费用列表
  4 +export function listFee(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/fee.listFee',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve(res)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 删除费用
  20 +export function deleteFee(data) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/fee.deleteFee',
  24 + method: 'post',
  25 + data
  26 + }).then(response => {
  27 + const res = response.data
  28 +
  29 + resolve(res)
  30 + }).catch(error => {
  31 + reject(error)
  32 + })
  33 + })
  34 +}
  35 +
  36 +// 更新费用
  37 +export function updateFee(data) {
  38 + return new Promise((resolve, reject) => {
  39 + request({
  40 + url: '/fee.updateFee',
  41 + method: 'post',
  42 + data
  43 + }).then(response => {
  44 + const res = response.data
  45 +
  46 + resolve(res)
  47 + }).catch(error => {
  48 + reject(error)
  49 + })
  50 + })
  51 +}
  52 +
  53 +// 拆分费用
  54 +export function splitFee(data) {
  55 + return new Promise((resolve, reject) => {
  56 + request({
  57 + url: '/feeSub.splitPayFee',
  58 + method: 'post',
  59 + data
  60 + }).then(response => {
  61 + const res = response.data
  62 +
  63 + resolve(res)
  64 + }).catch(error => {
  65 + reject(error)
  66 + })
  67 + })
  68 +}
  69 +
  70 +// 保存车位费用
  71 +export function saveParkingSpaceCreateFee(data) {
  72 + return new Promise((resolve, reject) => {
  73 + request({
  74 + url: '/fee.saveParkingSpaceCreateFee',
  75 + method: 'post',
  76 + data
  77 + }).then(response => {
  78 + const res = response.data
  79 +
  80 + resolve(res)
  81 + }).catch(error => {
  82 + reject(error)
  83 + })
  84 + })
  85 +}
  86 +
  87 +// 保存抄表
  88 +export function saveMeterWater(data) {
  89 + return new Promise((resolve, reject) => {
  90 + request({
  91 + url: '/meterWater.saveMeterWater',
  92 + method: 'post',
  93 + data
  94 + }).then(response => {
  95 + const res = response.data
  96 +
  97 + resolve(res)
  98 + }).catch(error => {
  99 + reject(error)
  100 + })
  101 + })
  102 +}
  103 +
  104 +// 查询抄表
  105 +export function queryPreMeterWater(params) {
  106 + return new Promise((resolve, reject) => {
  107 + request({
  108 + url: '/meterWater/queryPreMeterWater',
  109 + method: 'get',
  110 + params
  111 + }).then(response => {
  112 + const res = response.data
  113 +
  114 + resolve(res)
  115 + }).catch(error => {
  116 + reject(error)
  117 + })
  118 + })
  119 +}
  120 +
  121 +// 查询费用配置
  122 +export function listFeeConfigs(params) {
  123 + return new Promise((resolve, reject) => {
  124 + request({
  125 + url: '/feeConfig.listFeeConfigs',
  126 + method: 'get',
  127 + params
  128 + }).then(response => {
  129 + const res = response.data
  130 + resolve(res)
  131 + }).catch(error => {
  132 + reject(error)
  133 + })
  134 + })
  135 +}
  136 +
  137 +// 查询停车场
  138 +export function listParkingAreas(params) {
  139 + return new Promise((resolve, reject) => {
  140 + request({
  141 + url: '/parkingArea.listParkingAreas',
  142 + method: 'get',
  143 + params
  144 + }).then(response => {
  145 + const res = response.data
  146 + resolve(res)
  147 + }).catch(error => {
  148 + reject(error)
  149 + })
  150 + })
  151 +}
  152 +
  153 +// 查询楼栋
  154 +export function queryFloors(params) {
  155 + return new Promise((resolve, reject) => {
  156 + request({
  157 + url: '/floor.queryFloors',
  158 + method: 'get',
  159 + params
  160 + }).then(response => {
  161 + const res = response.data
  162 + resolve(res)
  163 + }).catch(error => {
  164 + reject(error)
  165 + })
  166 + })
  167 +}
  168 +
  169 +// 查询单元
  170 +export function queryUnits(params) {
  171 + return new Promise((resolve, reject) => {
  172 + request({
  173 + url: '/unit.queryUnits',
  174 + method: 'get',
  175 + params
  176 + }).then(response => {
  177 + const res = response.data
  178 + resolve(res)
  179 + }).catch(error => {
  180 + reject(error)
  181 + })
  182 + })
  183 +}
  184 +
  185 +// 查询房屋
  186 +export function queryRooms(params) {
  187 + return new Promise((resolve, reject) => {
  188 + request({
  189 + url: '/room.queryRooms',
  190 + method: 'get',
  191 + params
  192 + }).then(response => {
  193 + const res = response.data
  194 + resolve(res)
  195 + }).catch(error => {
  196 + reject(error)
  197 + })
  198 + })
  199 +}
  200 +
  201 +// 查询抄表类型
  202 +export function listMeterType(params) {
  203 + return new Promise((resolve, reject) => {
  204 + request({
  205 + url: '/meterType.listMeterType',
  206 + method: 'get',
  207 + params
  208 + }).then(response => {
  209 + const res = response.data
  210 + resolve(res)
  211 + }).catch(error => {
  212 + reject(error)
  213 + })
  214 + })
  215 +}
0 216 \ No newline at end of file
... ...
src/api/work/repairSettingApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取报修设置列表
  5 +export function listRepairSettings(params) {
  6 + return new Promise((resolve, reject) => {
  7 + params.communityId = getCommunityId()
  8 + request({
  9 + url: '/repair.listRepairSettings',
  10 + method: 'get',
  11 + params
  12 + }).then(response => {
  13 + const res = response.data
  14 + if (res.code === 0) {
  15 + resolve(res)
  16 + } else {
  17 + reject(new Error(res.msg || '获取报修设置列表失败'))
  18 + }
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
  24 +
  25 +// 添加报修设置
  26 +export function saveRepairSetting(data) {
  27 + return new Promise((resolve, reject) => {
  28 + data.communityId = getCommunityId()
  29 + request({
  30 + url: '/repair.saveRepairSetting',
  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 updateRepairSetting(data) {
  48 + return new Promise((resolve, reject) => {
  49 + data.communityId = getCommunityId()
  50 + request({
  51 + url: '/repair.updateRepairSetting',
  52 + method: 'post',
  53 + data
  54 + }).then(response => {
  55 + const res = response.data
  56 + if (res.code === 0) {
  57 + resolve(res)
  58 + } else {
  59 + reject(new Error(res.msg || '更新报修设置失败'))
  60 + }
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 删除报修设置
  68 +export function deleteRepairSetting(settingId) {
  69 + return new Promise((resolve, reject) => {
  70 + const data = {
  71 + settingId,
  72 + communityId: getCommunityId()
  73 + }
  74 + request({
  75 + url: '/repair.deleteRepairSetting',
  76 + method: 'post',
  77 + data
  78 + }).then(response => {
  79 + const res = response.data
  80 + if (res.code === 0) {
  81 + resolve(res)
  82 + } else {
  83 + reject(new Error(res.msg || '删除报修设置失败'))
  84 + }
  85 + }).catch(error => {
  86 + reject(error)
  87 + })
  88 + })
  89 +}
  90 +
  91 +// 获取字典数据
  92 +export function getDict(dictType, state) {
  93 + return new Promise((resolve, reject) => {
  94 + request({
  95 + url: '/dict.getDict',
  96 + method: 'get',
  97 + params: {
  98 + dictType,
  99 + state,
  100 + communityId: getCommunityId()
  101 + }
  102 + }).then(response => {
  103 + const res = response.data
  104 + if (res.code === 0) {
  105 + resolve(res.data)
  106 + } else {
  107 + reject(new Error(res.msg || '获取字典数据失败'))
  108 + }
  109 + }).catch(error => {
  110 + reject(error)
  111 + })
  112 + })
  113 +}
0 114 \ No newline at end of file
... ...
src/api/work/repairTypeUserApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取报修师傅列表
  5 +export function listRepairTypeUsers(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/repair.listRepairTypeUsers',
  9 + method: 'get',
  10 + params
  11 + }).then(response => {
  12 + resolve(response.data)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 保存报修师傅
  20 +export function saveRepairTypeUser(data) {
  21 + data.communityId = getCommunityId()
  22 + return new Promise((resolve, reject) => {
  23 + request({
  24 + url: '/repair.saveRepairTypeUser',
  25 + method: 'post',
  26 + data
  27 + }).then(response => {
  28 + resolve(response.data)
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +// 更新报修师傅
  36 +export function updateRepairTypeUser(data) {
  37 + data.communityId = getCommunityId()
  38 +
  39 + return new Promise((resolve, reject) => {
  40 + request({
  41 + url: '/repair/updateRepairTypeUser',
  42 + method: 'post',
  43 + data
  44 + }).then(response => {
  45 + resolve(response.data)
  46 + }).catch(error => {
  47 + reject(error)
  48 + })
  49 + })
  50 +}
  51 +
  52 +// 删除报修师傅
  53 +export function deleteRepairTypeUser(data) {
  54 + data.communityId = getCommunityId()
  55 +
  56 + return new Promise((resolve, reject) => {
  57 + request({
  58 + url: '/repair/deleteRepairTypeUser',
  59 + method: 'post',
  60 + data
  61 + }).then(response => {
  62 + resolve(response.data)
  63 + }).catch(error => {
  64 + reject(error)
  65 + })
  66 + })
  67 +}
  68 +
  69 +// 获取组织树
  70 +export function listOrgTree(params) {
  71 +
  72 + return new Promise((resolve, reject) => {
  73 + request({
  74 + url: '/org/listOrgTree',
  75 + method: 'get',
  76 + params
  77 + }).then(response => {
  78 + resolve(response.data)
  79 + }).catch(error => {
  80 + reject(error)
  81 + })
  82 + })
  83 +}
  84 +
  85 +// 获取员工信息
  86 +export function getStaffInfos(params) {
  87 + return new Promise((resolve, reject) => {
  88 + request({
  89 + url: '/query.staff.infos',
  90 + method: 'get',
  91 + params
  92 + }).then(response => {
  93 + resolve(response.data)
  94 + }).catch(error => {
  95 + reject(error)
  96 + })
  97 + })
  98 +}
0 99 \ No newline at end of file
... ...
src/components/fee/carCreateFeeAdd.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('carCreateFeeAdd.createFee')" :visible.sync="visible" width="50%" @close="handleClose">
  3 + <el-form :model="form" label-width="150px" ref="form">
  4 + <el-form-item v-if="isMore" :label="$t('carCreateFeeAdd.chargeScope')" prop="locationTypeCd"
  5 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredChargeScope') }]">
  6 + <el-select v-model="form.locationTypeCd" style="width:100%">
  7 + <el-option :label="$t('carCreateFeeAdd.community')" value="1000" />
  8 + <el-option :label="$t('carCreateFeeAdd.parkingLot')" value="3000" />
  9 + </el-select>
  10 + </el-form-item>
  11 +
  12 + <el-form-item v-else :label="$t('carCreateFeeAdd.vehicle')" prop="locationTypeCdName">
  13 + <el-input v-model="form.locationTypeCdName" disabled :placeholder="$t('carCreateFeeAdd.requiredChargeScope')" />
  14 + </el-form-item>
  15 +
  16 + <el-form-item v-if="form.locationTypeCd === '3000' && isMore" :label="$t('carCreateFeeAdd.parkingLot')" prop="paId">
  17 + <parking-area-select2 @change="handleParkingAreaChange" />
  18 + </el-form-item>
  19 +
  20 + <el-form-item :label="$t('carCreateFeeAdd.feeType')" prop="feeTypeCd"
  21 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredFeeType') }]">
  22 + <el-select v-model="form.feeTypeCd" @change="handleFeeTypeChange" style="width:100%">
  23 + <template v-for="item in feeTypeCds">
  24 + <el-option :key="item.statusCd" :label="item.name" :value="item.statusCd"
  25 + v-if="item.statusCd !== '888800010001' && item.statusCd !== '888800010009' && item.statusCd !== '888800010011'" />
  26 + </template>
  27 + </el-select>
  28 + </el-form-item>
  29 +
  30 + <el-form-item :label="$t('carCreateFeeAdd.feeItem')" prop="configId"
  31 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredFeeItem') }]">
  32 + <el-select v-model="form.configId" @change="handleConfigChange" style="width:100%">
  33 + <el-option v-for="item in feeConfigs" :key="item.configId" :label="item.feeName" :value="item.configId" />
  34 + </el-select>
  35 + </el-form-item>
  36 +
  37 + <el-form-item v-if="form.computingFormula === '4004'" :label="$t('carCreateFeeAdd.chargeAmount')" prop="amount"
  38 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredChargeAmount') }]">
  39 + <el-input v-model="form.amount" />
  40 + </el-form-item>
  41 +
  42 + <el-form-item v-if="isMore" :label="$t('carCreateFeeAdd.parkingSpaceStatus')" prop="carState">
  43 + <el-checkbox-group v-model="form.carState">
  44 + <el-checkbox label="S">{{ $t('carCreateFeeAdd.sold') }}</el-checkbox>
  45 + <el-checkbox label="H">{{ $t('carCreateFeeAdd.rented') }}</el-checkbox>
  46 + </el-checkbox-group>
  47 + </el-form-item>
  48 +
  49 + <el-form-item :label="$t('carCreateFeeAdd.startTime')" prop="startTime"
  50 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredStartTime') }]">
  51 + <el-date-picker v-model="form.startTime" type="date" value-format="yyyy-MM-dd" style="width:100%"
  52 + :placeholder="$t('carCreateFeeAdd.requiredStartTime')" />
  53 + </el-form-item>
  54 +
  55 + <el-form-item :label="$t('carCreateFeeAdd.endTime')" prop="endTime"
  56 + :rules="[{ required: true, message: $t('carCreateFeeAdd.requiredEndTime') }]">
  57 + <el-date-picker v-model="form.endTime" type="date" value-format="yyyy-MM-dd" style="width:100%"
  58 + :placeholder="$t('carCreateFeeAdd.requiredEndTime')" />
  59 + </el-form-item>
  60 + </el-form>
  61 +
  62 + <div slot="footer" class="dialog-footer">
  63 + <el-button @click="visible = false">{{ $t('carCreateFeeAdd.cancel') }}</el-button>
  64 + <el-button type="primary" @click="handleSubmit">{{ $t('carCreateFeeAdd.submit') }}</el-button>
  65 + </div>
  66 + </el-dialog>
  67 +</template>
  68 +
  69 +<script>
  70 +import { saveParkingSpaceCreateFee, listFeeConfigs } from '@/api/fee/carCreateFeeApi'
  71 +import { getCommunityId, getDict } from '@/api/community/communityApi'
  72 +
  73 +export default {
  74 + name: 'CarCreateFeeAdd',
  75 + data() {
  76 + return {
  77 + visible: false,
  78 + isMore: false,
  79 + form: {
  80 + feeTypeCds: [],
  81 + feeConfigs: [],
  82 + parkingAreas: [],
  83 + locationTypeCd: '',
  84 + locationObjId: '',
  85 + carId: '',
  86 + feeTypeCd: '',
  87 + configId: '',
  88 + carState: ['H', 'S'],
  89 + locationTypeCdName: '',
  90 + startTime: '',
  91 + paId: '',
  92 + feeFlag: '',
  93 + computingFormula: '',
  94 + amount: '',
  95 + endTime: ''
  96 + },
  97 + feeTypeCds: [],
  98 + feeConfigs: []
  99 + }
  100 + },
  101 + created() {
  102 + this.getDictData()
  103 + },
  104 + methods: {
  105 + async getDictData() {
  106 + try {
  107 + this.feeTypeCds = await getDict('pay_fee_config', 'fee_type_cd')
  108 + } catch (error) {
  109 + console.error('获取字典数据失败:', error)
  110 + }
  111 + },
  112 + open(params) {
  113 + this.isMore = params.isMore || false
  114 +
  115 + if (!this.isMore && params.car) {
  116 + this.form.locationTypeCd = '2000'
  117 + this.form.locationObjId = params.car.carId
  118 + this.form.carId = params.car.carId
  119 + this.form.locationTypeCdName = params.car.carNum
  120 + }
  121 +
  122 + this.visible = true
  123 + },
  124 + handleClose() {
  125 + this.resetForm()
  126 + },
  127 + resetForm() {
  128 + this.form = {
  129 + ...this.form,
  130 + locationTypeCd: '',
  131 + locationObjId: '',
  132 + carId: '',
  133 + feeTypeCd: '',
  134 + configId: '',
  135 + startTime: '',
  136 + paId: '',
  137 + feeFlag: '',
  138 + computingFormula: '',
  139 + amount: '',
  140 + endTime: ''
  141 + }
  142 + },
  143 + async handleFeeTypeChange(feeTypeCd) {
  144 + try {
  145 + const res = await listFeeConfigs({
  146 + feeTypeCd: feeTypeCd,
  147 + isDefault: 'F',
  148 + valid: '1',
  149 + page: 1,
  150 + row: 100
  151 + })
  152 + this.feeConfigs = res.feeConfigs || []
  153 + } catch (error) {
  154 + this.$message.error(this.$t('common.fetchError'))
  155 + }
  156 + },
  157 + handleConfigChange(configId) {
  158 + const config = this.feeConfigs.find(item => item.configId === configId)
  159 + if (config) {
  160 + this.form.feeFlag = config.feeFlag
  161 + this.form.computingFormula = config.computingFormula
  162 + this.form.endTime = ''
  163 + }
  164 + },
  165 + handleParkingAreaChange(paId) {
  166 + this.form.paId = paId
  167 + },
  168 + async handleSubmit() {
  169 + try {
  170 + await this.$refs.form.validate()
  171 +
  172 + // 设置收费对象ID
  173 + if (this.form.locationTypeCd === '1000') {
  174 + this.form.locationObjId = getCommunityId()
  175 + } else if (this.form.locationTypeCd === '2000') {
  176 + this.form.locationObjId = this.form.carId
  177 + } else if (this.form.locationTypeCd === '3000') {
  178 + this.form.locationObjId = this.form.paId
  179 + } else {
  180 + this.$message.error(this.$t('common.invalidScope'))
  181 + return
  182 + }
  183 +
  184 + // 提交表单
  185 + //const res = ;
  186 + await saveParkingSpaceCreateFee(this.form)
  187 + this.$message.success(this.$t('common.saveSuccess'))
  188 + this.visible = false
  189 + this.$emit('success')
  190 +
  191 + } catch (error) {
  192 + console.error('提交失败:', error)
  193 + }
  194 + }
  195 + }
  196 +}
  197 +</script>
0 198 \ No newline at end of file
... ...
src/components/fee/deleteFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('deleteFee.title')" :visible.sync="visible" width="30%">
  3 + <div>
  4 + <p>{{ $t('deleteFee.confirmDelete') }}</p>
  5 + </div>
  6 + <span slot="footer" class="dialog-footer">
  7 + <el-button @click="close">{{ $t('common.cancel') }}</el-button>
  8 + <el-button type="primary" @click="deleteFee">{{ $t('common.confirm') }}</el-button>
  9 + </span>
  10 + </el-dialog>
  11 +</template>
  12 +
  13 +<script>
  14 +import { deleteFee } from '@/api/fee/listCarFeeApi'
  15 +
  16 +export default {
  17 + name: 'DeleteFee',
  18 + data() {
  19 + return {
  20 + visible: false,
  21 + deleteFeeInfo: {}
  22 + }
  23 + },
  24 + methods: {
  25 + open(info) {
  26 + this.deleteFeeInfo = info
  27 + this.visible = true
  28 + },
  29 + close() {
  30 + this.visible = false
  31 + },
  32 + deleteFee() {
  33 + deleteFee(this.deleteFeeInfo).then(response => {
  34 + if (response.data.code === 0) {
  35 + this.$message.success(this.$t('common.deleteSuccess'))
  36 + this.$emit('success')
  37 + this.close()
  38 + } else {
  39 + this.$message.error(response.data.msg)
  40 + }
  41 + }).catch(error => {
  42 + this.$message.error(error.message)
  43 + })
  44 + }
  45 + }
  46 +}
  47 +</script>
0 48 \ No newline at end of file
... ...
src/components/fee/doImportCreateFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('doImportCreateFee.customCreateFee')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + >
  7 + <el-form label-width="150px">
  8 + <el-form-item :label="$t('doImportCreateFee.selectFile')">
  9 + <el-upload
  10 + class="upload-demo"
  11 + :before-upload="beforeUpload"
  12 + :show-file-list="false"
  13 + >
  14 + <el-button size="small" type="primary">
  15 + <i class="el-icon-upload"></i>
  16 + {{ $t('common.selectFile') }}
  17 + </el-button>
  18 + <div slot="tip" class="el-upload__tip" style="margin-top:10px">
  19 + {{ fileName || $t('doImportCreateFee.requiredFile') }}
  20 + </div>
  21 + </el-upload>
  22 + </el-form-item>
  23 + </el-form>
  24 +
  25 + <div slot="footer" class="dialog-footer">
  26 + <el-button @click="visible = false">{{ $t('doImportCreateFee.cancel') }}</el-button>
  27 + <el-button type="primary" @click="handleImport" :disabled="!file">
  28 + {{ $t('doImportCreateFee.import') }}
  29 + </el-button>
  30 + </div>
  31 + </el-dialog>
  32 +</template>
  33 +
  34 +<script>
  35 +import { importCustomFee } from '@/api/fee/carCreateFeeApi'
  36 +
  37 +export default {
  38 + name: 'DoImportCreateFee',
  39 + data() {
  40 + return {
  41 + visible: false,
  42 + file: null,
  43 + fileName: ''
  44 + }
  45 + },
  46 + methods: {
  47 + open() {
  48 + this.visible = true
  49 + this.file = null
  50 + this.fileName = ''
  51 + },
  52 + beforeUpload(file) {
  53 + const validTypes = ['xlsx', 'xls']
  54 + const fileType = file.name.split('.').pop().toLowerCase()
  55 + const isExcel = validTypes.includes(fileType)
  56 + const isLt2M = file.size / 1024 / 1024 < 2
  57 +
  58 + if (!isExcel) {
  59 + this.$message.error(this.$t('common.invalidExcelType'))
  60 + return false
  61 + }
  62 + if (!isLt2M) {
  63 + this.$message.error(this.$t('common.fileSizeExceed'))
  64 + return false
  65 + }
  66 +
  67 + this.file = file
  68 + this.fileName = file.name
  69 + return false // 阻止自动上传
  70 + },
  71 + async handleImport() {
  72 + if (!this.file) {
  73 + this.$message.warning(this.$t('doImportCreateFee.requiredFile'))
  74 + return
  75 + }
  76 +
  77 + try {
  78 + const res = await importCustomFee({
  79 + file: this.file
  80 + })
  81 +
  82 + if (res.code === 0) {
  83 + this.$message.success(this.$t('common.importSuccess'))
  84 + this.visible = false
  85 + this.$emit('success')
  86 + } else {
  87 + this.$message.error(res.msg || this.$t('common.importError'))
  88 + }
  89 + } catch (error) {
  90 + this.$message.error(this.$t('common.importError'))
  91 + }
  92 + }
  93 + }
  94 +}
  95 +</script>
0 96 \ No newline at end of file
... ...
src/components/fee/editFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('editFee.title')" :visible.sync="visible" width="50%">
  3 + <el-form :model="editFeeInfo" label-width="120px">
  4 + <el-form-item :label="$t('editFee.startTime')" required>
  5 + <el-date-picker v-model="editFeeInfo.startTime" type="datetime" :placeholder="$t('editFee.startTimePlaceholder')"
  6 + value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">
  7 + </el-date-picker>
  8 + </el-form-item>
  9 + <el-form-item :label="$t('editFee.endTime')" required>
  10 + <el-date-picker v-model="editFeeInfo.endTime" type="datetime" :placeholder="$t('editFee.endTimePlaceholder')"
  11 + value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">
  12 + </el-date-picker>
  13 + </el-form-item>
  14 + <el-form-item :label="$t('editFee.maxEndTime')" required>
  15 + <el-date-picker v-model="editFeeInfo.maxEndTime" type="datetime"
  16 + :placeholder="$t('editFee.maxEndTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">
  17 + </el-date-picker>
  18 + </el-form-item>
  19 + <template v-if="editFeeInfo.computingFormula == '1102'">
  20 + <el-form-item :label="$t('editFee.rateCycle')" required>
  21 + <el-input v-model="editFeeInfo.rateCycle" :placeholder="$t('editFee.rateCyclePlaceholder')"></el-input>
  22 + </el-form-item>
  23 + <el-form-item :label="$t('editFee.rate')" required>
  24 + <el-input v-model="editFeeInfo.rate" :placeholder="$t('editFee.ratePlaceholder')"></el-input>
  25 + </el-form-item>
  26 + <el-form-item :label="$t('editFee.rateStartTime')" required>
  27 + <el-date-picker v-model="editFeeInfo.rateStartTime" type="datetime"
  28 + :placeholder="$t('editFee.rateStartTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">
  29 + </el-date-picker>
  30 + </el-form-item>
  31 + </template>
  32 + </el-form>
  33 + <span slot="footer" class="dialog-footer">
  34 + <el-button @click="close">{{ $t('common.cancel') }}</el-button>
  35 + <el-button type="primary" @click="_doEidtFee">{{ $t('common.submit') }}</el-button>
  36 + </span>
  37 + </el-dialog>
  38 +</template>
  39 +
  40 +<script>
  41 +import { updateFee } from '@/api/fee/listCarFeeApi'
  42 +
  43 +export default {
  44 + name: 'EditFee',
  45 + data() {
  46 + return {
  47 + visible: false,
  48 + editFeeInfo: {
  49 + feeId: '',
  50 + startTime: '',
  51 + endTime: '',
  52 + feeFlag: '',
  53 + maxEndTime: '',
  54 + computingFormula: '',
  55 + rateCycle: '',
  56 + rate: '',
  57 + rateStartTime: ''
  58 + }
  59 + }
  60 + },
  61 + methods: {
  62 + open(fee) {
  63 + this.editFeeInfo = { ...fee }
  64 + this.visible = true
  65 + },
  66 + close() {
  67 + this.visible = false
  68 + },
  69 + _doEidtFee() {
  70 + // 验证逻辑
  71 + updateFee(this.editFeeInfo).then(response => {
  72 + if (response.data.code === 0) {
  73 + this.$message.success(this.$t('common.updateSuccess'))
  74 + this.$emit('success')
  75 + this.close()
  76 + } else {
  77 + this.$message.error(response.data.msg)
  78 + }
  79 + }).catch(error => {
  80 + this.$message.error(error.message)
  81 + })
  82 + }
  83 + }
  84 +}
  85 +</script>
0 86 \ No newline at end of file
... ...
src/components/fee/exportCarFeeImportExcel.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('exportCarFeeImportExcel.templateExport')" :visible.sync="visible" width="50%">
  3 + <el-form label-width="150px">
  4 + <el-form-item :label="$t('exportCarFeeImportExcel.parkingLot')">
  5 + <div>
  6 + <el-checkbox v-model="isParkingAreaAll" @change="changeAllParkingAreas">
  7 + {{ $t('exportCarFeeImportExcel.all') }}
  8 + </el-checkbox>
  9 + <el-checkbox-group v-model="selectedParkingAreas" @change="changeItemParkingArea">
  10 + <el-checkbox v-for="item in parkingAreas" :key="item.paId" :label="item.paId" style="margin-left:15px">
  11 + {{ item.num }}{{ $t('exportCarFeeImportExcel.parkingLotPlaceholder') }}
  12 + </el-checkbox>
  13 + </el-checkbox-group>
  14 + </div>
  15 + </el-form-item>
  16 +
  17 + <el-form-item :label="$t('exportCarFeeImportExcel.feeItem')">
  18 + <div>
  19 + <el-checkbox v-model="isConfigAll" @change="changeAllConfigs">
  20 + {{ $t('exportCarFeeImportExcel.all') }}
  21 + </el-checkbox>
  22 + <el-checkbox-group v-model="selectedConfigs" @change="changeItemConfig">
  23 + <template v-for="item in configs">
  24 + <el-checkbox :key="item.configId" :label="item.configId" style="margin-left:15px"
  25 + v-if="item.feeTypeCd !== '888800010001' && item.feeTypeCd !== '888800010009' && item.feeTypeCd !== '888800010011'">
  26 + {{ item.feeName }}
  27 + </el-checkbox>
  28 + </template>
  29 + </el-checkbox-group>
  30 + </div>
  31 + </el-form-item>
  32 + </el-form>
  33 +
  34 + <div slot="footer" class="dialog-footer">
  35 + <el-button @click="visible = false">{{ $t('exportCarFeeImportExcel.cancel') }}</el-button>
  36 + <el-button type="primary" @click="handleExport">{{ $t('exportCarFeeImportExcel.export') }}</el-button>
  37 + </div>
  38 + </el-dialog>
  39 +</template>
  40 +
  41 +<script>
  42 +import { listParkingAreas, listFeeConfigs, exportCarFeeExcel } from '@/api/fee/carCreateFeeApi'
  43 +
  44 +export default {
  45 + name: 'ExportCarFeeImportExcel',
  46 + data() {
  47 + return {
  48 + visible: false,
  49 + isParkingAreaAll: true,
  50 + isConfigAll: true,
  51 + selectedParkingAreas: [],
  52 + selectedConfigs: [],
  53 + parkingAreas: [],
  54 + configs: []
  55 + }
  56 + },
  57 + created() {
  58 + this.fetchData()
  59 + },
  60 + methods: {
  61 + async fetchData() {
  62 + try {
  63 + // 获取停车场
  64 + const parkingRes = await listParkingAreas({
  65 + page: 1,
  66 + row: 150
  67 + })
  68 + this.parkingAreas = parkingRes.parkingAreas || []
  69 + this.selectedParkingAreas = this.parkingAreas.map(item => item.paId)
  70 +
  71 + // 获取费用配置
  72 + const configRes = await listFeeConfigs({
  73 + page: 1,
  74 + row: 100,
  75 + isDefault: 'F'
  76 + })
  77 + this.configs = configRes.feeConfigs || []
  78 + this.selectedConfigs = this.configs
  79 + .filter(item => item.feeTypeCd !== '888800010001' && item.feeTypeCd !== '888800010009' && item.feeTypeCd !== '888800010011')
  80 + .map(item => item.configId)
  81 +
  82 + } catch (error) {
  83 + console.error('获取数据失败:', error)
  84 + }
  85 + },
  86 + open() {
  87 + this.visible = true
  88 + },
  89 + changeAllParkingAreas() {
  90 + if (this.isParkingAreaAll) {
  91 + this.selectedParkingAreas = this.parkingAreas.map(item => item.paId)
  92 + } else {
  93 + this.selectedParkingAreas = []
  94 + }
  95 + },
  96 + changeItemParkingArea() {
  97 + this.isParkingAreaAll = this.selectedParkingAreas.length === this.parkingAreas.length
  98 + },
  99 + changeAllConfigs() {
  100 + if (this.isConfigAll) {
  101 + this.selectedConfigs = this.configs
  102 + .filter(item => item.feeTypeCd !== '888800010001' && item.feeTypeCd !== '888800010009' && item.feeTypeCd !== '888800010011')
  103 + .map(item => item.configId)
  104 + } else {
  105 + this.selectedConfigs = []
  106 + }
  107 + },
  108 + changeItemConfig() {
  109 + this.isConfigAll = this.selectedConfigs.length === this.configs
  110 + .filter(item => item.feeTypeCd !== '888800010001' && item.feeTypeCd !== '888800010009' && item.feeTypeCd !== '888800010011')
  111 + .length
  112 + },
  113 + async handleExport() {
  114 + try {
  115 + const paIds = this.selectedParkingAreas.join(',')
  116 + const configIds = this.selectedConfigs.join(',')
  117 +
  118 + await exportCarFeeExcel({
  119 + paIds,
  120 + configIds
  121 + })
  122 +
  123 + this.$message.success(this.$t('common.exportSuccess'))
  124 + this.visible = false
  125 + } catch (error) {
  126 + this.$message.error(this.$t('common.exportError'))
  127 + }
  128 + }
  129 + }
  130 +}
  131 +</script>
0 132 \ No newline at end of file
... ...
src/components/fee/parkingAreaSelect2.vue 0 → 100644
  1 +<template>
  2 + <el-select
  3 + v-model="value"
  4 + filterable
  5 + remote
  6 + :remote-method="remoteMethod"
  7 + :loading="loading"
  8 + :placeholder="$t('parkingAreaSelect2.parkingLotPlaceholder')"
  9 + style="width:100%"
  10 + @change="handleChange"
  11 + >
  12 + <el-option
  13 + v-for="item in options"
  14 + :key="item.paId"
  15 + :label="item.num"
  16 + :value="item.paId"
  17 + />
  18 + </el-select>
  19 +</template>
  20 +
  21 +<script>
  22 +import { listParkingAreas } from '@/api/fee/carCreateFeeApi'
  23 +
  24 +export default {
  25 + name: 'ParkingAreaSelect2',
  26 + props: {
  27 + value: {
  28 + type: String,
  29 + default: ''
  30 + }
  31 + },
  32 + data() {
  33 + return {
  34 + options: [],
  35 + loading: false
  36 + }
  37 + },
  38 + methods: {
  39 + async remoteMethod(query) {
  40 + if (query) {
  41 + this.loading = true
  42 + try {
  43 + const res = await listParkingAreas({
  44 + num: query,
  45 + page: 1,
  46 + row: 50
  47 + })
  48 + this.options = res.parkingAreas || []
  49 + } catch (error) {
  50 + console.error('获取停车场失败:', error)
  51 + } finally {
  52 + this.loading = false
  53 + }
  54 + } else {
  55 + this.options = []
  56 + }
  57 + },
  58 + handleChange(value) {
  59 + this.$emit('change', value)
  60 + }
  61 + }
  62 +}
  63 +</script>
0 64 \ No newline at end of file
... ...
src/components/fee/splitFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('splitFee.title')" :visible.sync="visible" width="50%">
  3 + <el-form :model="splitFeeInfo" label-width="120px">
  4 + <el-form-item :label="$t('splitFee.timePeriod')">
  5 + <div>{{ splitFeeInfo.endTime }} ~ {{ splitFeeInfo.deadlineTime }}</div>
  6 + </el-form-item>
  7 + <el-form-item :label="$t('splitFee.splitTime')" required>
  8 + <el-date-picker
  9 + v-model="splitFeeInfo.splitTime"
  10 + type="date"
  11 + :placeholder="$t('splitFee.splitTimePlaceholder')"
  12 + value-format="yyyy-MM-dd"
  13 + style="width:100%">
  14 + </el-date-picker>
  15 + <span style="color: red;">{{ $t('splitFee.note') }}</span>
  16 + </el-form-item>
  17 + <el-form-item :label="$t('splitFee.remark')" required>
  18 + <el-input
  19 + type="textarea"
  20 + v-model="splitFeeInfo.remark"
  21 + :placeholder="$t('splitFee.remarkPlaceholder')"
  22 + :rows="3"
  23 + style="width:100%">
  24 + </el-input>
  25 + </el-form-item>
  26 + </el-form>
  27 + <span slot="footer" class="dialog-footer">
  28 + <el-button @click="close">{{ $t('common.cancel') }}</el-button>
  29 + <el-button type="primary" @click="_doSplitFee">{{ $t('common.submit') }}</el-button>
  30 + </span>
  31 + </el-dialog>
  32 +</template>
  33 +
  34 +<script>
  35 +import { splitFee } from '@/api/fee/listCarFeeApi'
  36 +
  37 +export default {
  38 + name: 'SplitFee',
  39 + data() {
  40 + return {
  41 + visible: false,
  42 + splitFeeInfo: {
  43 + feeId: '',
  44 + splitTime: '',
  45 + remark: '',
  46 + endTime: '',
  47 + deadlineTime: ''
  48 + }
  49 + }
  50 + },
  51 + methods: {
  52 + open(fee) {
  53 + this.splitFeeInfo = {
  54 + feeId: fee.feeId,
  55 + endTime: this.$formatDate(fee.endTime),
  56 + deadlineTime: this._computeSplitDeadLineTime(fee),
  57 + splitTime: '',
  58 + remark: ''
  59 + }
  60 + this.visible = true
  61 + },
  62 + close() {
  63 + this.visible = false
  64 + },
  65 + _doSplitFee() {
  66 + if (!this.splitFeeInfo.splitTime) {
  67 + this.$message.error(this.$t('splitFee.splitTimeRequired'))
  68 + return
  69 + }
  70 +
  71 + const data = {
  72 + preFeeId: this.splitFeeInfo.feeId,
  73 + splitTime: this.splitFeeInfo.splitTime,
  74 + remark: this.splitFeeInfo.remark
  75 + }
  76 +
  77 + splitFee(data).then(response => {
  78 + if (response.data.code === 0) {
  79 + this.$message.success(this.$t('common.operateSuccess'))
  80 + this.$emit('success')
  81 + this.close()
  82 + } else {
  83 + this.$message.error(response.data.msg)
  84 + }
  85 + }).catch(error => {
  86 + this.$message.error(error.message)
  87 + })
  88 + },
  89 + _computeSplitDeadLineTime(fee) {
  90 + if (fee.amountOwed == 0 && fee.endTime == fee.deadlineTime) {
  91 + return "-"
  92 + }
  93 + if (fee.state == '2009001') {
  94 + return "-"
  95 + }
  96 + return this.$formatDate(fee.deadlineTime)
  97 + }
  98 + }
  99 +}
  100 +</script>
0 101 \ No newline at end of file
... ...
src/components/work/AddRepairSetting.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('repairSetting.addTitle')" :visible.sync="visible" width="50%" @close="closeDialog">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="150px">
  4 + <el-row>
  5 + <el-col :span="12">
  6 + <el-form-item :label="$t('repairSetting.typeName')" prop="repairTypeName">
  7 + <el-input v-model="formData.repairTypeName" :placeholder="$t('repairSetting.repairTypeNamePlaceholder')" />
  8 + </el-form-item>
  9 + </el-col>
  10 + <el-col :span="12">
  11 + <el-form-item :label="$t('repairSetting.settingType')" prop="repairSettingType">
  12 + <el-select v-model="formData.repairSettingType"
  13 + :placeholder="$t('repairSetting.required') + $t('repairSetting.repairSettingTypePlaceholder')"
  14 + style="width:100%">
  15 + <el-option :label="$t('repairSetting.cleaningOrder')" value="100" />
  16 + <el-option :label="$t('repairSetting.repairOrder')" value="200" />
  17 + </el-select>
  18 + </el-form-item>
  19 + </el-col>
  20 + </el-row>
  21 +
  22 + <el-row>
  23 + <el-col :span="12">
  24 + <el-form-item :label="$t('repairSetting.dispatchMethod')" prop="repairWay">
  25 + <el-select v-model="formData.repairWay"
  26 + :placeholder="$t('repairSetting.required') + $t('repairSetting.repairWayPlaceholder')" style="width:100%">
  27 + <el-option :label="$t('repairSetting.grabOrder')" value="100" />
  28 + <el-option :label="$t('repairSetting.assign')" value="200" />
  29 + <el-option :label="$t('repairSetting.polling')" value="300" />
  30 + </el-select>
  31 + </el-form-item>
  32 + </el-col>
  33 + <el-col :span="12">
  34 + <el-form-item :label="$t('repairSetting.publicArea')" prop="publicArea">
  35 + <el-select v-model="formData.publicArea"
  36 + :placeholder="$t('repairSetting.required') + $t('repairSetting.publicAreaPlaceholder')" style="width:100%">
  37 + <el-option :label="$t('repairSetting.nonHouse')" value="T" />
  38 + <el-option :label="$t('repairSetting.house')" value="F" />
  39 + </el-select>
  40 + </el-form-item>
  41 + </el-col>
  42 + </el-row>
  43 +
  44 + <el-row>
  45 + <el-col :span="12">
  46 + <el-form-item :label="$t('repairSetting.ownerDisplay')" prop="isShow">
  47 + <el-select v-model="formData.isShow" :placeholder="$t('repairSetting.ownerDisplayPlaceholder')"
  48 + style="width:100%">
  49 + <el-option :label="$t('repairSetting.yes')" value="Y" />
  50 + <el-option :label="$t('repairSetting.no')" value="N" />
  51 + </el-select>
  52 + </el-form-item>
  53 + </el-col>
  54 + <el-col :span="12">
  55 + <el-form-item :label="$t('repairSetting.notificationMethod')" prop="notifyWay">
  56 + <el-select v-model="formData.notifyWay" :placeholder="$t('repairSetting.notificationMethodPlaceholder')"
  57 + style="width:100%">
  58 + <el-option :label="$t('repairSetting.sms')" value="SMS" />
  59 + <el-option :label="$t('repairSetting.wechat')" value="WECHAT" />
  60 + <el-option :label="$t('repairSetting.wechatWorkLicense')" value="WORK_LICENSE" />
  61 + </el-select>
  62 + </el-form-item>
  63 + </el-col>
  64 + </el-row>
  65 +
  66 + <el-row>
  67 + <el-col :span="12">
  68 + <el-form-item :label="$t('repairSetting.processingTime')" prop="doTime">
  69 + <el-input v-model.number="formData.doTime" type="number"
  70 + :placeholder="$t('repairSetting.required') + $t('repairSetting.processingTimePlaceholder')">
  71 + <template slot="append">{{ $t('repairSetting.processingTimeUnit') }}</template>
  72 + </el-input>
  73 + </el-form-item>
  74 + </el-col>
  75 + <el-col :span="12">
  76 + <el-form-item :label="$t('repairSetting.timeoutWarning')" prop="warningTime">
  77 + <el-input v-model.number="formData.warningTime" type="number"
  78 + :placeholder="$t('repairSetting.required') + $t('repairSetting.timeoutWarningPlaceholder')">
  79 + <template slot="append">{{ $t('repairSetting.timeoutWarningUnit') }}</template>
  80 + </el-input>
  81 + </el-form-item>
  82 + </el-col>
  83 + </el-row>
  84 +
  85 + <el-row>
  86 + <el-col :span="12">
  87 + <el-form-item :label="$t('repairSetting.returnVisitSetting')" prop="returnVisitFlag">
  88 + <el-select v-model="formData.returnVisitFlag"
  89 + :placeholder="$t('repairSetting.required') + $t('repairSetting.returnVisitFlagPlaceholder')"
  90 + style="width:100%">
  91 + <el-option :label="$t('repairSetting.noFollowUp')" value="001" />
  92 + <el-option :label="$t('repairSetting.followUpAfterEvaluation')" value="002" />
  93 + <el-option :label="$t('repairSetting.followUp')" value="003" />
  94 + </el-select>
  95 + </el-form-item>
  96 + </el-col>
  97 + </el-row>
  98 +
  99 + <el-row>
  100 + <el-col :span="24">
  101 + <el-form-item :label="$t('repairSetting.explanation')" prop="remark">
  102 + <el-input v-model="formData.remark" type="textarea" :rows="3"
  103 + :placeholder="$t('repairSetting.remarkPlaceholder')" />
  104 + </el-form-item>
  105 + </el-col>
  106 + </el-row>
  107 + </el-form>
  108 +
  109 + <div slot="footer" class="dialog-footer">
  110 + <el-button @click="closeDialog">{{ $t('repairSetting.cancel') }}</el-button>
  111 + <el-button type="primary" @click="submitForm">{{ $t('repairSetting.save') }}</el-button>
  112 + </div>
  113 + </el-dialog>
  114 +</template>
  115 +
  116 +<script>
  117 +import { saveRepairSetting } from '@/api/work/repairSettingApi'
  118 +
  119 +export default {
  120 + name: 'AddRepairSetting',
  121 + data() {
  122 + return {
  123 + visible: false,
  124 + formData: {
  125 + repairTypeName: '',
  126 + repairWay: '200',
  127 + repairSettingType: '200',
  128 + remark: '',
  129 + publicArea: 'F',
  130 + payFeeFlag: 'F',
  131 + returnVisitFlag: '003',
  132 + isShow: 'Y',
  133 + doTime: 24,
  134 + warningTime: 30,
  135 + notifyWay: 'WECHAT'
  136 + },
  137 + rules: {
  138 + repairTypeName: [
  139 + { required: true, message: this.$t('repairSetting.typeNamePlaceholder'), trigger: 'blur' },
  140 + { max: 200, message: this.$t('repairSetting.typeNameMaxLength'), trigger: 'blur' }
  141 + ],
  142 + repairSettingType: [
  143 + { required: true, message: this.$t('repairSetting.settingTypeRequired'), trigger: 'change' }
  144 + ],
  145 + repairWay: [
  146 + { required: true, message: this.$t('repairSetting.dispatchMethodRequired'), trigger: 'change' }
  147 + ],
  148 + publicArea: [
  149 + { required: true, message: this.$t('repairSetting.publicAreaRequired'), trigger: 'change' }
  150 + ],
  151 + isShow: [
  152 + { required: true, message: this.$t('repairSetting.ownerDisplayRequired'), trigger: 'change' }
  153 + ],
  154 + notifyWay: [
  155 + { required: true, message: this.$t('repairSetting.notificationMethodRequired'), trigger: 'change' }
  156 + ],
  157 + returnVisitFlag: [
  158 + { required: true, message: this.$t('repairSetting.returnVisitRequired'), trigger: 'change' }
  159 + ],
  160 + doTime: [
  161 + { required: true, message: this.$t('repairSetting.processingTimeRequired'), trigger: 'blur' },
  162 + { type: 'number', min: 1, message: this.$t('repairSetting.processingTimeMin'), trigger: 'blur' }
  163 + ],
  164 + warningTime: [
  165 + { required: true, message: this.$t('repairSetting.timeoutWarningRequired'), trigger: 'blur' },
  166 + { type: 'number', min: 1, message: this.$t('repairSetting.timeoutWarningMin'), trigger: 'blur' }
  167 + ],
  168 + remark: [
  169 + { max: 500, message: this.$t('repairSetting.remarkMaxLength'), trigger: 'blur' }
  170 + ]
  171 + }
  172 + }
  173 + },
  174 + methods: {
  175 + open() {
  176 + this.visible = true
  177 + },
  178 +
  179 + closeDialog() {
  180 + this.visible = false
  181 + this.resetForm()
  182 + },
  183 +
  184 + resetForm() {
  185 + this.$refs.form.resetFields()
  186 + this.formData = {
  187 + repairTypeName: '',
  188 + repairWay: '200',
  189 + repairSettingType: '200',
  190 + remark: '',
  191 + publicArea: 'F',
  192 + payFeeFlag: 'F',
  193 + returnVisitFlag: '003',
  194 + isShow: 'Y',
  195 + doTime: 24,
  196 + warningTime: 30,
  197 + notifyWay: 'WECHAT'
  198 + }
  199 + },
  200 +
  201 + submitForm() {
  202 + this.$refs.form.validate(async valid => {
  203 + if (valid) {
  204 + try {
  205 + await saveRepairSetting(this.formData)
  206 + this.$message.success(this.$t('repairSetting.addSuccess'))
  207 + this.$emit('success')
  208 + this.closeDialog()
  209 + } catch (error) {
  210 + console.error('添加报修设置失败:', error)
  211 + this.$message.error(this.$t('repairSetting.addFailed'))
  212 + }
  213 + }
  214 + })
  215 + }
  216 + }
  217 +}
  218 +</script>
0 219 \ No newline at end of file
... ...
src/components/work/DeleteRepairSetting.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairSetting.confirmDeleteTitle')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center
  7 + >
  8 + <div style="text-align: center">
  9 + <p>{{ $t('repairSetting.confirmDeleteContent') }} [{{ currentRow.repairTypeName }}]?</p>
  10 + </div>
  11 + <div slot="footer" class="dialog-footer">
  12 + <el-button @click="closeDialog">{{ $t('repairSetting.cancelDelete') }}</el-button>
  13 + <el-button type="danger" @click="confirmDelete">{{ $t('repairSetting.confirmDelete') }}</el-button>
  14 + </div>
  15 + </el-dialog>
  16 +</template>
  17 +
  18 +<script>
  19 +import { deleteRepairSetting } from '@/api/work/repairSettingApi'
  20 +
  21 +export default {
  22 + name: 'DeleteRepairSetting',
  23 + data() {
  24 + return {
  25 + visible: false,
  26 + currentRow: {}
  27 + }
  28 + },
  29 + methods: {
  30 + open(row) {
  31 + this.currentRow = { ...row }
  32 + this.visible = true
  33 + },
  34 +
  35 + closeDialog() {
  36 + this.visible = false
  37 + this.currentRow = {}
  38 + },
  39 +
  40 + async confirmDelete() {
  41 + try {
  42 + await deleteRepairSetting(this.currentRow.settingId)
  43 + this.$message.success(this.$t('repairSetting.deleteSuccess'))
  44 + this.$emit('success')
  45 + this.closeDialog()
  46 + } catch (error) {
  47 + console.error('删除报修设置失败:', error)
  48 + this.$message.error(this.$t('repairSetting.deleteFailed'))
  49 + }
  50 + }
  51 + }
  52 +}
  53 +</script>
0 54 \ No newline at end of file
... ...
src/components/work/DeleteRepairTypeUser.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible="visible"
  4 + :title="$t('deleteRepairTypeUser.title')"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('deleteRepairTypeUser.confirmDelete') }}</p>
  10 + </div>
  11 + <div slot="footer" class="dialog-footer">
  12 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  13 + <el-button type="danger" @click="confirmDelete">{{ $t('common.confirmDelete') }}</el-button>
  14 + </div>
  15 + </el-dialog>
  16 +</template>
  17 +
  18 +<script>
  19 +import { deleteRepairTypeUser } from '@/api/work/repairTypeUserApi'
  20 +import { getCommunityId } from '@/api/community/communityApi'
  21 +
  22 +export default {
  23 + name: 'DeleteRepairTypeUser',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + repairTypeUser: {}
  28 + }
  29 + },
  30 + methods: {
  31 + open(repairTypeUser) {
  32 + this.repairTypeUser = repairTypeUser
  33 + this.visible = true
  34 + },
  35 + handleClose() {
  36 + this.visible = false
  37 + this.repairTypeUser = {}
  38 + },
  39 + async confirmDelete() {
  40 + try {
  41 + const communityId = await getCommunityId()
  42 + const data = {
  43 + communityId: communityId,
  44 + typeUserId: this.repairTypeUser.typeUserId
  45 + }
  46 +
  47 + const response = await deleteRepairTypeUser(data)
  48 + if (response.code === 0) {
  49 + this.$message.success(this.$t('common.deleteSuccess'))
  50 + this.$emit('success')
  51 + this.handleClose()
  52 + } else {
  53 + this.$message.error(response.msg || this.$t('common.deleteFailed'))
  54 + }
  55 + } catch (error) {
  56 + console.error('Error deleting repair type user:', error)
  57 + this.$message.error(this.$t('common.deleteFailed'))
  58 + }
  59 + }
  60 + }
  61 +}
  62 +</script>
0 63 \ No newline at end of file
... ...
src/components/work/EditRepairSetting.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('repairSetting.editTitle')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="closeDialog"
  7 + >
  8 + <el-form ref="form" :model="formData" :rules="rules" label-width="150px">
  9 + <el-row>
  10 + <el-col :span="12">
  11 + <el-form-item :label="$t('repairSetting.typeName')" prop="repairTypeName">
  12 + <el-input
  13 + v-model="formData.repairTypeName"
  14 + :placeholder="$t('repairSetting.repairTypeNamePlaceholder')"
  15 + />
  16 + </el-form-item>
  17 + </el-col>
  18 + <el-col :span="12">
  19 + <el-form-item :label="$t('repairSetting.settingType')" prop="repairSettingType">
  20 + <el-select
  21 + v-model="formData.repairSettingType"
  22 + :placeholder="$t('repairSetting.required') + $t('repairSetting.repairSettingTypePlaceholder')"
  23 + style="width:100%"
  24 + >
  25 + <el-option :label="$t('repairSetting.cleaningOrder')" value="100" />
  26 + <el-option :label="$t('repairSetting.repairOrder')" value="200" />
  27 + </el-select>
  28 + </el-form-item>
  29 + </el-col>
  30 + </el-row>
  31 +
  32 + <el-row>
  33 + <el-col :span="12">
  34 + <el-form-item :label="$t('repairSetting.dispatchMethod')" prop="repairWay">
  35 + <el-select
  36 + v-model="formData.repairWay"
  37 + :placeholder="$t('repairSetting.required') + $t('repairSetting.repairWayPlaceholder')"
  38 + style="width:100%"
  39 + >
  40 + <el-option :label="$t('repairSetting.grabOrder')" value="100" />
  41 + <el-option :label="$t('repairSetting.assign')" value="200" />
  42 + <el-option :label="$t('repairSetting.polling')" value="300" />
  43 + </el-select>
  44 + </el-form-item>
  45 + </el-col>
  46 + <el-col :span="12">
  47 + <el-form-item :label="$t('repairSetting.publicArea')" prop="publicArea">
  48 + <el-select
  49 + v-model="formData.publicArea"
  50 + :placeholder="$t('repairSetting.required') + $t('repairSetting.publicAreaPlaceholder')"
  51 + style="width:100%"
  52 + >
  53 + <el-option :label="$t('repairSetting.nonHouse')" value="T" />
  54 + <el-option :label="$t('repairSetting.house')" value="F" />
  55 + </el-select>
  56 + </el-form-item>
  57 + </el-col>
  58 + </el-row>
  59 +
  60 + <el-row>
  61 + <el-col :span="12">
  62 + <el-form-item :label="$t('repairSetting.ownerDisplay')" prop="isShow">
  63 + <el-select
  64 + v-model="formData.isShow"
  65 + :placeholder="$t('repairSetting.ownerDisplayPlaceholder')"
  66 + style="width:100%"
  67 + >
  68 + <el-option :label="$t('repairSetting.yes')" value="Y" />
  69 + <el-option :label="$t('repairSetting.no')" value="N" />
  70 + </el-select>
  71 + </el-form-item>
  72 + </el-col>
  73 + <el-col :span="12">
  74 + <el-form-item :label="$t('repairSetting.notificationMethod')" prop="notifyWay">
  75 + <el-select
  76 + v-model="formData.notifyWay"
  77 + :placeholder="$t('repairSetting.notificationMethodPlaceholder')"
  78 + style="width:100%"
  79 + >
  80 + <el-option :label="$t('repairSetting.sms')" value="SMS" />
  81 + <el-option :label="$t('repairSetting.wechat')" value="WECHAT" />
  82 + <el-option :label="$t('repairSetting.wechatWorkLicense')" value="WORK_LICENSE" />
  83 + </el-select>
  84 + </el-form-item>
  85 + </el-col>
  86 + </el-row>
  87 +
  88 + <el-row>
  89 + <el-col :span="12">
  90 + <el-form-item :label="$t('repairSetting.processingTime')" prop="doTime">
  91 + <el-input
  92 + v-model.number="formData.doTime"
  93 + type="number"
  94 + :placeholder="$t('repairSetting.required') + $t('repairSetting.processingTimePlaceholder')"
  95 + >
  96 + <template slot="append">{{ $t('repairSetting.processingTimeUnit') }}</template>
  97 + </el-input>
  98 + </el-form-item>
  99 + </el-col>
  100 + <el-col :span="12">
  101 + <el-form-item :label="$t('repairSetting.timeoutWarning')" prop="warningTime">
  102 + <el-input
  103 + v-model.number="formData.warningTime"
  104 + type="number"
  105 + :placeholder="$t('repairSetting.required') + $t('repairSetting.timeoutWarningPlaceholder')"
  106 + >
  107 + <template slot="append">{{ $t('repairSetting.timeoutWarningUnit') }}</template>
  108 + </el-input>
  109 + </el-form-item>
  110 + </el-col>
  111 + </el-row>
  112 +
  113 + <el-row>
  114 + <el-col :span="12">
  115 + <el-form-item :label="$t('repairSetting.returnVisitSetting')" prop="returnVisitFlag">
  116 + <el-select
  117 + v-model="formData.returnVisitFlag"
  118 + :placeholder="$t('repairSetting.required') + $t('repairSetting.returnVisitFlagPlaceholder')"
  119 + style="width:100%"
  120 + >
  121 + <el-option :label="$t('repairSetting.noFollowUp')" value="001" />
  122 + <el-option :label="$t('repairSetting.followUpAfterEvaluation')" value="002" />
  123 + <el-option :label="$t('repairSetting.followUp')" value="003" />
  124 + </el-select>
  125 + </el-form-item>
  126 + </el-col>
  127 + </el-row>
  128 +
  129 + <el-row>
  130 + <el-col :span="24">
  131 + <el-form-item :label="$t('repairSetting.explanation')" prop="remark">
  132 + <el-input
  133 + v-model="formData.remark"
  134 + type="textarea"
  135 + :rows="3"
  136 + :placeholder="$t('repairSetting.remarkPlaceholder')"
  137 + />
  138 + </el-form-item>
  139 + </el-col>
  140 + </el-row>
  141 + </el-form>
  142 +
  143 + <div slot="footer" class="dialog-footer">
  144 + <el-button @click="closeDialog">{{ $t('repairSetting.cancel') }}</el-button>
  145 + <el-button type="primary" @click="submitForm">{{ $t('repairSetting.save') }}</el-button>
  146 + </div>
  147 + </el-dialog>
  148 +</template>
  149 +
  150 +<script>
  151 +import { updateRepairSetting } from '@/api/work/repairSettingApi'
  152 +
  153 +export default {
  154 + name: 'EditRepairSetting',
  155 + data() {
  156 + return {
  157 + visible: false,
  158 + formData: {
  159 + settingId: '',
  160 + repairTypeName: '',
  161 + repairWay: '',
  162 + repairSettingType: '',
  163 + remark: '',
  164 + publicArea: '',
  165 + returnVisitFlag: '',
  166 + isShow: '',
  167 + doTime: 24,
  168 + warningTime: 30,
  169 + notifyWay: ''
  170 + },
  171 + rules: {
  172 + repairTypeName: [
  173 + { required: true, message: this.$t('repairSetting.typeNamePlaceholder'), trigger: 'blur' },
  174 + { max: 200, message: this.$t('repairSetting.typeNameMaxLength'), trigger: 'blur' }
  175 + ],
  176 + repairSettingType: [
  177 + { required: true, message: this.$t('repairSetting.settingTypeRequired'), trigger: 'change' }
  178 + ],
  179 + repairWay: [
  180 + { required: true, message: this.$t('repairSetting.dispatchMethodRequired'), trigger: 'change' }
  181 + ],
  182 + publicArea: [
  183 + { required: true, message: this.$t('repairSetting.publicAreaRequired'), trigger: 'change' }
  184 + ],
  185 + isShow: [
  186 + { required: true, message: this.$t('repairSetting.ownerDisplayRequired'), trigger: 'change' }
  187 + ],
  188 + notifyWay: [
  189 + { required: true, message: this.$t('repairSetting.notificationMethodRequired'), trigger: 'change' }
  190 + ],
  191 + returnVisitFlag: [
  192 + { required: true, message: this.$t('repairSetting.returnVisitRequired'), trigger: 'change' }
  193 + ],
  194 + doTime: [
  195 + { required: true, message: this.$t('repairSetting.processingTimeRequired'), trigger: 'blur' },
  196 + { type: 'number', min: 1, message: this.$t('repairSetting.processingTimeMin'), trigger: 'blur' }
  197 + ],
  198 + warningTime: [
  199 + { required: true, message: this.$t('repairSetting.timeoutWarningRequired'), trigger: 'blur' },
  200 + { type: 'number', min: 1, message: this.$t('repairSetting.timeoutWarningMin'), trigger: 'blur' }
  201 + ],
  202 + remark: [
  203 + { max: 500, message: this.$t('repairSetting.remarkMaxLength'), trigger: 'blur' }
  204 + ],
  205 + settingId: [
  206 + { required: true, message: this.$t('repairSetting.settingIdRequired'), trigger: 'blur' }
  207 + ]
  208 + }
  209 + }
  210 + },
  211 + methods: {
  212 + open(row) {
  213 + this.formData = { ...row }
  214 + this.visible = true
  215 + },
  216 +
  217 + closeDialog() {
  218 + this.visible = false
  219 + this.$refs.form.resetFields()
  220 + },
  221 +
  222 + submitForm() {
  223 + this.$refs.form.validate(async valid => {
  224 + if (valid) {
  225 + try {
  226 + await updateRepairSetting(this.formData)
  227 + this.$message.success(this.$t('repairSetting.updateSuccess'))
  228 + this.$emit('success')
  229 + this.closeDialog()
  230 + } catch (error) {
  231 + console.error('更新报修设置失败:', error)
  232 + this.$message.error(this.$t('repairSetting.updateFailed'))
  233 + }
  234 + }
  235 + })
  236 + }
  237 + }
  238 +}
  239 +</script>
0 240 \ No newline at end of file
... ...
src/components/work/EditRepairTypeUser.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible="visible"
  4 + :title="$t('editRepairTypeUser.title')"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" label-width="120px">
  9 + <el-form-item :label="$t('editRepairTypeUser.status')" prop="state" required>
  10 + <el-select v-model="form.state" style="width: 100%">
  11 + <el-option :value="9999" :label="$t('editRepairTypeUser.online')"></el-option>
  12 + <el-option :value="8888" :label="$t('editRepairTypeUser.offline')"></el-option>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item :label="$t('editRepairTypeUser.description')" prop="remark">
  16 + <el-input v-model="form.remark" :placeholder="$t('editRepairTypeUser.descriptionPlaceholder')"></el-input>
  17 + </el-form-item>
  18 + </el-form>
  19 + <div slot="footer" class="dialog-footer">
  20 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  21 + <el-button type="primary" @click="saveChanges">{{ $t('common.save') }}</el-button>
  22 + </div>
  23 + </el-dialog>
  24 +</template>
  25 +
  26 +<script>
  27 +import { updateRepairTypeUser } from '@/api/work/repairTypeUserApi'
  28 +import { getCommunityId } from '@/api/community/communityApi'
  29 +
  30 +export default {
  31 + name: 'EditRepairTypeUser',
  32 + data() {
  33 + return {
  34 + visible: false,
  35 + form: {
  36 + typeUserId: '',
  37 + state: '',
  38 + remark: ''
  39 + }
  40 + }
  41 + },
  42 + methods: {
  43 + open(repairTypeUser) {
  44 + this.form = {
  45 + typeUserId: repairTypeUser.typeUserId,
  46 + state: repairTypeUser.state,
  47 + remark: repairTypeUser.remark
  48 + }
  49 + this.visible = true
  50 + },
  51 + handleClose() {
  52 + this.visible = false
  53 + this.form = {
  54 + typeUserId: '',
  55 + state: '',
  56 + remark: ''
  57 + }
  58 + },
  59 + async saveChanges() {
  60 + try {
  61 + if (!this.form.state) {
  62 + this.$message.warning(this.$t('editRepairTypeUser.statusRequired'))
  63 + return
  64 + }
  65 +
  66 + const communityId = await getCommunityId()
  67 + const data = {
  68 + ...this.form,
  69 + communityId: communityId
  70 + }
  71 +
  72 + const response = await updateRepairTypeUser(data)
  73 + if (response.code === 0) {
  74 + this.$message.success(this.$t('common.saveSuccess'))
  75 + this.$emit('success')
  76 + this.handleClose()
  77 + } else {
  78 + this.$message.error(response.msg || this.$t('common.saveFailed'))
  79 + }
  80 + } catch (error) {
  81 + console.error('Error updating repair type user:', error)
  82 + this.$message.error(this.$t('common.saveFailed'))
  83 + }
  84 + }
  85 + }
  86 +}
  87 +</script>
0 88 \ No newline at end of file
... ...
src/components/work/OrgTreeShow.vue 0 → 100644
  1 +<template>
  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>
  12 + </div>
  13 +</template>
  14 +
  15 +<script>
  16 +import { listOrgTree } from '@/api/work/repairTypeUserApi'
  17 +import { getCommunityId } from '@/api/community/communityApi'
  18 +
  19 +export default {
  20 + name: 'OrgTreeShow',
  21 + data() {
  22 + return {
  23 + orgs: [],
  24 + defaultProps: {
  25 + children: 'children',
  26 + label: 'text'
  27 + }
  28 + }
  29 + },
  30 + methods: {
  31 + async refreshTree() {
  32 + try {
  33 + const communityId = await getCommunityId()
  34 + const params = {
  35 + communityId: communityId
  36 + }
  37 + const response = await listOrgTree(params)
  38 + if (response.code === 0) {
  39 + this.orgs = response.data
  40 + } else {
  41 + this.$message.error(response.msg || this.$t('common.requestFailed'))
  42 + }
  43 + } catch (error) {
  44 + console.error('Error loading org tree:', error)
  45 + this.$message.error(this.$t('common.requestFailed'))
  46 + }
  47 + },
  48 + handleNodeClick(data) {
  49 + this.$emit('org-selected', {
  50 + orgId: data.id,
  51 + orgName: data.text
  52 + })
  53 + }
  54 + },
  55 + mounted() {
  56 + this.refreshTree()
  57 + }
  58 +}
  59 +</script>
0 60 \ No newline at end of file
... ...
src/components/work/SelectStaff.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible="visible"
  4 + :title="$t('selectStaff.title')"
  5 + width="80%"
  6 + @close="handleClose"
  7 + >
  8 + <el-row :gutter="20">
  9 + <el-col :span="12" class="border-right">
  10 + <div class="text-center">
  11 + <h4>{{ $t('selectStaff.orgInfo') }}</h4>
  12 + </div>
  13 + <div class="staff padding">
  14 + <OrgTreeShow ref="orgTree" @org-selected="handleOrgSelected" />
  15 + </div>
  16 + </el-col>
  17 + <el-col :span="12">
  18 + <div class="text-center">
  19 + <h4>{{ $t('selectStaff.staffInfo') }}</h4>
  20 + </div>
  21 + <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 + >
  29 + <div>
  30 + <i class="el-icon-user margin-right-xs"></i>
  31 + {{ item.name }}
  32 + </div>
  33 + <div>{{ item.tel }}</div>
  34 + </div>
  35 + </div>
  36 + </el-col>
  37 + </el-row>
  38 + <div slot="footer" class="dialog-footer">
  39 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  40 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  41 + </div>
  42 + </el-dialog>
  43 +</template>
  44 +
  45 +<script>
  46 +import OrgTreeShow from '@/components/work/OrgTreeShow'
  47 +import { getStaffInfos } from '@/api/work/repairTypeUserApi'
  48 +
  49 +export default {
  50 + name: 'SelectStaff',
  51 + components: {
  52 + OrgTreeShow
  53 + },
  54 + data() {
  55 + return {
  56 + visible: false,
  57 + staffs: [],
  58 + curStaffId: '',
  59 + selectedStaff: null,
  60 + staffConfig: {},
  61 + currentOrgId: ''
  62 + }
  63 + },
  64 + methods: {
  65 + open(staffConfig) {
  66 + this.staffConfig = staffConfig || {}
  67 + this.visible = true
  68 + this.$nextTick(() => {
  69 + this.$refs.orgTree.refreshTree()
  70 + })
  71 + },
  72 + handleClose() {
  73 + this.visible = false
  74 + this.staffs = []
  75 + this.curStaffId = ''
  76 + this.selectedStaff = null
  77 + },
  78 + handleOrgSelected(org) {
  79 + this.currentOrgId = org.orgId
  80 + this.loadStaff(org.orgId)
  81 + },
  82 + async loadStaff(orgId) {
  83 + try {
  84 + const params = {
  85 + orgId: orgId,
  86 + row: 50
  87 + }
  88 + const response = await getStaffInfos(params)
  89 + if (response.code === 0) {
  90 + this.staffs = response.data
  91 + if (this.staffs.length > 0) {
  92 + this.curStaffId = this.staffs[0].staffId
  93 + }
  94 + } else {
  95 + this.$message.error(response.msg || this.$t('common.requestFailed'))
  96 + }
  97 + } catch (error) {
  98 + console.error('Error loading staff:', error)
  99 + this.$message.error(this.$t('common.requestFailed'))
  100 + }
  101 + },
  102 + selectStaff(staff) {
  103 + this.curStaffId = staff.staffId
  104 + this.selectedStaff = staff
  105 + },
  106 + handleSubmit() {
  107 + if (this.selectedStaff) {
  108 + if (this.staffConfig.call) {
  109 + this.staffConfig.call({
  110 + staffId: this.selectedStaff.staffId,
  111 + staffName: this.selectedStaff.name
  112 + })
  113 + }
  114 + this.handleClose()
  115 + } else {
  116 + this.$message.warning(this.$t('selectStaff.selectStaffFirst'))
  117 + }
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style scoped>
  124 +.border-right {
  125 + border-right: 1px solid #ebeef5;
  126 +}
  127 +.padding {
  128 + padding: 15px;
  129 +}
  130 +.staff-item {
  131 + padding: 10px;
  132 + margin-bottom: 10px;
  133 + border: 1px solid #ebeef5;
  134 + border-radius: 4px;
  135 + cursor: pointer;
  136 +}
  137 +.staff-item:hover {
  138 + background-color: #f5f7fa;
  139 +}
  140 +.staff-item.selected {
  141 + background-color: #ecf5ff;
  142 + border-color: #409eff;
  143 +}
  144 +.text-center {
  145 + text-align: center;
  146 + margin-bottom: 15px;
  147 +}
  148 +</style>
0 149 \ No newline at end of file
... ...
src/i18n/commonLang.js
... ... @@ -44,6 +44,7 @@ export const messages = {
44 44 hour:'hour',
45 45 more:'More',
46 46 tip:'Tip',
  47 + selectFile:'Select File'
47 48 }
48 49 },
49 50 zh: {
... ... @@ -91,7 +92,7 @@ export const messages = {
91 92 hour:'时',
92 93 more:'更多',
93 94 tip:'提示',
94   -
  95 + selectFile:'选择文件'
95 96 }
96 97 }
97 98 }
98 99 \ No newline at end of file
... ...
src/i18n/index.js
... ... @@ -158,6 +158,10 @@ import { messages as tempCarPaymentMessages } from &#39;../views/car/tempCarPaymentL
158 158 import { messages as parkingSpaceApplyManageMessages } from '../views/car/parkingSpaceApplyManageLang'
159 159 import { messages as addParkingSpaceApplyMessages } from '../views/car/addParkingSpaceApplyLang'
160 160 import { messages as auditParkingSpaceApplyMessages } from '../views/car/auditParkingSpaceApplyLang'
  161 +import { messages as carCreateFeeMessages } from '../views/fee/carCreateFeeLang'
  162 +import { messages as listCarFeeMessages } from '../views/fee/listCarFeeLang'
  163 +import { messages as repairSettingMessages } from '../views/work/repairSettingLang'
  164 +import { messages as repairTypeUserMessages } from '../views/work/repairTypeUserLang'
161 165  
162 166 Vue.use(VueI18n)
163 167  
... ... @@ -320,6 +324,10 @@ const messages = {
320 324 ...parkingSpaceApplyManageMessages.en,
321 325 ...addParkingSpaceApplyMessages.en,
322 326 ...auditParkingSpaceApplyMessages.en,
  327 + ...carCreateFeeMessages.en,
  328 + ...listCarFeeMessages.en,
  329 + ...repairSettingMessages.en,
  330 + ...repairTypeUserMessages.en,
323 331 },
324 332 zh: {
325 333 ...loginMessages.zh,
... ... @@ -478,6 +486,10 @@ const messages = {
478 486 ...parkingSpaceApplyManageMessages.zh,
479 487 ...addParkingSpaceApplyMessages.zh,
480 488 ...auditParkingSpaceApplyMessages.zh,
  489 + ...carCreateFeeMessages.zh,
  490 + ...listCarFeeMessages.zh,
  491 + ...repairSettingMessages.zh,
  492 + ...repairTypeUserMessages.zh,
481 493 }
482 494 }
483 495  
... ...
src/router/index.js
... ... @@ -767,25 +767,45 @@ const routes = [
767 767 component: () => import('@/views/car/remainingParkingSpaceList.vue')
768 768 },
769 769 {
770   - path:'/pages/car/tempCarPayment',
771   - name:'/pages/car/tempCarPayment',
  770 + path: '/pages/car/tempCarPayment',
  771 + name: '/pages/car/tempCarPayment',
772 772 component: () => import('@/views/car/tempCarPaymentList.vue')
  773 + },
  774 + {
  775 + path: '/pages/property/parkingSpaceApplyManage',
  776 + name: '/pages/property/parkingSpaceApplyManage',
  777 + component: () => import('@/views/car/parkingSpaceApplyManageList.vue')
  778 + },
  779 + {
  780 + path: '/views/car/addParkingSpaceApply',
  781 + name: '/views/car/addParkingSpaceApply',
  782 + component: () => import('@/views/car/addParkingSpaceApply.vue')
  783 + },
  784 + {
  785 + path: '/views/car/auditParkingSpaceApply',
  786 + name: '/views/car/auditParkingSpaceApply',
  787 + component: () => import('@/views/car/auditParkingSpaceApply.vue')
  788 + },
  789 + {
  790 + path: '/pages/property/carCreateFee',
  791 + name: '/pages/property/carCreateFee',
  792 + component: () => import('@/views/fee/carCreateFeeList.vue')
  793 + },
  794 + {
  795 + path: '/views/fee/listCarFee',
  796 + name: '/views/fee/listCarFee',
  797 + component: () => import('@/views/fee/listCarFeeList.vue')
  798 + },
  799 + {
  800 + path: '/pages/work/repairSetting',
  801 + name: '/pages/work/repairSetting',
  802 + component: () => import('@/views/work/repairSettingList.vue')
  803 + },
  804 + {
  805 + path:'/views/work/repairTypeUser',
  806 + name:'/views/work/repairTypeUser',
  807 + component: () => import('@/views/work/repairTypeUserList.vue')
773 808 },
774   - {
775   - path:'/pages/property/parkingSpaceApplyManage',
776   - name:'/pages/property/parkingSpaceApplyManage',
777   - component: () => import('@/views/car/parkingSpaceApplyManageList.vue')
778   - },
779   - {
780   - path:'/views/car/addParkingSpaceApply',
781   - name:'/views/car/addParkingSpaceApply',
782   - component: () => import('@/views/car/addParkingSpaceApply.vue')
783   - },
784   - {
785   - path:'/views/car/auditParkingSpaceApply',
786   - name:'/views/car/auditParkingSpaceApply',
787   - component: () => import('@/views/car/auditParkingSpaceApply.vue')
788   - },
789 809 // 其他子路由可以在这里添加
790 810 ]
791 811 },
... ...
src/views/fee/carCreateFeeLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + carCreateFee: {
  4 + queryCondition: "Query Conditions",
  5 + parkingSpacePlaceholder: "Please fill in parking lot-space, e.g. 1-101",
  6 + carNumPlaceholder: "Please fill in license plate number",
  7 + ownerNamePlaceholder: "Please fill in owner name",
  8 + parkingSpaceStatus: "Parking space status",
  9 + query: "Query",
  10 + reset: "Reset",
  11 + vehicleCharging: "Vehicle Charging",
  12 + customTemplate: "Custom Template",
  13 + customCreate: "Custom Create",
  14 + batchCreate: "Batch Create",
  15 + buyMonthlyCard: "Buy Monthly Card",
  16 + licensePlate: "License Plate",
  17 + parkingLot: "Parking Lot (Unit: No.)",
  18 + parkingSpace: "Parking Space (Unit: No.)",
  19 + ownerName: "Owner Name",
  20 + contact: "Contact",
  21 + status: "Status",
  22 + operation: "Operation",
  23 + viewCharges: "View Charges"
  24 + },
  25 + carCreateFeeAdd: {
  26 + createFee: "Create Fee",
  27 + chargeScope: "Charge Scope",
  28 + requiredChargeScope: "Required, please select charge scope",
  29 + community: "Community",
  30 + parkingLot: "Parking Lot",
  31 + vehicle: "Vehicle",
  32 + feeType: "Fee Type",
  33 + requiredFeeType: "Required, please select fee type",
  34 + feeItem: "Fee Item",
  35 + requiredFeeItem: "Required, please select fee item",
  36 + chargeAmount: "Charge Amount",
  37 + requiredChargeAmount: "Required, please fill in charge amount",
  38 + parkingSpaceStatus: "Parking Space Status",
  39 + sold: "Sold",
  40 + rented: "Rented",
  41 + startTime: "Billing Start Time",
  42 + requiredStartTime: "Required, please fill in billing start time",
  43 + endTime: "Billing End Time",
  44 + requiredEndTime: "Required, please fill in billing end time",
  45 + submit: "Submit",
  46 + cancel: "Cancel"
  47 + },
  48 + exportCarFeeImportExcel: {
  49 + templateExport: "Template Export",
  50 + parkingLot: "Parking Lot",
  51 + all: "All",
  52 + parkingLotPlaceholder: "Parking Lot",
  53 + feeItem: "Fee Item",
  54 + export: "Export",
  55 + cancel: "Cancel"
  56 + },
  57 + doImportCreateFee: {
  58 + customCreateFee: "Custom Create Fee",
  59 + selectFile: "Select File",
  60 + requiredFile: "Required, please select data file",
  61 + import: "Import",
  62 + cancel: "Cancel"
  63 + },
  64 + parkingAreaSelect2: {
  65 + parkingLotPlaceholder: "Required, please select parking lot"
  66 + }
  67 + },
  68 + zh: {
  69 + carCreateFee: {
  70 + queryCondition: "查询条件",
  71 + parkingSpacePlaceholder: "请填写停车场-车位,如 1-101",
  72 + carNumPlaceholder: "请填写车牌号",
  73 + ownerNamePlaceholder: "请填写业主名称",
  74 + parkingSpaceStatus: "请选择车位状态",
  75 + query: "查询",
  76 + reset: "重置",
  77 + vehicleCharging: "车辆收费",
  78 + customTemplate: "自定义模板",
  79 + customCreate: "自定义创建",
  80 + batchCreate: "批量创建",
  81 + buyMonthlyCard: "购买月卡",
  82 + licensePlate: "车牌号",
  83 + parkingLot: "停车场(单位:号)",
  84 + parkingSpace: "车位(单位:号)",
  85 + ownerName: "业主名称",
  86 + contact: "联系方式",
  87 + status: "车位状态",
  88 + operation: "操作",
  89 + viewCharges: "查看收费"
  90 + },
  91 + carCreateFeeAdd: {
  92 + createFee: "创建费用",
  93 + chargeScope: "收费范围",
  94 + requiredChargeScope: "必填,请选择收费范围",
  95 + community: "小区",
  96 + parkingLot: "停车场",
  97 + vehicle: "车辆",
  98 + feeType: "费用类型",
  99 + requiredFeeType: "必填,请选择费用类型",
  100 + feeItem: "收费项目",
  101 + requiredFeeItem: "必填,请选择收费项目",
  102 + chargeAmount: "收费金额",
  103 + requiredChargeAmount: "必填,请填写收费金额",
  104 + parkingSpaceStatus: "车位状态",
  105 + sold: "已出售",
  106 + rented: "已出租",
  107 + startTime: "计费起始时间",
  108 + requiredStartTime: "必填,请填写计费起始时间",
  109 + endTime: "计费结束时间",
  110 + requiredEndTime: "必填,请填写计费结束时间",
  111 + submit: "提交",
  112 + cancel: "取消"
  113 + },
  114 + exportCarFeeImportExcel: {
  115 + templateExport: "模板导出",
  116 + parkingLot: "停车场",
  117 + all: "全部",
  118 + parkingLotPlaceholder: "停车场",
  119 + feeItem: "费用项",
  120 + export: "导出",
  121 + cancel: "取消"
  122 + },
  123 + doImportCreateFee: {
  124 + customCreateFee: "自定义创建费用",
  125 + selectFile: "选择文件",
  126 + requiredFile: "必填,请选择数据文件",
  127 + import: "导入",
  128 + cancel: "取消"
  129 + },
  130 + parkingAreaSelect2: {
  131 + parkingLotPlaceholder: "必填,请选择停车场"
  132 + }
  133 + }
  134 +}
0 135 \ No newline at end of file
... ...
src/views/fee/carCreateFeeList.vue 0 → 100644
  1 +<template>
  2 + <div class="car-create-fee-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <h5>{{ $t('carCreateFee.queryCondition') }}</h5>
  6 + </div>
  7 + <el-row :gutter="20">
  8 + <el-col :span="4">
  9 + <el-input v-model.trim="queryParams.allNum" :placeholder="$t('carCreateFee.parkingSpacePlaceholder')"
  10 + @keyup.enter.native="handleQuery" />
  11 + </el-col>
  12 + <el-col :span="4">
  13 + <el-input v-model.trim="queryParams.carNumLike" :placeholder="$t('carCreateFee.carNumPlaceholder')"
  14 + @keyup.enter.native="handleQuery" />
  15 + </el-col>
  16 + <el-col :span="4">
  17 + <el-input v-model.trim="queryParams.ownerName" :placeholder="$t('carCreateFee.ownerNamePlaceholder')"
  18 + @keyup.enter.native="handleQuery" />
  19 + </el-col>
  20 + <el-col :span="4">
  21 + <el-select v-model="queryParams.state" :placeholder="$t('carCreateFee.parkingSpaceStatus')" style="width:100%">
  22 + <el-option v-for="item in states" :key="item.statusCd" :label="item.name" :value="item.statusCd" />
  23 + </el-select>
  24 + </el-col>
  25 + <el-col :span="4" style="text-align:right">
  26 + <el-button type="primary" @click="handleQuery">
  27 + <i class="el-icon-search"></i>
  28 + {{ $t('carCreateFee.query') }}
  29 + </el-button>
  30 + <el-button @click="handleReset" style="margin-left:10px">
  31 + <i class="el-icon-refresh"></i>
  32 + {{ $t('carCreateFee.reset') }}
  33 + </el-button>
  34 + </el-col>
  35 + </el-row>
  36 + </el-card>
  37 +
  38 + <el-card class="box-card" style="margin-top:20px">
  39 + <div slot="header" class="clearfix">
  40 + <h5>{{ $t('carCreateFee.vehicleCharging') }}</h5>
  41 + <div style="float:right">
  42 + <el-button @click="handleOpenFeeImportExcel">
  43 + <i class="el-icon-plus"></i>
  44 + {{ $t('carCreateFee.customTemplate') }}
  45 + </el-button>
  46 + <el-button @click="handleOpenDoCreateRoomFee" style="margin-left:10px">
  47 + <i class="el-icon-plus"></i>
  48 + {{ $t('carCreateFee.customCreate') }}
  49 + </el-button>
  50 + <el-button type="primary" @click="handleBatchCreate" style="margin-left:10px">
  51 + {{ $t('carCreateFee.batchCreate') }}
  52 + </el-button>
  53 + <el-button type="primary" @click="handleBuyMonthlyCard" style="margin-left:10px">
  54 + {{ $t('carCreateFee.buyMonthlyCard') }}
  55 + </el-button>
  56 + </div>
  57 + </div>
  58 +
  59 + <el-table :data="cars" border style="width:100%">
  60 + <el-table-column prop="carNum" :label="$t('carCreateFee.licensePlate')" align="center" />
  61 + <el-table-column prop="areaNum" :label="$t('carCreateFee.parkingLot')" align="center" />
  62 + <el-table-column prop="num" :label="$t('carCreateFee.parkingSpace')" align="center" />
  63 + <el-table-column prop="ownerName" :label="$t('carCreateFee.ownerName')" align="center" />
  64 + <el-table-column prop="link" :label="$t('carCreateFee.contact')" align="center" />
  65 + <el-table-column prop="stateName" :label="$t('carCreateFee.status')" align="center" />
  66 + <el-table-column :label="$t('carCreateFee.operation')" align="center" width="150">
  67 + <template slot-scope="scope">
  68 + <el-button size="mini" @click="handleViewCharges(scope.row)">
  69 + {{ $t('carCreateFee.viewCharges') }}
  70 + </el-button>
  71 + </template>
  72 + </el-table-column>
  73 + </el-table>
  74 +
  75 + <el-pagination style="margin-top:20px" :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]"
  76 + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
  77 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  78 + </el-card>
  79 +
  80 + <!-- 子组件 -->
  81 + <car-create-fee-add ref="carCreateFeeAdd" @success="handleSuccess" />
  82 + <export-car-fee-import-excel ref="exportCarFeeImportExcel" />
  83 + <do-import-create-fee ref="doImportCreateFee" />
  84 + </div>
  85 +</template>
  86 +
  87 +<script>
  88 +import { listCarCreateFees } from '@/api/fee/carCreateFeeApi'
  89 +import { getDict } from '@/api/community/communityApi'
  90 +
  91 +export default {
  92 + name: 'CarCreateFeeList',
  93 + components: {
  94 + 'car-create-fee-add': () => import('@/components/fee/carCreateFeeAdd'),
  95 + 'export-car-fee-import-excel': () => import('@/components/fee/exportCarFeeImportExcel'),
  96 + 'do-import-create-fee': () => import('@/components/fee/doImportCreateFee')
  97 + },
  98 + data() {
  99 + return {
  100 + queryParams: {
  101 + allNum: '',
  102 + carNumLike: '',
  103 + ownerName: '',
  104 + state: '',
  105 + carTypeCd: '1001',
  106 + page: 1,
  107 + row: 10
  108 + },
  109 + pagination: {
  110 + current: 1,
  111 + size: 10,
  112 + total: 0
  113 + },
  114 + cars: [],
  115 + states: []
  116 + }
  117 + },
  118 + created() {
  119 + this.getDictData()
  120 + this.fetchData()
  121 + },
  122 + methods: {
  123 + async getDictData() {
  124 + try {
  125 + this.states = await getDict('owner_car', 'state')
  126 + } catch (error) {
  127 + console.error('获取字典数据失败:', error)
  128 + }
  129 + },
  130 + async fetchData() {
  131 + try {
  132 + const res = await listCarCreateFees(this.queryParams)
  133 + this.cars = res.data || []
  134 + this.pagination.total = res.total || 0
  135 + } catch (error) {
  136 + this.$message.error(this.$t('common.fetchError'))
  137 + }
  138 + },
  139 + handleQuery() {
  140 + this.queryParams.page = 1
  141 + this.fetchData()
  142 + },
  143 + handleReset() {
  144 + this.queryParams = {
  145 + allNum: '',
  146 + carNumLike: '',
  147 + ownerName: '',
  148 + state: '',
  149 + carTypeCd: '1001',
  150 + page: 1,
  151 + row: this.queryParams.row
  152 + }
  153 + this.fetchData()
  154 + },
  155 + handleSizeChange(size) {
  156 + this.queryParams.row = size
  157 + this.fetchData()
  158 + },
  159 + handleCurrentChange(current) {
  160 + this.queryParams.page = current
  161 + this.fetchData()
  162 + },
  163 + handleBatchCreate() {
  164 + this.$refs.carCreateFeeAdd.open({ isMore: true })
  165 + },
  166 + handleOpenFeeImportExcel() {
  167 + this.$refs.exportCarFeeImportExcel.open()
  168 + },
  169 + handleOpenDoCreateRoomFee() {
  170 + this.$refs.doImportCreateFee.open()
  171 + },
  172 + handleBuyMonthlyCard() {
  173 + this.$router.push({ path: '/views/fee/buyCarMonthCard' })
  174 + },
  175 + handleViewCharges(row) {
  176 + this.$router.push({
  177 + path: '/views/fee/listCarFee',
  178 + query: {
  179 + carId: row.carId,
  180 + carNum: row.carNum,
  181 + areaNum: row.areaNum,
  182 + num: row.num
  183 + }
  184 + })
  185 + },
  186 + handleSuccess() {
  187 + this.fetchData()
  188 + }
  189 + }
  190 +}
  191 +</script>
  192 +
  193 +<style lang="scss" scoped>
  194 +.car-create-fee-container {
  195 + padding: 20px;
  196 +
  197 + .box-card {
  198 + margin-bottom: 20px;
  199 + }
  200 +
  201 + .clearfix {
  202 + display: flex;
  203 + justify-content: space-between;
  204 + align-items: center;
  205 +
  206 + h5 {
  207 + margin: 0;
  208 + font-size: 16px;
  209 + }
  210 + }
  211 +}
  212 +</style>
0 213 \ No newline at end of file
... ...
src/views/fee/listCarFeeLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + listCarFee: {
  4 + fee: 'Fee',
  5 + createFee: 'Create Fee',
  6 + feeItem: 'Fee Item',
  7 + feeFlag: 'Fee Flag',
  8 + feeType: 'Fee Type',
  9 + amountOwed: 'Amount Owed',
  10 + startTime: 'Start Time',
  11 + endTime: 'End Time',
  12 + remark: 'Remark',
  13 + state: 'State',
  14 + operation: 'Operation',
  15 + pay: 'Pay',
  16 + history: 'History',
  17 + cancel: 'Cancel',
  18 + change: 'Change',
  19 + split: 'Split',
  20 + detail: 'Detail',
  21 + preDegrees: 'Pre Degrees',
  22 + curDegrees: 'Cur Degrees',
  23 + price: 'Price',
  24 + additionalAmount: 'Additional Amount',
  25 + algorithm: 'Algorithm',
  26 + usage: 'Usage',
  27 + note1: 'Note: The end time "-" means the fee is not due or the fee collection has ended.',
  28 + note2: 'If the amount owed is -1, it is usually an error in the fee item formula setting, please check.'
  29 + },
  30 + },
  31 + zh: {
  32 + listCarFee: {
  33 + fee: '费用',
  34 + createFee: '创建费用',
  35 + feeItem: '费用项目',
  36 + feeFlag: '费用标识',
  37 + feeType: '费用类型',
  38 + amountOwed: '应收金额',
  39 + startTime: '建账时间',
  40 + endTime: '应收时间段',
  41 + remark: '说明',
  42 + state: '状态',
  43 + operation: '操作',
  44 + pay: '缴费',
  45 + history: '历史',
  46 + cancel: '取消',
  47 + change: '变更',
  48 + split: '拆分',
  49 + detail: '详情',
  50 + preDegrees: '上期度数',
  51 + curDegrees: '本期度数',
  52 + price: '单价',
  53 + additionalAmount: '附加费',
  54 + algorithm: '算法',
  55 + usage: '用量',
  56 + note1: '注意:应收结束时间“-”表示未到应收时间或收费已结束。',
  57 + note2: '应收金额为-1一般为费用项公式设置出错请检查。'
  58 + },
  59 + }
  60 +}
0 61 \ No newline at end of file
... ...
src/views/fee/listCarFeeList.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-card class="box-card margin">
  4 + <div slot="header" class="flex justify-between">
  5 + <div>{{ listCarFeeInfo.carNum }}
  6 + <span>{{ $t('listCarFee.fee') }}</span>({{ listCarFeeInfo.parkingName }})
  7 + </div>
  8 + <div class="ibox-tools" style="top:10px;">
  9 + <el-button type="primary" size="small" style="margin-left:10px" @click="_openCarCreateFeeAddModal">
  10 + <i class="el-icon-plus"></i>
  11 + <span>{{ $t('listCarFee.createFee') }}</span>
  12 + </el-button>
  13 + <el-button type="primary" size="small" style="margin-left:10px" @click="_goBack">
  14 + <i class="el-icon-close"></i>
  15 + <span>{{ $t('common.back') }}</span>
  16 + </el-button>
  17 + </div>
  18 + </div>
  19 + <div class="ibox-content">
  20 + <el-table :data="listCarFeeInfo.fees" border style="width: 100%">
  21 + <el-table-column prop="feeName" :label="$t('listCarFee.feeItem')" align="center">
  22 + <template slot-scope="scope">
  23 + <span class="hand" @click="_viewCarFeeConfig(scope.row)">{{ scope.row.feeName }}
  24 + <i class="el-icon-info"></i>
  25 + </span>
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column prop="feeFlagName" :label="$t('listCarFee.feeFlag')" align="center"></el-table-column>
  29 + <el-table-column prop="feeTypeCdName" :label="$t('listCarFee.feeType')" align="center"></el-table-column>
  30 + <el-table-column prop="amountOwed" :label="$t('listCarFee.amountOwed')" align="center"></el-table-column>
  31 + <el-table-column prop="startTime" :label="$t('listCarFee.startTime')" align="center"></el-table-column>
  32 + <el-table-column :label="$t('listCarFee.endTime')" align="center">
  33 + <template slot-scope="scope">
  34 + {{ _getEndTime(scope.row) }}~<br />{{ _getDeadlineTime(scope.row) }}
  35 + </template>
  36 + </el-table-column>
  37 + <el-table-column :label="$t('listCarFee.remark')" align="center" width="150">
  38 + <template slot-scope="scope">
  39 + <div v-if="scope.row.feeTypeCd == '888800010015' || scope.row.feeTypeCd == '888800010016'">
  40 + <div>
  41 + <span>{{ $t('listCarFee.preDegrees') }}:</span>{{ scope.row.preDegrees }}
  42 + </div>
  43 + <div>
  44 + <span>{{ $t('listCarFee.curDegrees') }}:</span>{{ scope.row.curDegrees }}
  45 + </div>
  46 + <div>
  47 + <span>{{ $t('listCarFee.price') }}:</span>{{ scope.row.mwPrice ? scope.row.mwPrice :
  48 + scope.row.squarePrice
  49 + }}
  50 + </div>
  51 + <div>
  52 + <span>{{ $t('listCarFee.additionalAmount') }}:</span>{{ scope.row.additionalAmount }}
  53 + </div>
  54 + </div>
  55 + <div v-else-if="scope.row.feeTypeCd == '888800010017'">
  56 + <div>
  57 + <span>{{ $t('listCarFee.algorithm') }}:</span>{{ _getAttrValue(scope.row.feeAttrs, '390005') }}
  58 + </div>
  59 + <div>
  60 + <span>{{ $t('listCarFee.usage') }}:</span>{{ _getAttrValue(scope.row.feeAttrs, '390003') }}
  61 + </div>
  62 + </div>
  63 + <div v-else>
  64 + <div>
  65 + <span>{{ $t('listCarFee.price') }}:</span>{{ scope.row.squarePrice }}
  66 + </div>
  67 + <div>
  68 + <span>{{ $t('listCarFee.additionalAmount') }}:</span>{{ scope.row.additionalAmount }}
  69 + </div>
  70 + </div>
  71 + </template>
  72 + </el-table-column>
  73 + <el-table-column prop="stateName" :label="$t('listCarFee.state')" align="center"></el-table-column>
  74 + <el-table-column :label="$t('listCarFee.operation')" align="center">
  75 + <template slot-scope="scope">
  76 + <el-button type="text" v-if="scope.row.state != '2009001' && hasPrivilege('502020082314267912')"
  77 + @click="_payFee(scope.row)">{{ $t('listCarFee.pay') }}</el-button>
  78 + <el-button type="text" @click="_payFeeHis(scope.row)">{{ $t('listCarFee.history') }}</el-button>
  79 + <el-button type="text" v-if="hasPrivilege('502020090604200029')" @click="_deleteFee(scope.row)">{{
  80 + $t('listCarFee.cancel') }}</el-button>
  81 + <el-button type="text" v-if="scope.row.state != '2009001' && hasPrivilege('502020090427190001')"
  82 + @click="_editFee(scope.row)">{{ $t('listCarFee.change') }}</el-button>
  83 + <el-button type="text" v-if="scope.row.feeFlag == '4012024' && scope.row.state == '2008001'"
  84 + @click="_splitPayFee(scope.row)">{{ $t('listCarFee.split') }}</el-button>
  85 + <el-button type="text" @click="_viewCarFee(scope.row)">{{ $t('listCarFee.detail') }}</el-button>
  86 + </template>
  87 + </el-table-column>
  88 + </el-table>
  89 + <el-row>
  90 + <el-col :span="12">
  91 + <div> {{ $t('listCarFee.note1') }}</div>
  92 + <div> {{ $t('listCarFee.note2') }}</div>
  93 + </el-col>
  94 + <el-col :span="12">
  95 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  96 + :current-page="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  97 + layout="total, sizes, prev, pager, next, jumper" :total="page.total">
  98 + </el-pagination>
  99 + </el-col>
  100 + </el-row>
  101 + </div>
  102 + </el-card>
  103 +
  104 + <!-- 子组件 -->
  105 + <delete-fee ref="deleteFee"></delete-fee>
  106 + <edit-fee ref="editFee"></edit-fee>
  107 + <split-fee ref="splitFee"></split-fee>
  108 + <car-create-fee-add ref="carCreateFeeAdd" @success="handleSuccess"></car-create-fee-add>
  109 + <!-- <add-meter-water ref="addMeterWater"></add-meter-water> -->
  110 + </div>
  111 +</template>
  112 +
  113 +<script>
  114 +import { listFee } from '@/api/fee/listCarFeeApi'
  115 +import DeleteFee from '@/components/fee/deleteFee'
  116 +import EditFee from '@/components/fee/editFee'
  117 +import SplitFee from '@/components/fee/splitFee'
  118 +import CarCreateFeeAdd from '@/components/fee/carCreateFeeAdd'
  119 +//import AddMeterWater from '@/components/fee/addMeterWater'
  120 +import { getCommunityId } from '@/api/community/communityApi'
  121 +import {dateFormat} from '@/utils/dateUtil'
  122 +
  123 +export default {
  124 + name: 'ListCarFee',
  125 + components: {
  126 + DeleteFee,
  127 + EditFee,
  128 + SplitFee,
  129 + CarCreateFeeAdd,
  130 + // AddMeterWater
  131 + },
  132 + data() {
  133 + return {
  134 + listCarFeeInfo: {
  135 + fees: [],
  136 + carNum: '',
  137 + carId: '',
  138 + total: 0,
  139 + records: 1,
  140 + areaNum: '',
  141 + num: '',
  142 + parkingName: ''
  143 + },
  144 + page: {
  145 + current: 1,
  146 + size: 10,
  147 + total: 0
  148 + },
  149 + communityId: ''
  150 + }
  151 + },
  152 + created() {
  153 + this.communityId = getCommunityId()
  154 + if (this.$route.query.carNum) {
  155 + this.listCarFeeInfo.carNum = this.$route.query.carNum
  156 + this.listCarFeeInfo.carId = this.$route.query.carId
  157 + this.listCarFeeInfo.areaNum = this.$route.query.areaNum
  158 + this.listCarFeeInfo.num = this.$route.query.num
  159 + }
  160 + let parkingName = this.listCarFeeInfo.areaNum ? `${this.listCarFeeInfo.areaNum}停车场${this.listCarFeeInfo.num}车位` : '无车位'
  161 + this.listCarFeeInfo.parkingName = parkingName
  162 + this._loadlistCarFeeInfo(1, 10)
  163 + },
  164 + methods: {
  165 + handleSuccess() {
  166 + this._loadlistCarFeeInfo(1, 10)
  167 + },
  168 + async _loadlistCarFeeInfo(page, row) {
  169 + const params = {
  170 + page: page,
  171 + row: row,
  172 + communityId: this.communityId,
  173 + payerObjId: this.listCarFeeInfo.carId
  174 + }
  175 + const { fees,total,records } = await listFee(params)
  176 + this.listCarFeeInfo.fees = fees
  177 + this.page.total = total
  178 + this.page.records = records
  179 +
  180 + },
  181 + handleSizeChange(val) {
  182 + this.page.size = val
  183 + this._loadlistCarFeeInfo(this.page.current, val)
  184 + },
  185 + handleCurrentChange(val) {
  186 + this.page.current = val
  187 + this._loadlistCarFeeInfo(val, this.page.size)
  188 + },
  189 + _payFee(fee) {
  190 + fee.roomName = this.listCarFeeInfo.carNum
  191 + this.$router.push({ path: '/fee/payFeeOrder', query: { feeId: fee.feeId } })
  192 + },
  193 + _payFeeHis(fee) {
  194 + this.$router.push({ path: '/property/propertyFee', query: fee })
  195 + },
  196 + _editFee(fee) {
  197 + this.$refs.editFee.open(fee)
  198 + },
  199 + _deleteFee(fee) {
  200 + this.$refs.deleteFee.open({
  201 + communityId: this.communityId,
  202 + feeId: fee.feeId
  203 + })
  204 + },
  205 + _openCarCreateFeeAddModal() {
  206 + this.$refs.carCreateFeeAdd.open({
  207 + isMore: false,
  208 + car: this.listCarFeeInfo
  209 + })
  210 + },
  211 + _openAddMeterWaterModal() {
  212 + this.$refs.addMeterWater.open({
  213 + roomId: this.listCarFeeInfo.carId,
  214 + roomName: this.listCarFeeInfo.carNum,
  215 + ownerName: this.listCarFeeInfo.parkingName,
  216 + objType: '6666'
  217 + })
  218 + },
  219 + _goBack() {
  220 + this.$router.go(-1)
  221 + },
  222 + _getDeadlineTime(fee) {
  223 + if (fee.amountOwed == 0 && fee.endTime == fee.deadlineTime) {
  224 + return "-"
  225 + }
  226 + if (fee.state == '2009001') {
  227 + return "-"
  228 + }
  229 + return dateFormat(fee.deadlineTime) || fee.deadlineTime
  230 + },
  231 + _getEndTime(fee) {
  232 + if (fee.state == '2009001') {
  233 + return "-"
  234 + }
  235 + return dateFormat(fee.endTime) || fee.endTime
  236 + },
  237 + _viewCarFeeConfig(fee) {
  238 + // 查看费用项配置逻辑
  239 + console.log(fee)
  240 + },
  241 + _viewCarFee(fee) {
  242 + // 查看费用详情逻辑
  243 + console.log(fee)
  244 +
  245 + },
  246 + _splitPayFee(fee) {
  247 + this.$refs.splitFee.open(fee)
  248 + },
  249 + _getAttrValue(attrs, specCd) {
  250 + const attr = attrs.find(item => item.specCd === specCd)
  251 + return attr ? attr.value : ''
  252 + },
  253 + }
  254 +}
  255 +</script>
  256 +
  257 +<style scoped>
  258 +.hand {
  259 + cursor: pointer;
  260 +}
  261 +</style>
0 262 \ No newline at end of file
... ...
src/views/work/repairSettingLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairSetting: {
  4 + queryCondition: 'Query Condition',
  5 + repairTypeNamePlaceholder: 'Please enter type name',
  6 + repairWayPlaceholder: 'Please select dispatch method',
  7 + repairSettingTypePlaceholder: 'Please select repair setting type',
  8 + publicAreaPlaceholder: 'Please select area',
  9 + returnVisitFlagPlaceholder: 'Please select whether to follow up',
  10 + search: 'Search',
  11 + reset: 'Reset',
  12 + repairSettingTitle: 'Repair Settings',
  13 + documentation: 'Documentation',
  14 + add: 'Add',
  15 + typeName: 'Type Name',
  16 + repairSettingType: 'Repair Setting Type',
  17 + dispatchMethod: 'Dispatch Method',
  18 + area: 'Area',
  19 + ownerDisplay: 'Owner Display',
  20 + notificationMethod: 'Notification Method',
  21 + returnVisit: 'Return Visit',
  22 + processingTime: 'Processing Time (hours)',
  23 + timeoutWarning: 'Timeout Warning (minutes)',
  24 + createTime: 'Create Time',
  25 + operation: 'Operation',
  26 + edit: 'Edit',
  27 + bindRepairMaster: 'Bind Repair Master',
  28 + delete: 'Delete',
  29 + explanation: 'Explanation',
  30 + save: 'Save',
  31 + cancel: 'Cancel',
  32 + confirmDeleteTitle: 'Please confirm your operation!',
  33 + confirmDeleteContent: 'Are you sure to delete this repair setting?',
  34 + cancelDelete: 'Cancel',
  35 + confirmDelete: 'Confirm Delete',
  36 + addTitle: 'Add Repair Setting',
  37 + editTitle: 'Edit Repair Setting',
  38 + settingType: 'Setting Type',
  39 + publicArea: 'Public Area',
  40 + ownerDisplayPlaceholder: 'Whether to display in owner app',
  41 + notificationMethodPlaceholder: 'Please select notification method',
  42 + returnVisitSetting: 'Return Visit Setting',
  43 + remarkPlaceholder: 'Optional, please enter remarks',
  44 + required: 'Required',
  45 + cleaningOrder: 'Cleaning Order',
  46 + repairOrder: 'Repair Order',
  47 + grabOrder: 'Grab Order',
  48 + assign: 'Assign',
  49 + polling: 'Polling',
  50 + nonHouse: 'Non-House',
  51 + house: 'House',
  52 + yes: 'Yes',
  53 + no: 'No',
  54 + sms: 'SMS',
  55 + wechat: 'WeChat',
  56 + wechatWorkLicense: 'WeChat + Employee License',
  57 + noFollowUp: 'No Follow Up',
  58 + followUpAfterEvaluation: 'Follow Up After Evaluation',
  59 + followUp: 'Follow Up',
  60 + dispatchExplanation: 'Dispatch Explanation:',
  61 + dispatchPoint1: '1. Grab Order: Employees (masters under the repair type) grab orders independently, suitable for scenarios where the property gives commissions per order',
  62 + dispatchPoint2: '2. Assign: Specifically assigned by customer service to employees (masters under the repair type)',
  63 + dispatchPoint3: '3. Polling: System periodically assigns orders to employees (masters under the repair type)',
  64 + areaExplanation: 'Area Explanation:',
  65 + areaPoint1: 'Community, building, unit are non-house areas; houses are house areas',
  66 + areaPoint2: 'Note: For owner house repairs, a house area type must be added for normal repair',
  67 + processingTimeUnit: 'Hours',
  68 + timeoutWarningUnit: 'Minutes'
  69 + }
  70 + },
  71 + zh: {
  72 + repairSetting: {
  73 + queryCondition: '查询条件',
  74 + repairTypeNamePlaceholder: '请输入类型名称',
  75 + repairWayPlaceholder: '请选择派单方式',
  76 + repairSettingTypePlaceholder: '请选择报修设置类型',
  77 + publicAreaPlaceholder: '请选择区域',
  78 + returnVisitFlagPlaceholder: '请选择是否回访',
  79 + search: '查询',
  80 + reset: '重置',
  81 + repairSettingTitle: '报修设置',
  82 + documentation: '文档',
  83 + add: '添加',
  84 + typeName: '类型名称',
  85 + repairSettingType: '报修设置类型',
  86 + dispatchMethod: '派单方式',
  87 + area: '区域',
  88 + ownerDisplay: '业主端展示',
  89 + notificationMethod: '通知方式',
  90 + returnVisit: '是否回访',
  91 + processingTime: '办理时长',
  92 + timeoutWarning: '超时预警',
  93 + createTime: '创建时间',
  94 + operation: '操作',
  95 + edit: '修改',
  96 + bindRepairMaster: '绑定维修师傅',
  97 + delete: '删除',
  98 + explanation: '说明',
  99 + save: '保存',
  100 + cancel: '取消',
  101 + confirmDeleteTitle: '请确认您的操作!',
  102 + confirmDeleteContent: '确定删除报修设置',
  103 + cancelDelete: '点错了',
  104 + confirmDelete: '确认删除',
  105 + addTitle: '添加报修设置',
  106 + editTitle: '修改报修设置',
  107 + settingType: '设置类型',
  108 + publicArea: '公共区域',
  109 + ownerDisplayPlaceholder: '必填,请选择是否在业主端展示',
  110 + notificationMethodPlaceholder: '必填,请选择通知方式',
  111 + returnVisitSetting: '回访设置',
  112 + remarkPlaceholder: '选填,请填写说明',
  113 + required: '必填',
  114 + cleaningOrder: '保洁单',
  115 + repairOrder: '维修单',
  116 + grabOrder: '抢单',
  117 + assign: '指派',
  118 + polling: '轮训',
  119 + nonHouse: '非房屋',
  120 + house: '房屋',
  121 + yes: '是',
  122 + no: '否',
  123 + sms: '短信',
  124 + wechat: '微信',
  125 + wechatWorkLicense: '微信+员工工牌',
  126 + noFollowUp: '不回访',
  127 + followUpAfterEvaluation: '已评价不回访',
  128 + followUp: '回访',
  129 + dispatchExplanation: '派单方式说明:',
  130 + dispatchPoint1: '1、抢单:员工(报修类型下的师傅)自主抢单维修处理,比较实用于物业每单给维修是否提成的场景',
  131 + dispatchPoint2: '2、指派:专门由客服派单员工(报修类型下的师傅)维修处理,一般物业的选择',
  132 + dispatchPoint3: '3、轮训:由系统定时派单员工(报修类型下的师傅)维修处理',
  133 + areaExplanation: '区域说明:',
  134 + areaPoint1: '小区、楼栋、单元为非房屋类区域,房屋为房屋类区域',
  135 + areaPoint2: '注意:一般业主房屋报修必须添加一个房屋类区域的类型才能正常报修',
  136 + processingTimeUnit: '小时',
  137 + timeoutWarningUnit: '分钟'
  138 + }
  139 + }
  140 +}
0 141 \ No newline at end of file
... ...
src/views/work/repairSettingList.vue 0 → 100644
  1 +<template>
  2 + <div class="repair-setting-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-card">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('repairSetting.queryCondition') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="5">
  10 + <el-input v-model="searchForm.repairTypeName" :placeholder="$t('repairSetting.repairTypeNamePlaceholder')"
  11 + clearable />
  12 + </el-col>
  13 + <el-col :span="5">
  14 + <el-select v-model="searchForm.repairWay" :placeholder="$t('repairSetting.repairWayPlaceholder')"
  15 + style="width:100%">
  16 + <el-option :label="$t('common.all')" value=""></el-option>
  17 + <el-option v-for="item in repairWays" :key="item.statusCd" :label="item.name" :value="item.statusCd" />
  18 + </el-select>
  19 + </el-col>
  20 + <el-col :span="5">
  21 + <el-select v-model="searchForm.repairSettingType"
  22 + :placeholder="$t('repairSetting.repairSettingTypePlaceholder')" style="width:100%">
  23 + <el-option :label="$t('common.all')" value=""></el-option>
  24 + <el-option v-for="item in repairSettingTypes" :key="item.statusCd" :label="item.name"
  25 + :value="item.statusCd" />
  26 + </el-select>
  27 + </el-col>
  28 + <el-col :span="5">
  29 + <el-select v-model="searchForm.publicArea" :placeholder="$t('repairSetting.publicAreaPlaceholder')"
  30 + style="width:100%">
  31 + <el-option :label="$t('common.all')" value=""></el-option>
  32 + <el-option v-for="item in publicAreas" :key="item.statusCd" :label="item.name" :value="item.statusCd" />
  33 + </el-select>
  34 + </el-col>
  35 + <el-col :span="4">
  36 + <el-button type="primary" @click="handleSearch">{{ $t('repairSetting.search') }}</el-button>
  37 + <el-button @click="handleReset">{{ $t('repairSetting.reset') }}</el-button>
  38 + </el-col>
  39 + </el-row>
  40 + </el-card>
  41 +
  42 + <!-- 报修设置列表 -->
  43 + <el-card class="list-card">
  44 + <div slot="header" class="flex justify-between">
  45 + <span>{{ $t('repairSetting.repairSettingTitle') }}</span>
  46 + <div style="float: right">
  47 + <el-button type="text" @click="showDocumentation">
  48 + {{ $t('repairSetting.documentation') }}
  49 + </el-button>
  50 + <el-button type="primary" size="small" @click="openAddDialog">
  51 + {{ $t('repairSetting.add') }}
  52 + </el-button>
  53 + </div>
  54 + </div>
  55 +
  56 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  57 + <el-table-column prop="repairTypeName" :label="$t('repairSetting.typeName')" align="center" />
  58 + <el-table-column prop="repairSettingTypeName" :label="$t('repairSetting.repairSettingType')" align="center" />
  59 + <el-table-column prop="repairWayName" :label="$t('repairSetting.dispatchMethod')" align="center" />
  60 + <el-table-column prop="publicArea" :label="$t('repairSetting.area')" align="center">
  61 + <template slot-scope="scope">
  62 + {{ scope.row.publicArea === 'T' ? $t('repairSetting.nonHouse') : $t('repairSetting.house') }}
  63 + </template>
  64 + </el-table-column>
  65 + <el-table-column prop="isShow" :label="$t('repairSetting.ownerDisplay')" align="center">
  66 + <template slot-scope="scope">
  67 + {{ scope.row.isShow === 'Y' ? $t('repairSetting.yes') : $t('repairSetting.no') }}
  68 + </template>
  69 + </el-table-column>
  70 + <el-table-column prop="notifyWay" :label="$t('repairSetting.notificationMethod')" align="center">
  71 + <template slot-scope="scope">
  72 + <span v-if="scope.row.notifyWay === 'SMS'">{{ $t('repairSetting.sms') }}</span>
  73 + <span v-else-if="scope.row.notifyWay === 'WORK_LICENSE'">{{ $t('repairSetting.wechatWorkLicense') }}</span>
  74 + <span v-else>{{ $t('repairSetting.wechat') }}</span>
  75 + </template>
  76 + </el-table-column>
  77 + <el-table-column prop="returnVisitFlagName" :label="$t('repairSetting.returnVisit')" align="center" />
  78 + <el-table-column prop="doTime" :label="$t('repairSetting.processingTime')" align="center">
  79 + <template slot-scope="scope">
  80 + {{ scope.row.doTime }}{{ $t('repairSetting.processingTimeUnit') }}
  81 + </template>
  82 + </el-table-column>
  83 + <el-table-column prop="warningTime" :label="$t('repairSetting.timeoutWarning')" align="center">
  84 + <template slot-scope="scope">
  85 + {{ scope.row.warningTime }}{{ $t('repairSetting.timeoutWarningUnit') }}
  86 + </template>
  87 + </el-table-column>
  88 + <el-table-column prop="createTime" :label="$t('repairSetting.createTime')" align="center" />
  89 + <el-table-column :label="$t('repairSetting.operation')" align="center" width="300">
  90 + <template slot-scope="scope">
  91 + <el-button size="mini" @click="openEditDialog(scope.row)">
  92 + {{ $t('repairSetting.edit') }}
  93 + </el-button>
  94 + <el-button size="mini" @click="bindRepairMaster(scope.row)">
  95 + {{ $t('repairSetting.bindRepairMaster') }}
  96 + </el-button>
  97 + <el-button size="mini" type="danger" @click="openDeleteDialog(scope.row)">
  98 + {{ $t('repairSetting.delete') }}
  99 + </el-button>
  100 + </template>
  101 + </el-table-column>
  102 + </el-table>
  103 +
  104 + <!-- 分页和说明 -->
  105 + <el-row :gutter="20" class="margin-top-xs">
  106 + <el-col :span="18">
  107 + <div class="explanation-section">
  108 + <p><strong>{{ $t('repairSetting.dispatchExplanation') }}</strong></p>
  109 + <p>{{ $t('repairSetting.dispatchPoint1') }}</p>
  110 + <p>{{ $t('repairSetting.dispatchPoint2') }}</p>
  111 + <p>{{ $t('repairSetting.dispatchPoint3') }}</p>
  112 + <p><strong>{{ $t('repairSetting.areaExplanation') }}</strong></p>
  113 + <p>{{ $t('repairSetting.areaPoint1') }}</p>
  114 + <p>{{ $t('repairSetting.areaPoint2') }}</p>
  115 + </div>
  116 + </el-col>
  117 + <el-col :span="6">
  118 + <el-pagination background :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]"
  119 + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
  120 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  121 + </el-col>
  122 + </el-row>
  123 + </el-card>
  124 +
  125 + <!-- 子组件 -->
  126 + <add-repair-setting ref="addDialog" @success="fetchData" />
  127 + <edit-repair-setting ref="editDialog" @success="fetchData" />
  128 + <delete-repair-setting ref="deleteDialog" @success="fetchData" />
  129 + </div>
  130 +</template>
  131 +
  132 +<script>
  133 +import { listRepairSettings } from '@/api/work/repairSettingApi'
  134 +import AddRepairSetting from '@/components/work/AddRepairSetting'
  135 +import EditRepairSetting from '@/components/work/EditRepairSetting'
  136 +import DeleteRepairSetting from '@/components/work/DeleteRepairSetting'
  137 +import {getDict} from '@/api/community/communityApi'
  138 +
  139 +export default {
  140 + name: 'RepairSettingList',
  141 + components: {
  142 + AddRepairSetting,
  143 + EditRepairSetting,
  144 + DeleteRepairSetting
  145 + },
  146 + data() {
  147 + return {
  148 + loading: false,
  149 + searchForm: {
  150 + repairTypeName: '',
  151 + repairWay: '',
  152 + repairSettingType: '',
  153 + publicArea: '',
  154 + returnVisitFlag: ''
  155 + },
  156 + tableData: [],
  157 + repairWays: [],
  158 + repairSettingTypes: [],
  159 + publicAreas: [],
  160 + returnVisitFlags: [],
  161 + pagination: {
  162 + current: 1,
  163 + size: 10,
  164 + total: 0
  165 + }
  166 + }
  167 + },
  168 + created() {
  169 + this.fetchData()
  170 + this.loadDictData()
  171 + },
  172 + methods: {
  173 + async fetchData() {
  174 + this.loading = true
  175 + try {
  176 + const params = {
  177 + page: this.pagination.current,
  178 + row: this.pagination.size,
  179 + ...this.searchForm
  180 + }
  181 +
  182 + const { data, records } = await listRepairSettings(params)
  183 + this.tableData = data
  184 + this.pagination.total = records
  185 + } catch (error) {
  186 + console.error('获取报修设置列表失败:', error)
  187 + this.$message.error(this.$t('common.fetchError'))
  188 + } finally {
  189 + this.loading = false
  190 + }
  191 + },
  192 +
  193 + async loadDictData() {
  194 + try {
  195 + this.repairWays = await getDict('r_repair_setting', 'repair_way')
  196 + this.repairSettingTypes = await getDict('r_repair_setting', 'repair_setting_type')
  197 + this.publicAreas = await getDict('r_repair_setting', 'public_area')
  198 + this.returnVisitFlags = await getDict('r_repair_setting', 'return_visit_flag')
  199 + } catch (error) {
  200 + console.error('加载字典数据失败:', error)
  201 + }
  202 + },
  203 +
  204 + handleSearch() {
  205 + this.pagination.current = 1
  206 + this.fetchData()
  207 + },
  208 +
  209 + handleReset() {
  210 + this.searchForm = {
  211 + repairTypeName: '',
  212 + repairWay: '',
  213 + repairSettingType: '',
  214 + publicArea: '',
  215 + returnVisitFlag: ''
  216 + }
  217 + this.handleSearch()
  218 + },
  219 +
  220 + handleSizeChange(size) {
  221 + this.pagination.size = size
  222 + this.fetchData()
  223 + },
  224 +
  225 + handleCurrentChange(current) {
  226 + this.pagination.current = current
  227 + this.fetchData()
  228 + },
  229 +
  230 + openAddDialog() {
  231 + this.$refs.addDialog.open()
  232 + },
  233 +
  234 + openEditDialog(row) {
  235 + this.$refs.editDialog.open(row)
  236 + },
  237 +
  238 + openDeleteDialog(row) {
  239 + this.$refs.deleteDialog.open(row)
  240 + },
  241 +
  242 + bindRepairMaster(row) {
  243 + // 跳转到绑定维修师傅页面
  244 + this.$router.push({
  245 + path: '/views/work/repairTypeUser',
  246 + query: {
  247 + settingId: row.settingId,
  248 + repairType: row.repairType,
  249 + repairTypeName: row.repairTypeName
  250 + }
  251 + })
  252 + },
  253 +
  254 + showDocumentation() {
  255 + // 显示文档逻辑
  256 + console.log('Show documentation')
  257 + }
  258 + }
  259 +}
  260 +</script>
  261 +
  262 +<style lang="scss" scoped>
  263 +.repair-setting-container {
  264 + padding: 20px;
  265 +
  266 + .search-card {
  267 + margin-bottom: 20px;
  268 + }
  269 +
  270 + .list-card {
  271 + margin-bottom: 20px;
  272 + }
  273 +
  274 + .margin-top-xs {
  275 + margin-top: 20px;
  276 + }
  277 +
  278 + .explanation-section {
  279 + background-color: #f8f9fa;
  280 + padding: 15px;
  281 + border-radius: 4px;
  282 + font-size: 14px;
  283 + line-height: 1.6;
  284 +
  285 + p {
  286 + margin-bottom: 8px;
  287 + }
  288 + }
  289 +}
  290 +</style>
0 291 \ No newline at end of file
... ...
src/views/work/repairTypeUserLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + repairTypeUser: {
  4 + title: 'Repair Master',
  5 + repairMasterId: 'Repair Master ID',
  6 + masterName: 'Master Name',
  7 + repairType: 'Repair Type',
  8 + status: 'Status',
  9 + description: 'Description',
  10 + createTime: 'Create Time',
  11 + operation: 'Operation',
  12 + repairTypeRequired: 'Repair type is required'
  13 + },
  14 + selectStaff: {
  15 + title: 'Select Staff',
  16 + orgInfo: 'Organization Information',
  17 + staffInfo: 'Staff Information',
  18 + selectStaffFirst: 'Please select a staff first'
  19 + },
  20 + deleteRepairTypeUser: {
  21 + title: 'Confirm Operation',
  22 + confirmDelete: 'Are you sure to delete this repair master?'
  23 + },
  24 + editRepairTypeUser: {
  25 + title: 'Modify Repair Master',
  26 + status: 'Status',
  27 + description: 'Description',
  28 + online: 'Online',
  29 + offline: 'Offline',
  30 + descriptionPlaceholder: 'Optional, please enter description',
  31 + statusRequired: 'Status is required'
  32 + }
  33 + },
  34 + zh: {
  35 + repairTypeUser: {
  36 + title: '报修师傅',
  37 + repairMasterId: '维修师傅ID',
  38 + masterName: '师傅名称',
  39 + repairType: '报修类型',
  40 + status: '状态',
  41 + description: '说明',
  42 + createTime: '创建时间',
  43 + operation: '操作',
  44 + repairTypeRequired: '未包含报修类型'
  45 + },
  46 + selectStaff: {
  47 + title: '选择员工',
  48 + orgInfo: '组织信息',
  49 + staffInfo: '员工信息',
  50 + selectStaffFirst: '请先选择员工'
  51 + },
  52 + deleteRepairTypeUser: {
  53 + title: '请确认您的操作',
  54 + confirmDelete: '确定删除报修师傅?'
  55 + },
  56 + editRepairTypeUser: {
  57 + title: '变更报修师傅',
  58 + status: '状态',
  59 + description: '说明',
  60 + online: '在线',
  61 + offline: '离线',
  62 + descriptionPlaceholder: '选填,请填写说明',
  63 + statusRequired: '状态不能为空'
  64 + }
  65 + }
  66 +}
0 67 \ No newline at end of file
... ...
src/views/work/repairTypeUserList.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row>
  4 + <el-col :span="24">
  5 + <el-card class="box-card">
  6 + <div slot="header" class="clearfix">
  7 + <h5>{{ $t('repairTypeUser.title') }}</h5>
  8 + <div class="ibox-tools" style="top:10px;">
  9 + <el-button type="primary" size="small" @click="_goBack">
  10 + <i class="el-icon-close"></i>{{ $t('common.back') }}
  11 + </el-button>
  12 + <el-button type="primary" size="small" @click="_openAddRepairTypeUserModal">
  13 + <i class="el-icon-plus"></i>{{ $t('common.add') }}
  14 + </el-button>
  15 + </div>
  16 + </div>
  17 + <div class="ibox-content">
  18 + <el-table :data="repairTypeUserManageInfo.repairTypeUsers" style="width: 100%" border stripe>
  19 + <el-table-column prop="staffId" :label="$t('repairTypeUser.repairMasterId')" align="center" />
  20 + <el-table-column prop="staffName" :label="$t('repairTypeUser.masterName')" align="center" />
  21 + <el-table-column prop="repairTypeName" :label="$t('repairTypeUser.repairType')" align="center" />
  22 + <el-table-column prop="stateName" :label="$t('repairTypeUser.status')" align="center" />
  23 + <el-table-column prop="remark" :label="$t('repairTypeUser.description')" align="center" />
  24 + <el-table-column prop="createTime" :label="$t('repairTypeUser.createTime')" align="center" />
  25 + <el-table-column :label="$t('common.operation')" align="center">
  26 + <template slot-scope="scope">
  27 + <el-button-group>
  28 + <el-button size="mini" @click="_openDeleteTypeUserModel(scope.row)">
  29 + {{ $t('common.delete') }}
  30 + </el-button>
  31 + <el-button size="mini" @click="_openEditrepairTypeUserModel(scope.row)">
  32 + {{ $t('common.change') }}
  33 + </el-button>
  34 + </el-button-group>
  35 + </template>
  36 + </el-table-column>
  37 + </el-table>
  38 + <el-pagination :current-page="currentPage" :page-sizes="[10, 20, 30, 50]" :page-size="pageSize"
  39 + layout="total, sizes, prev, pager, next, jumper" :total="repairTypeUserManageInfo.total"
  40 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  41 + </div>
  42 + </el-card>
  43 + </el-col>
  44 + </el-row>
  45 +
  46 + <SelectStaff ref="selectStaff" />
  47 + <DeleteRepairTypeUser ref="deleteRepairTypeUser" @success="handleDeleteSuccess" />
  48 + <EditRepairTypeUser ref="editRepairTypeUser" @success="handleEditSuccess" />
  49 + </div>
  50 +</template>
  51 +
  52 +<script>
  53 +import { listRepairTypeUsers, saveRepairTypeUser } from '@/api/work/repairTypeUserApi'
  54 +import { getCommunityId } from '@/api/community/communityApi'
  55 +import SelectStaff from '@/components/work/SelectStaff'
  56 +import DeleteRepairTypeUser from '@/components/work/DeleteRepairTypeUser'
  57 +import EditRepairTypeUser from '@/components/work/EditRepairTypeUser'
  58 +
  59 +export default {
  60 + name: 'RepairTypeUserList',
  61 + components: {
  62 + SelectStaff,
  63 + DeleteRepairTypeUser,
  64 + EditRepairTypeUser
  65 + },
  66 + data() {
  67 + return {
  68 + repairTypeUserManageInfo: {
  69 + repairTypeUsers: [],
  70 + total: 0,
  71 + records: 1,
  72 + repairType: '',
  73 + conditions: {
  74 + repairTypeName: '',
  75 + repairWay: '',
  76 + repairType: ''
  77 + }
  78 + },
  79 + currentPage: 1,
  80 + pageSize: 10
  81 + }
  82 + },
  83 + created() {
  84 + this.repairTypeUserManageInfo.repairType = this.$route.query.repairType
  85 + this._listRepairTypeUsers(this.currentPage, this.pageSize)
  86 + },
  87 + methods: {
  88 + async _listRepairTypeUsers(page, size) {
  89 + try {
  90 + const communityId = await getCommunityId()
  91 + const params = {
  92 + page: page,
  93 + row: size,
  94 + communityId: communityId,
  95 + repairType: this.repairTypeUserManageInfo.repairType
  96 + }
  97 +
  98 + const response = await listRepairTypeUsers(params)
  99 + if (response.code === 0) {
  100 + this.repairTypeUserManageInfo.repairTypeUsers = response.data
  101 + this.repairTypeUserManageInfo.total = response.total
  102 + } else {
  103 + this.$message.error(response.msg || this.$t('common.requestFailed'))
  104 + }
  105 + } catch (error) {
  106 + console.error('Error fetching repair type users:', error)
  107 + this.$message.error(this.$t('common.requestFailed'))
  108 + }
  109 + },
  110 + handleSizeChange(val) {
  111 + this.pageSize = val
  112 + this._listRepairTypeUsers(this.currentPage, val)
  113 + },
  114 + handleCurrentChange(val) {
  115 + this.currentPage = val
  116 + this._listRepairTypeUsers(val, this.pageSize)
  117 + },
  118 + _openAddRepairTypeUserModal() {
  119 + this.$refs.selectStaff.open({
  120 + call: (staff) => {
  121 + this.saveRepairTypeUserInfo(staff)
  122 + }
  123 + })
  124 + },
  125 + _openEditrepairTypeUserModel(row) {
  126 + this.$refs.editRepairTypeUser.open(row)
  127 + },
  128 + _openDeleteTypeUserModel(row) {
  129 + this.$refs.deleteRepairTypeUser.open(row)
  130 + },
  131 + _goBack() {
  132 + this.$router.go(-1)
  133 + },
  134 + async saveRepairTypeUserInfo(staff) {
  135 + try {
  136 + const communityId = await getCommunityId()
  137 + const data = {
  138 + communityId: communityId,
  139 + staffId: staff.staffId,
  140 + staffName: staff.staffName,
  141 + repairType: this.repairTypeUserManageInfo.repairType
  142 + }
  143 +
  144 + const response = await saveRepairTypeUser(data)
  145 + if (response.code === 0) {
  146 + this.$message.success(this.$t('common.saveSuccess'))
  147 + this._listRepairTypeUsers(this.currentPage, this.pageSize)
  148 + } else {
  149 + this.$message.error(response.msg || this.$t('common.saveFailed'))
  150 + }
  151 + } catch (error) {
  152 + console.error('Error saving repair type user:', error)
  153 + this.$message.error(this.$t('common.saveFailed'))
  154 + }
  155 + },
  156 + handleDeleteSuccess() {
  157 + this._listRepairTypeUsers(this.currentPage, this.pageSize)
  158 + },
  159 + handleEditSuccess() {
  160 + this._listRepairTypeUsers(this.currentPage, this.pageSize)
  161 + }
  162 + }
  163 +}
  164 +</script>
  165 +
  166 +<style scoped>
  167 +.ibox-tools {
  168 + position: absolute;
  169 + right: 15px;
  170 + top: 10px;
  171 +}
  172 +
  173 +.clearfix {
  174 + position: relative;
  175 +}
  176 +</style>
0 177 \ No newline at end of file
... ...