Commit ce5e1a2a9f3073eb75e17ffbacd4e7f791be38d9

Authored by wuxw
1 parent 03f63ab4

系统模块开发中

Showing 37 changed files with 4923 additions and 3 deletions
src/api/system/feePrintSpecManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询打印配置列表
  5 +export function queryFeePrintSpec(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const defaultParams = {
  8 + communityId: getCommunityId(),
  9 + ...params
  10 + }
  11 + request({
  12 + url: '/feePrintSpec/queryFeePrintSpec',
  13 + method: 'get',
  14 + params: defaultParams
  15 + }).then(response => {
  16 + const res = response.data
  17 + resolve({
  18 + data: res.data,
  19 + total: res.total
  20 + })
  21 + }).catch(error => {
  22 + reject(error)
  23 + })
  24 + })
  25 +}
  26 +
  27 +// 添加打印配置
  28 +export function saveFeePrintSpec(data) {
  29 + return new Promise((resolve, reject) => {
  30 + const postData = {
  31 + ...data,
  32 + communityId: getCommunityId()
  33 + }
  34 + request({
  35 + url: '/feePrintSpec/saveFeePrintSpec',
  36 + method: 'post',
  37 + data: postData
  38 + }).then(response => {
  39 + const res = response.data
  40 + if (res.code === 0) {
  41 + resolve(res)
  42 + } else {
  43 + reject(new Error(res.msg || 'Add failed'))
  44 + }
  45 + }).catch(error => {
  46 + reject(error)
  47 + })
  48 + })
  49 +}
  50 +
  51 +// 更新打印配置
  52 +export function updateFeePrintSpec(data) {
  53 + return new Promise((resolve, reject) => {
  54 + const postData = {
  55 + ...data,
  56 + communityId: getCommunityId()
  57 + }
  58 + request({
  59 + url: '/feePrintSpec/updateFeePrintSpec',
  60 + method: 'post',
  61 + data: postData
  62 + }).then(response => {
  63 + const res = response.data
  64 + if (res.code === 0) {
  65 + resolve(res)
  66 + } else {
  67 + reject(new Error(res.msg || 'Update failed'))
  68 + }
  69 + }).catch(error => {
  70 + reject(error)
  71 + })
  72 + })
  73 +}
  74 +
  75 +// 删除打印配置
  76 +export function deleteFeePrintSpec(data) {
  77 + return new Promise((resolve, reject) => {
  78 + const postData = {
  79 + ...data,
  80 + communityId: getCommunityId()
  81 + }
  82 + request({
  83 + url: '/feePrintSpec/deleteFeePrintSpec',
  84 + method: 'post',
  85 + data: postData
  86 + }).then(response => {
  87 + const res = response.data
  88 + if (res.code === 0) {
  89 + resolve(res)
  90 + } else {
  91 + reject(new Error(res.msg || 'Delete failed'))
  92 + }
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
0 98 \ No newline at end of file
... ...
src/api/system/historyFeeDetailImportApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * Import historical fee detail data
  5 + * @param {FormData} formData
  6 + * @returns {Promise}
  7 + */
  8 +export function importData(formData) {
  9 + return new Promise((resolve, reject) => {
  10 + request({
  11 + url: '/assetImport/importData',
  12 + method: 'post',
  13 + data: formData,
  14 + headers: {
  15 + 'Content-Type': 'multipart/form-data'
  16 + }
  17 + }).then(response => {
  18 + resolve(response.data)
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
  24 +
  25 +/**
  26 + * Download house template
  27 + * @returns {Promise}
  28 + */
  29 +export function downloadHouseTemplate() {
  30 + return new Promise((resolve, reject) => {
  31 + request({
  32 + url: '/import/importFeeDetail.xlsx',
  33 + method: 'get',
  34 + responseType: 'blob'
  35 + }).then(response => {
  36 + resolve(response.data)
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +/**
  44 + * Download car template
  45 + * @returns {Promise}
  46 + */
  47 +export function downloadCarTemplate() {
  48 + return new Promise((resolve, reject) => {
  49 + request({
  50 + url: '/import/importCarFeeDetail.xlsx',
  51 + method: 'get',
  52 + responseType: 'blob'
  53 + }).then(response => {
  54 + resolve(response.data)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
0 60 \ No newline at end of file
... ...
src/api/system/operateDataLogApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询费用项历史记录
  4 +export function queryHisFeeConfig(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/fee.queryHisFeeConfig',
  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 queryHisFee(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/fee.queryHisFee',
  24 + method: 'get',
  25 + params
  26 + }).then(response => {
  27 + const res = response.data
  28 + resolve(res)
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +// 查询业主历史记录
  36 +export function queryHisOwner(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/owner.queryHisOwner',
  40 + method: 'get',
  41 + params
  42 + }).then(response => {
  43 + const res = response.data
  44 + resolve(res)
  45 + }).catch(error => {
  46 + reject(error)
  47 + })
  48 + })
  49 +}
  50 +
  51 +// 获取业主属性规格
  52 +export function getAttrSpec(attrType) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/attrSpec.listAttrSpec',
  56 + method: 'get',
  57 + params: { attrType }
  58 + }).then(response => {
  59 + const res = response.data
  60 + resolve(res)
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 查询房屋历史记录
  68 +export function queryHisRoom(params) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/room.queryHisRoom',
  72 + method: 'get',
  73 + params
  74 + }).then(response => {
  75 + const res = response.data
  76 + resolve(res)
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 查询车辆历史记录
  84 +export function queryHisOwnerCar(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/car.queryHisOwnerCar',
  88 + method: 'get',
  89 + params
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
  98 +
  99 +// 查询合同变更计划
  100 +export function queryContractChangePlan(params) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/contract/queryContractChangePlan',
  104 + method: 'get',
  105 + params
  106 + }).then(response => {
  107 + const res = response.data
  108 + resolve(res)
  109 + }).catch(error => {
  110 + reject(error)
  111 + })
  112 + })
  113 +}
0 114 \ No newline at end of file
... ...
src/api/system/paymentPoolApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取支付池列表
  5 +export function listPaymentPool(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/payment.listPaymentPool',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 添加支付配置
  24 +export function savePaymentPool(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/payment.savePaymentPool',
  28 + method: 'post',
  29 + data: {
  30 + ...data,
  31 + communityId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 修改支付配置
  43 +export function updatePaymentPool(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/payment.updatePaymentPool',
  47 + method: 'post',
  48 + data: {
  49 + ...data,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 删除支付配置
  62 +export function deletePaymentPool(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/payment.deletePaymentPool',
  66 + method: 'post',
  67 + data: {
  68 + ...data,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
  79 +
  80 +// 获取支付适配器列表
  81 +export function listPaymentAdapt(params) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/payment.listPaymentAdapt',
  85 + method: 'get',
  86 + params
  87 + }).then(response => {
  88 + const res = response.data
  89 + resolve(res)
  90 + }).catch(error => {
  91 + reject(error)
  92 + })
  93 + })
  94 +}
  95 +
  96 +// 获取支付密钥列表
  97 +export function listPaymentKey(params) {
  98 + return new Promise((resolve, reject) => {
  99 + request({
  100 + url: '/payment.listPaymentKey',
  101 + method: 'get',
  102 + params
  103 + }).then(response => {
  104 + const res = response.data
  105 + resolve(res)
  106 + }).catch(error => {
  107 + reject(error)
  108 + })
  109 + })
  110 +}
  111 +
  112 +// 获取支付配置详情
  113 +export function getPaymentPoolDetail(params) {
  114 + return new Promise((resolve, reject) => {
  115 + request({
  116 + url: '/payment.listPaymentPool',
  117 + method: 'get',
  118 + params: {
  119 + ...params,
  120 + communityId: getCommunityId(),
  121 + page: 1,
  122 + row: 1
  123 + }
  124 + }).then(response => {
  125 + const res = response.data
  126 + resolve(res)
  127 + }).catch(error => {
  128 + reject(error)
  129 + })
  130 + })
  131 +}
  132 +
  133 +// 获取费用配置列表
  134 +export function listFeeConfigs(params) {
  135 + return new Promise((resolve, reject) => {
  136 + request({
  137 + url: '/feeConfig.listFeeConfigs',
  138 + method: 'get',
  139 + params: {
  140 + ...params,
  141 + communityId: getCommunityId()
  142 + }
  143 + }).then(response => {
  144 + const res = response.data
  145 + resolve(res)
  146 + }).catch(error => {
  147 + reject(error)
  148 + })
  149 + })
  150 +}
  151 +
  152 +// 上传文件
  153 +export function uploadFile(data, config) {
  154 + return new Promise((resolve, reject) => {
  155 + request({
  156 + url: '/uploadVedio/upload',
  157 + method: 'post',
  158 + data,
  159 + headers: {
  160 + 'Content-Type': 'multipart/form-data'
  161 + },
  162 + ...config
  163 + }).then(response => {
  164 + const res = response.data
  165 + resolve(res)
  166 + }).catch(error => {
  167 + reject(error)
  168 + })
  169 + })
  170 +}
0 171 \ No newline at end of file
... ...
src/api/system/publicWeChatManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取公众号列表
  5 +export function listSmallWeChats(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/smallWeChat.listSmallWeChats',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve({
  17 + data: res.smallWeChats,
  18 + total: res.total || 0
  19 + })
  20 + }).catch(error => {
  21 + reject(error)
  22 + })
  23 + })
  24 +}
  25 +
  26 +// 添加公众号
  27 +export function saveSmallWeChat(data) {
  28 + return new Promise((resolve, reject) => {
  29 + request({
  30 + url: '/smallWeChat.saveSmallWeChat',
  31 + method: 'post',
  32 + data: {
  33 + ...data,
  34 + objId: getCommunityId()
  35 + }
  36 + }).then(response => {
  37 + const res = response.data
  38 + resolve(res)
  39 + }).catch(error => {
  40 + reject(error)
  41 + })
  42 + })
  43 +}
  44 +
  45 +// 更新公众号信息
  46 +export function updateSmallWeChat(data) {
  47 + return new Promise((resolve, reject) => {
  48 + request({
  49 + url: '/smallWeChat.updateSmallWeChat',
  50 + method: 'post',
  51 + data: {
  52 + ...data,
  53 + objId: getCommunityId()
  54 + }
  55 + }).then(response => {
  56 + const res = response.data
  57 + resolve(res)
  58 + }).catch(error => {
  59 + reject(error)
  60 + })
  61 + })
  62 +}
  63 +
  64 +// 删除公众号
  65 +export function deleteSmallWeChat(data) {
  66 + return new Promise((resolve, reject) => {
  67 + request({
  68 + url: '/smallWeChat.deleteSmallWeChat',
  69 + method: 'post',
  70 + data: {
  71 + ...data,
  72 + communityId: getCommunityId()
  73 + }
  74 + }).then(response => {
  75 + const res = response.data
  76 + resolve(res)
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
0 82 \ No newline at end of file
... ...
src/api/system/smallWeChatManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取小程序列表
  5 +export function listSmallWeChats(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/smallWeChat.listSmallWeChats',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId()
  13 + }
  14 + }).then(response => {
  15 + const res = response.data
  16 + resolve(res)
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 添加小程序
  24 +export function saveSmallWeChat(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/smallWeChat.saveSmallWeChat',
  28 + method: 'post',
  29 + data: {
  30 + ...data,
  31 + objId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 更新小程序
  43 +export function updateSmallWeChat(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/smallWeChat.updateSmallWeChat',
  47 + method: 'post',
  48 + data: {
  49 + ...data,
  50 + objId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 删除小程序
  62 +export function deleteSmallWeChat(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/smallWeChat.deleteSmallWeChat',
  66 + method: 'post',
  67 + data: {
  68 + ...data,
  69 + communityId: getCommunityId()
  70 + }
  71 + }).then(response => {
  72 + const res = response.data
  73 + resolve(res)
  74 + }).catch(error => {
  75 + reject(error)
  76 + })
  77 + })
  78 +}
  79 +
  80 +// 获取小程序字典数据
  81 +export function getSmallWeChatDict(dictType, dictCode) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/dict.getDict',
  85 + method: 'get',
  86 + params: {
  87 + dictType,
  88 + dictCode
  89 + }
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
0 98 \ No newline at end of file
... ...
src/components/system/addFeePrintSpec.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('feePrintSpecManage.addTitle')" :visible.sync="visible" width="50%" @close="resetForm">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('feePrintSpecManage.spec')" prop="specCd">
  5 + <el-select v-model="formData.specCd" style="width:100%" :placeholder="$t('feePrintSpecManage.specPlaceholder')">
  6 + <el-option v-for="item in specOptions" :key="item.value" :label="item.label" :value="item.value">
  7 + </el-option>
  8 + </el-select>
  9 + </el-form-item>
  10 +
  11 + <el-form-item :label="$t('feePrintSpecManage.name')" prop="printName">
  12 + <el-input v-model="formData.printName" :placeholder="$t('feePrintSpecManage.namePlaceholder')">
  13 + </el-input>
  14 + </el-form-item>
  15 +
  16 + <el-form-item :label="$t('feePrintSpecManage.image')" prop="qrImg">
  17 + <upload-image-url ref="uploader" :image-count="1" @notifyUploadCoverImage="handleImageChange">
  18 + </upload-image-url>
  19 + </el-form-item>
  20 +
  21 + <el-form-item :label="$t('feePrintSpecManage.content')">
  22 + <el-input type="textarea" :rows="5" v-model="formData.content"
  23 + :placeholder="$t('feePrintSpecManage.contentPlaceholder')">
  24 + </el-input>
  25 + </el-form-item>
  26 + </el-form>
  27 +
  28 + <span slot="footer" class="dialog-footer">
  29 + <el-button @click="visible = false">
  30 + {{ $t('common.cancel') }}
  31 + </el-button>
  32 + <el-button type="primary" @click="submitForm" :loading="submitting">
  33 + {{ $t('common.confirm') }}
  34 + </el-button>
  35 + </span>
  36 + </el-dialog>
  37 +</template>
  38 +
  39 +<script>
  40 +import { saveFeePrintSpec } from '@/api/system/feePrintSpecManageApi'
  41 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  42 +import { getCommunityId } from '@/api/community/communityApi'
  43 +
  44 +export default {
  45 + name: 'AddFeePrintSpec',
  46 + components: {
  47 + UploadImageUrl
  48 + },
  49 + data() {
  50 + return {
  51 + visible: false,
  52 + submitting: false,
  53 + formData: {
  54 + specCd: '',
  55 + printName: '',
  56 + qrImg: '',
  57 + content: '',
  58 + communityId: ''
  59 + },
  60 + rules: {
  61 + specCd: [
  62 + { required: true, message: this.$t('feePrintSpecManage.specRequired'), trigger: 'blur' }
  63 + ],
  64 + printName: [
  65 + { required: true, message: this.$t('feePrintSpecManage.nameRequired'), trigger: 'blur' },
  66 + { max: 128, message: this.$t('feePrintSpecManage.nameMaxLength'), trigger: 'blur' }
  67 + ]
  68 + },
  69 + specOptions: [
  70 + { value: '1010', label: this.$t('feePrintSpecManage.reminderPrint') },
  71 + { value: '2020', label: this.$t('feePrintSpecManage.receiptPrint') }
  72 + ]
  73 + }
  74 + },
  75 + methods: {
  76 + open() {
  77 + this.visible = true
  78 + this.formData.communityId = getCommunityId()
  79 + this.$nextTick(() => {
  80 + this.$refs.uploader.clear()
  81 + })
  82 + },
  83 + handleImageChange(images) {
  84 + if (images && images.length > 0) {
  85 + this.formData.qrImg = images[0]
  86 + } else {
  87 + this.formData.qrImg = ''
  88 + }
  89 + },
  90 + submitForm() {
  91 + this.$refs.form.validate(async valid => {
  92 + if (!valid) return
  93 +
  94 + this.submitting = true
  95 + try {
  96 + await saveFeePrintSpec(this.formData)
  97 + this.$message.success(this.$t('feePrintSpecManage.addSuccess'))
  98 + this.visible = false
  99 + this.$emit('success')
  100 + } catch (error) {
  101 + this.$message.error(error.message || this.$t('feePrintSpecManage.addFailed'))
  102 + } finally {
  103 + this.submitting = false
  104 + }
  105 + })
  106 + },
  107 + resetForm() {
  108 + this.$refs.form.resetFields()
  109 + this.formData = {
  110 + specCd: '',
  111 + printName: '',
  112 + qrImg: '',
  113 + content: '',
  114 + communityId: ''
  115 + }
  116 + }
  117 + }
  118 +}
  119 +</script>
0 120 \ No newline at end of file
... ...
src/components/system/addPaymentPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('paymentPool.add.title')" :visible.sync="visible" width="50%" @close="handleClose">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('paymentPool.add.paymentName')" prop="paymentName">
  5 + <el-input v-model="formData.paymentName" :placeholder="$t('paymentPool.add.paymentNamePlaceholder')" />
  6 + </el-form-item>
  7 +
  8 + <el-form-item :label="$t('paymentPool.add.paymentType')" prop="paymentType">
  9 + <el-select v-model="formData.paymentType" :placeholder="$t('paymentPool.add.paymentTypePlaceholder')"
  10 + style="width:100%" @change="handlePaymentTypeChange">
  11 + <el-option v-for="item in paymentTypes" :key="item.paymentType" :label="item.name"
  12 + :value="item.paymentType" />
  13 + </el-select>
  14 + </el-form-item>
  15 +
  16 + <el-form-item v-for="(item, index) in paymentKeys" :key="index" :label="item.name">
  17 + <el-input v-model="item.columnValue" type="textarea" :placeholder="item.remark" :rows="3" />
  18 + </el-form-item>
  19 +
  20 + <el-form-item v-if="formData.paymentType === 'WECHAT'" :label="$t('paymentPool.add.certFile')">
  21 + <upload-file ref="uploadFile" :call-back-listener="'addPaymentPool'" :call-back-function="'notifyCert'" />
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('paymentPool.add.payRange')" prop="payType">
  25 + <el-select v-model="formData.payType" :placeholder="$t('paymentPool.add.payRangePlaceholder')"
  26 + style="width:100%">
  27 + <el-option :label="$t('paymentPool.add.communityFee')" value="1001" />
  28 + <el-option :label="$t('paymentPool.add.tempCarFee')" value="2002" />
  29 + <el-option :label="$t('paymentPool.add.specifiedFee')" value="3003" />
  30 + </el-select>
  31 + </el-form-item>
  32 +
  33 + <el-form-item v-if="formData.payType === '3003'" :label="$t('paymentPool.add.feeItems')">
  34 + <el-checkbox-group v-model="formData.configIds">
  35 + <el-checkbox v-for="item in feeConfigs" :key="item.configId" :label="item.configId">
  36 + {{ item.feeName }}
  37 + </el-checkbox>
  38 + </el-checkbox-group>
  39 + </el-form-item>
  40 +
  41 + <el-form-item :label="$t('paymentPool.add.remark')">
  42 + <el-input v-model="formData.remark" type="textarea" :placeholder="$t('paymentPool.add.remarkPlaceholder')"
  43 + :rows="3" />
  44 + </el-form-item>
  45 + </el-form>
  46 +
  47 + <div slot="footer" class="dialog-footer">
  48 + <el-button @click="visible = false">
  49 + {{ $t('common.cancel') }}
  50 + </el-button>
  51 + <el-button type="primary" @click="handleSubmit">
  52 + {{ $t('common.confirm') }}
  53 + </el-button>
  54 + </div>
  55 + </el-dialog>
  56 +</template>
  57 +
  58 +<script>
  59 +import { savePaymentPool, listPaymentKey, listFeeConfigs,listPaymentAdapt } from '@/api/system/paymentPoolApi'
  60 +import UploadFile from '@/components/upload/FileUpload'
  61 +import { getCommunityId } from '@/api/community/communityApi'
  62 +
  63 +export default {
  64 + name: 'AddPaymentPool',
  65 + components: {
  66 + UploadFile
  67 + },
  68 + props: {
  69 + callBackListener: {
  70 + type: String,
  71 + default: ''
  72 + },
  73 + callBackFunction: {
  74 + type: String,
  75 + default: ''
  76 + }
  77 + },
  78 + data() {
  79 + return {
  80 + visible: false,
  81 + formData: {
  82 + paymentName: '',
  83 + paymentType: '',
  84 + certPath: '',
  85 + state: 'Y',
  86 + remark: '',
  87 + payType: '1001',
  88 + configIds: [],
  89 + communityId: ''
  90 + },
  91 + paymentTypes: [],
  92 + paymentKeys: [],
  93 + feeConfigs: [],
  94 + rules: {
  95 + paymentName: [
  96 + { required: true, message: this.$t('paymentPool.validate.paymentNameRequired'), trigger: 'blur' },
  97 + { max: 64, message: this.$t('paymentPool.validate.paymentNameMaxLength'), trigger: 'blur' }
  98 + ],
  99 + paymentType: [
  100 + { required: true, message: this.$t('paymentPool.validate.paymentTypeRequired'), trigger: 'change' }
  101 + ],
  102 + payType: [
  103 + { required: true, message: this.$t('paymentPool.validate.payTypeRequired'), trigger: 'change' }
  104 + ]
  105 + }
  106 + }
  107 + },
  108 + created() {
  109 + this.formData.communityId = getCommunityId()
  110 + this.getPaymentTypes()
  111 + this.$on('notifyCert', this.handleNotifyCert)
  112 + },
  113 + methods: {
  114 + open() {
  115 + this.visible = true
  116 + this.getFeeConfigs()
  117 + if (this.$refs.uploadFile) {
  118 + this.$refs.uploadFile.clear()
  119 + }
  120 + },
  121 + handleClose() {
  122 + this.$refs.form.resetFields()
  123 + this.formData = {
  124 + paymentName: '',
  125 + paymentType: '',
  126 + certPath: '',
  127 + state: 'Y',
  128 + remark: '',
  129 + payType: '1001',
  130 + configIds: [],
  131 + communityId: getCommunityId()
  132 + }
  133 + this.paymentKeys = []
  134 + },
  135 + async getPaymentTypes() {
  136 + try {
  137 + const { data } = await listPaymentAdapt({
  138 + page: 1,
  139 + row: 100,
  140 + })
  141 + this.paymentTypes = data
  142 + } catch (error) {
  143 + console.error('获取支付类型失败:', error)
  144 + }
  145 + },
  146 + async getFeeConfigs() {
  147 + try {
  148 + const params = {
  149 + page: 1,
  150 + row: 100,
  151 + isDefault: 'F',
  152 + communityId: this.formData.communityId
  153 + }
  154 + const { data } = await listFeeConfigs(params)
  155 + this.feeConfigs = data
  156 + } catch (error) {
  157 + console.error('获取费用配置失败:', error)
  158 + }
  159 + },
  160 + async handlePaymentTypeChange() {
  161 + if (!this.formData.paymentType) return
  162 +
  163 + try {
  164 + const params = {
  165 + paymentType: this.formData.paymentType,
  166 + page: 1,
  167 + row: 100
  168 + }
  169 + const { data } = await listPaymentKey(params)
  170 + this.paymentKeys = data.map(item => ({
  171 + ...item,
  172 + columnValue: ''
  173 + }))
  174 + } catch (error) {
  175 + console.error('获取支付密钥失败:', error)
  176 + }
  177 + },
  178 + handleNotifyCert(param) {
  179 + this.formData.certPath = param.realFileName
  180 + },
  181 + handleSubmit() {
  182 + this.$refs.form.validate(async valid => {
  183 + if (!valid) return
  184 +
  185 + try {
  186 + const params = {
  187 + ...this.formData,
  188 + values: this.paymentKeys.map(item => ({
  189 + columnKey: item.columnKey,
  190 + columnValue: item.columnValue
  191 + }))
  192 + }
  193 + await savePaymentPool(params)
  194 + this.$message.success(this.$t('paymentPool.add.success'))
  195 + this.visible = false
  196 + this.$emit('success')
  197 + } catch (error) {
  198 + this.$message.error(error.message || this.$t('paymentPool.add.error'))
  199 + }
  200 + })
  201 + }
  202 + }
  203 +}
  204 +</script>
0 205 \ No newline at end of file
... ...
src/components/system/addSmallWechat.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('smallWeChatManage.addTitle')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  9 + <el-form-item :label="$t('smallWeChatManage.name')" prop="name">
  10 + <el-input
  11 + v-model="formData.name"
  12 + :placeholder="$t('smallWeChatManage.namePlaceholder')"
  13 + />
  14 + </el-form-item>
  15 + <el-form-item label="APPID" prop="appId">
  16 + <el-input
  17 + v-model="formData.appId"
  18 + :placeholder="$t('smallWeChatManage.appIdPlaceholder')"
  19 + />
  20 + </el-form-item>
  21 + <el-form-item :label="$t('smallWeChatManage.appSecret')" prop="appSecret">
  22 + <el-input
  23 + v-model="formData.appSecret"
  24 + :placeholder="$t('smallWeChatManage.appSecretPlaceholder')"
  25 + show-password
  26 + />
  27 + </el-form-item>
  28 + <el-form-item :label="$t('smallWeChatManage.remarks')">
  29 + <el-input
  30 + v-model="formData.remarks"
  31 + type="textarea"
  32 + :placeholder="$t('smallWeChatManage.remarksPlaceholder')"
  33 + :rows="3"
  34 + />
  35 + </el-form-item>
  36 + </el-form>
  37 +
  38 + <div slot="footer" class="dialog-footer">
  39 + <el-button @click="visible = false">{{ $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 { saveSmallWeChat } from '@/api/system/smallWeChatManageApi'
  47 +import { getCommunityId } from '@/api/community/communityApi'
  48 +import { getDict } from '@/api/community/communityApi'
  49 +
  50 +export default {
  51 + name: 'AddSmallWechat',
  52 + data() {
  53 + return {
  54 + visible: false,
  55 + formData: {
  56 + name: '',
  57 + appId: '',
  58 + appSecret: '',
  59 + remarks: '',
  60 + objType: '1000',
  61 + objId: '',
  62 + weChatType: '',
  63 + payPassword: '1',
  64 + mchId: '1',
  65 + mchName: '1',
  66 + certPath: ''
  67 + },
  68 + rules: {
  69 + name: [
  70 + { required: true, message: this.$t('smallWeChatManage.nameRequired'), trigger: 'blur' },
  71 + { max: 100, message: this.$t('smallWeChatManage.nameMaxLength'), trigger: 'blur' }
  72 + ],
  73 + appId: [
  74 + { required: true, message: this.$t('smallWeChatManage.appIdRequired'), trigger: 'blur' },
  75 + { max: 100, message: this.$t('smallWeChatManage.appIdMaxLength'), trigger: 'blur' }
  76 + ],
  77 + appSecret: [
  78 + { required: true, message: this.$t('smallWeChatManage.appSecretRequired'), trigger: 'blur' },
  79 + { max: 200, message: this.$t('smallWeChatManage.appSecretMaxLength'), trigger: 'blur' }
  80 + ]
  81 + },
  82 + objTypes: [],
  83 + types: []
  84 + }
  85 + },
  86 + methods: {
  87 + open(type) {
  88 + this.formData.weChatType = type
  89 + this.formData.objId = getCommunityId()
  90 + this.getDictData()
  91 + this.visible = true
  92 + },
  93 + async getDictData() {
  94 + try {
  95 + const objTypes = await getDict('small_wechat', 'obj_type')
  96 + const types = await getDict('small_wechat', 'wechat_type')
  97 + this.objTypes = objTypes
  98 + this.types = types
  99 + } catch (error) {
  100 + console.error('Failed to get dict data:', error)
  101 + }
  102 + },
  103 + handleClose() {
  104 + this.$refs.form.resetFields()
  105 + this.formData = {
  106 + name: '',
  107 + appId: '',
  108 + appSecret: '',
  109 + remarks: '',
  110 + objType: '1000',
  111 + objId: '',
  112 + weChatType: '',
  113 + payPassword: '1',
  114 + mchId: '1',
  115 + mchName: '1',
  116 + certPath: ''
  117 + }
  118 + },
  119 + handleSubmit() {
  120 + this.$refs.form.validate(async valid => {
  121 + if (valid) {
  122 + try {
  123 + await saveSmallWeChat(this.formData)
  124 + this.$message.success(this.$t('smallWeChatManage.addSuccess'))
  125 + this.visible = false
  126 + this.$emit('success')
  127 + } catch (error) {
  128 + this.$message.error(error.message || this.$t('smallWeChatManage.addFailed'))
  129 + }
  130 + }
  131 + })
  132 + }
  133 + }
  134 +}
  135 +</script>
0 136 \ No newline at end of file
... ...
src/components/system/carDetailHis.vue 0 → 100644
  1 +<template>
  2 + <div class="car-detail-his">
  3 + <el-table
  4 + :data="carDetailHisInfo.cars"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + prop="carNum"
  10 + :label="$t('carDetailHis.carNum')"
  11 + align="center">
  12 + </el-table-column>
  13 + <el-table-column
  14 + :label="$t('carDetailHis.leaseType')"
  15 + align="center">
  16 + <template slot-scope="scope">
  17 + <span v-if="scope.row.leaseType === 'T'">{{ $t('carDetailHis.tempCar') }}</span>
  18 + <span v-else>{{ scope.row.leaseTypeName }}</span>
  19 + </template>
  20 + </el-table-column>
  21 + <el-table-column
  22 + :label="$t('carDetailHis.carTypeName')"
  23 + align="center">
  24 + <template slot-scope="scope">
  25 + {{ scope.row.carTypeName || '-' }}
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column
  29 + :label="$t('carDetailHis.carColor')"
  30 + align="center">
  31 + <template slot-scope="scope">
  32 + {{ scope.row.carColor || '-' }}
  33 + </template>
  34 + </el-table-column>
  35 + <el-table-column
  36 + :label="$t('carDetailHis.owner')"
  37 + align="center">
  38 + <template slot-scope="scope">
  39 + <div class="hand">
  40 + {{ scope.row.ownerName }}({{ scope.row.link }})
  41 + </div>
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column
  45 + :label="$t('carDetailHis.parkingSpace')"
  46 + align="center">
  47 + <template slot-scope="scope">
  48 + <span v-if="scope.row.areaNum && scope.row.state === '1001'">
  49 + {{ scope.row.areaNum }}-{{ scope.row.num }}
  50 + </span>
  51 + <span v-else>
  52 + {{ $t('carDetailHis.released') }}
  53 + </span>
  54 + </template>
  55 + </el-table-column>
  56 + <el-table-column
  57 + :label="$t('carDetailHis.validityPeriod')"
  58 + align="center">
  59 + <template slot-scope="scope">
  60 + <div v-if="scope.row.leaseType === 'H'">
  61 + {{ scope.row.startTime }}<br>~{{ scope.row.endTime }}
  62 + </div>
  63 + <div v-else>--</div>
  64 + </template>
  65 + </el-table-column>
  66 + <el-table-column
  67 + :label="$t('carDetailHis.operate')"
  68 + align="center">
  69 + <template slot-scope="scope">
  70 + {{ _getHisOperate(scope.row) }}
  71 + </template>
  72 + </el-table-column>
  73 + <el-table-column
  74 + :label="$t('carDetailHis.userName')"
  75 + align="center">
  76 + <template slot-scope="scope">
  77 + {{ scope.row.userName || '-' }}
  78 + </template>
  79 + </el-table-column>
  80 + <el-table-column
  81 + :label="$t('carDetailHis.createTime')"
  82 + align="center">
  83 + <template slot-scope="scope">
  84 + {{ scope.row.createTime }}
  85 + </template>
  86 + </el-table-column>
  87 + </el-table>
  88 +
  89 + <el-pagination
  90 + @size-change="handleSizeChange"
  91 + @current-change="handleCurrentChange"
  92 + :current-page="page.current"
  93 + :page-sizes="[10, 20, 30, 50]"
  94 + :page-size="page.size"
  95 + layout="total, sizes, prev, pager, next, jumper"
  96 + :total="page.total">
  97 + </el-pagination>
  98 + </div>
  99 +</template>
  100 +
  101 +<script>
  102 +import { queryHisOwnerCar } from '@/api/system/operateDataLogApi'
  103 +
  104 +export default {
  105 + name: 'CarDetailHis',
  106 + data() {
  107 + return {
  108 + loading: false,
  109 + carDetailHisInfo: {
  110 + cars: [],
  111 + carId: '',
  112 + memberId: '',
  113 + carNum: '',
  114 + carNumLike: '',
  115 + logStartTime: '',
  116 + logEndTime: '',
  117 + paId: ''
  118 + },
  119 + page: {
  120 + current: 1,
  121 + size: 10,
  122 + total: 0
  123 + }
  124 + }
  125 + },
  126 + methods: {
  127 + open(conditions) {
  128 + this.carDetailHisInfo = {
  129 + ...this.carDetailHisInfo,
  130 + ...conditions
  131 + }
  132 + this._loadCarDetailHisData()
  133 + },
  134 + async _loadCarDetailHisData() {
  135 + try {
  136 + this.loading = true
  137 + const params = {
  138 + page: this.page.current,
  139 + row: this.page.size,
  140 + carNum: this.carDetailHisInfo.carNum,
  141 + carNumLike: this.carDetailHisInfo.carNumLike,
  142 + logStartTime: this.carDetailHisInfo.logStartTime,
  143 + logEndTime: this.carDetailHisInfo.logEndTime
  144 + }
  145 +
  146 + const { data, total } = await queryHisOwnerCar(params)
  147 + this.carDetailHisInfo.cars = data
  148 + this.page.total = total
  149 + } catch (error) {
  150 + console.error('Failed to load car history:', error)
  151 + } finally {
  152 + this.loading = false
  153 + }
  154 + },
  155 + _getHisOperate(car) {
  156 + const carCount = this.carDetailHisInfo.cars.filter(item => item.bId === car.bId).length
  157 +
  158 + if (carCount <= 1) {
  159 + if (car.operate === 'ADD') return this.$t('carDetailHis.add')
  160 + if (car.operate === 'DEL') return this.$t('carDetailHis.delete')
  161 + return '-'
  162 + }
  163 +
  164 + if (car.operate === 'ADD') return this.$t('carDetailHis.modifyNew')
  165 + if (car.operate === 'DEL') return this.$t('carDetailHis.modifyOld')
  166 + return '-'
  167 + },
  168 + handleSizeChange(size) {
  169 + this.page.size = size
  170 + this._loadCarDetailHisData()
  171 + },
  172 + handleCurrentChange(current) {
  173 + this.page.current = current
  174 + this._loadCarDetailHisData()
  175 + }
  176 + }
  177 +}
  178 +</script>
  179 +
  180 +<style scoped>
  181 +.car-detail-his {
  182 + padding: 20px;
  183 +}
  184 +
  185 +.hand {
  186 + cursor: pointer;
  187 +}
  188 +
  189 +.el-pagination {
  190 + margin-top: 20px;
  191 + text-align: right;
  192 +}
  193 +</style>
0 194 \ No newline at end of file
... ...
src/components/system/contractDetailChange.vue 0 → 100644
  1 +<template>
  2 + <div class="contract-detail-change">
  3 + <el-table
  4 + :data="contractDetailChangeInfo.contracts"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + prop="contractName"
  10 + :label="$t('contractDetailChange.contractName')"
  11 + align="center">
  12 + </el-table-column>
  13 + <el-table-column
  14 + prop="contractCode"
  15 + :label="$t('contractDetailChange.contractCode')"
  16 + align="center">
  17 + </el-table-column>
  18 + <el-table-column
  19 + prop="contractTypeName"
  20 + :label="$t('contractDetailChange.contractTypeName')"
  21 + align="center">
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="partyA"
  25 + :label="$t('contractDetailChange.partyA')"
  26 + align="center">
  27 + </el-table-column>
  28 + <el-table-column
  29 + prop="partyB"
  30 + :label="$t('contractDetailChange.partyB')"
  31 + align="center">
  32 + </el-table-column>
  33 + <el-table-column
  34 + prop="planTypeName"
  35 + :label="$t('contractDetailChange.planTypeName')"
  36 + align="center">
  37 + </el-table-column>
  38 + <el-table-column
  39 + prop="changePersonName"
  40 + :label="$t('contractDetailChange.changePersonName')"
  41 + align="center">
  42 + </el-table-column>
  43 + <el-table-column
  44 + prop="createTime"
  45 + :label="$t('contractDetailChange.createTime')"
  46 + align="center">
  47 + </el-table-column>
  48 + <el-table-column
  49 + prop="remark"
  50 + :label="$t('contractDetailChange.remark')"
  51 + align="center">
  52 + </el-table-column>
  53 + <el-table-column
  54 + prop="stateName"
  55 + :label="$t('contractDetailChange.stateName')"
  56 + align="center">
  57 + </el-table-column>
  58 + <el-table-column
  59 + :label="$t('contractDetailChange.operation')"
  60 + align="center"
  61 + width="120">
  62 + <template slot-scope="scope">
  63 + <el-button
  64 + size="mini"
  65 + type="primary"
  66 + @click="_toContractDetails(scope.row)">
  67 + {{ $t('contractDetailChange.detail') }}
  68 + </el-button>
  69 + </template>
  70 + </el-table-column>
  71 + </el-table>
  72 +
  73 + <el-pagination
  74 + @size-change="handleSizeChange"
  75 + @current-change="handleCurrentChange"
  76 + :current-page="page.current"
  77 + :page-sizes="[10, 20, 30, 50]"
  78 + :page-size="page.size"
  79 + layout="total, sizes, prev, pager, next, jumper"
  80 + :total="page.total">
  81 + </el-pagination>
  82 + </div>
  83 +</template>
  84 +
  85 +<script>
  86 +import { queryContractChangePlan } from '@/api/system/operateDataLogApi'
  87 +
  88 +export default {
  89 + name: 'ContractDetailChange',
  90 + data() {
  91 + return {
  92 + loading: false,
  93 + contractDetailChangeInfo: {
  94 + contracts: [],
  95 + contractId: '',
  96 + roomNum: '',
  97 + totalArea: '0',
  98 + logStartTime: '',
  99 + logEndTime: '',
  100 + contractCode: '',
  101 + staffNameLike: ''
  102 + },
  103 + page: {
  104 + current: 1,
  105 + size: 10,
  106 + total: 0
  107 + }
  108 + }
  109 + },
  110 + methods: {
  111 + open(conditions) {
  112 + this.contractDetailChangeInfo = {
  113 + ...this.contractDetailChangeInfo,
  114 + ...conditions
  115 + }
  116 + this._loadContractDetailChangeData()
  117 + },
  118 + async _loadContractDetailChangeData() {
  119 + try {
  120 + this.loading = true
  121 + const params = {
  122 + page: this.page.current,
  123 + row: this.page.size,
  124 + contractId: this.contractDetailChangeInfo.contractId,
  125 + logStartTime: this.contractDetailChangeInfo.logStartTime,
  126 + logEndTime: this.contractDetailChangeInfo.logEndTime,
  127 + contractCode: this.contractDetailChangeInfo.contractCode,
  128 + staffNameLike: this.contractDetailChangeInfo.staffNameLike
  129 + }
  130 +
  131 + const { data, total } = await queryContractChangePlan(params)
  132 + this.contractDetailChangeInfo.contracts = data
  133 + this.page.total = total
  134 + } catch (error) {
  135 + console.error('Failed to load contract change history:', error)
  136 + } finally {
  137 + this.loading = false
  138 + }
  139 + },
  140 + _toContractDetails(contract) {
  141 + this.$router.push({
  142 + path: '/admin/contractChangeDetails',
  143 + query: { planId: contract.planId }
  144 + })
  145 + },
  146 + handleSizeChange(size) {
  147 + this.page.size = size
  148 + this._loadContractDetailChangeData()
  149 + },
  150 + handleCurrentChange(current) {
  151 + this.page.current = current
  152 + this._loadContractDetailChangeData()
  153 + }
  154 + }
  155 +}
  156 +</script>
  157 +
  158 +<style scoped>
  159 +.contract-detail-change {
  160 + padding: 20px;
  161 +}
  162 +
  163 +.el-pagination {
  164 + margin-top: 20px;
  165 + text-align: right;
  166 +}
  167 +</style>
0 168 \ No newline at end of file
... ...
src/components/system/deleteFeePrintSpec.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('feePrintSpec.deleteTitle')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center>
  7 + <div class="text-center">
  8 + <p>{{ $t('feePrintSpec.deleteConfirm') }}</p>
  9 + </div>
  10 + <span slot="footer" class="dialog-footer">
  11 + <el-button @click="visible = false">
  12 + {{ $t('common.cancel') }}
  13 + </el-button>
  14 + <el-button
  15 + type="primary"
  16 + @click="confirmDelete"
  17 + :loading="deleting">
  18 + {{ $t('common.confirm') }}
  19 + </el-button>
  20 + </span>
  21 + </el-dialog>
  22 +</template>
  23 +
  24 +<script>
  25 +import { deleteFeePrintSpec } from '@/api/system/feePrintSpecManageApi'
  26 +import { getCommunityId } from '@/api/community/communityApi'
  27 +
  28 +export default {
  29 + name: 'DeleteFeePrintSpec',
  30 + data() {
  31 + return {
  32 + visible: false,
  33 + deleting: false,
  34 + currentItem: {
  35 + printId: '',
  36 + communityId: ''
  37 + }
  38 + }
  39 + },
  40 + methods: {
  41 + open(item) {
  42 + this.visible = true
  43 + this.currentItem = {
  44 + printId: item.printId,
  45 + communityId: getCommunityId()
  46 + }
  47 + },
  48 + async confirmDelete() {
  49 + this.deleting = true
  50 + try {
  51 + await deleteFeePrintSpec(this.currentItem)
  52 + this.$message.success(this.$t('feePrintSpec.deleteSuccess'))
  53 + this.visible = false
  54 + this.$emit('success')
  55 + } catch (error) {
  56 + this.$message.error(error.message || this.$t('feePrintSpec.deleteFailed'))
  57 + } finally {
  58 + this.deleting = false
  59 + }
  60 + }
  61 + }
  62 +}
  63 +</script>
  64 +
  65 +<style scoped>
  66 +.text-center {
  67 + text-align: center;
  68 + font-size: 16px;
  69 + margin-bottom: 20px;
  70 +}
  71 +</style>
0 72 \ No newline at end of file
... ...
src/components/system/deletePaymentPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('paymentPool.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div class="delete-content">
  9 + <i class="el-icon-warning" style="color:#E6A23C;font-size:24px;margin-right:10px;"></i>
  10 + <span>{{ $t('paymentPool.delete.confirmText') }}</span>
  11 + </div>
  12 + <div slot="footer" class="dialog-footer">
  13 + <el-button @click="visible = false">
  14 + {{ $t('common.cancel') }}
  15 + </el-button>
  16 + <el-button
  17 + type="primary"
  18 + @click="handleConfirm"
  19 + >
  20 + {{ $t('common.confirm') }}
  21 + </el-button>
  22 + </div>
  23 + </el-dialog>
  24 +</template>
  25 +
  26 +<script>
  27 +import { deletePaymentPool } from '@/api/system/paymentPoolApi'
  28 +import { getCommunityId } from '@/api/community/communityApi'
  29 +
  30 +export default {
  31 + name: 'DeletePaymentPool',
  32 + data() {
  33 + return {
  34 + visible: false,
  35 + ppId: '',
  36 + communityId: ''
  37 + }
  38 + },
  39 + created() {
  40 + this.communityId = getCommunityId()
  41 + },
  42 + methods: {
  43 + open(row) {
  44 + this.visible = true
  45 + this.ppId = row.ppId
  46 + },
  47 + handleClose() {
  48 + this.ppId = ''
  49 + },
  50 + async handleConfirm() {
  51 + try {
  52 + await deletePaymentPool({
  53 + ppId: this.ppId,
  54 + communityId: this.communityId
  55 + })
  56 + this.$message.success(this.$t('paymentPool.delete.success'))
  57 + this.visible = false
  58 + this.$emit('success')
  59 + } catch (error) {
  60 + this.$message.error(error.message || this.$t('paymentPool.delete.error'))
  61 + }
  62 + }
  63 + }
  64 +}
  65 +</script>
  66 +
  67 +<style lang="scss" scoped>
  68 +.delete-content {
  69 + display: flex;
  70 + align-items: center;
  71 + justify-content: center;
  72 + padding: 20px 0;
  73 + font-size: 16px;
  74 +}
  75 +</style>
0 76 \ No newline at end of file
... ...
src/components/system/deleteSmallWechat.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('smallWeChatManage.deleteTitle')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div class="delete-content">
  9 + <p>{{ $t('smallWeChatManage.deleteConfirm') }}</p>
  10 + </div>
  11 +
  12 + <div slot="footer" class="dialog-footer">
  13 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  14 + <el-button type="primary" @click="handleConfirm" :loading="loading">
  15 + {{ $t('common.confirm') }}
  16 + </el-button>
  17 + </div>
  18 + </el-dialog>
  19 +</template>
  20 +
  21 +<script>
  22 +import { deleteSmallWeChat } from '@/api/system/smallWeChatManageApi'
  23 +import { getCommunityId } from '@/api/community/communityApi'
  24 +
  25 +export default {
  26 + name: 'DeleteSmallWechat',
  27 + data() {
  28 + return {
  29 + visible: false,
  30 + loading: false,
  31 + formData: {
  32 + wechatId: '',
  33 + communityId: ''
  34 + }
  35 + }
  36 + },
  37 + methods: {
  38 + open(data) {
  39 + this.formData.wechatId = data.wechatId
  40 + this.formData.communityId = getCommunityId()
  41 + this.visible = true
  42 + },
  43 + handleClose() {
  44 + this.formData = {
  45 + wechatId: '',
  46 + communityId: ''
  47 + }
  48 + this.loading = false
  49 + },
  50 + async handleConfirm() {
  51 + try {
  52 + this.loading = true
  53 + await deleteSmallWeChat(this.formData)
  54 + this.$message.success(this.$t('smallWeChatManage.deleteSuccess'))
  55 + this.visible = false
  56 + this.$emit('success')
  57 + } catch (error) {
  58 + this.$message.error(error.message || this.$t('smallWeChatManage.deleteFailed'))
  59 + } finally {
  60 + this.loading = false
  61 + }
  62 + }
  63 + }
  64 +}
  65 +</script>
  66 +
  67 +<style scoped>
  68 +.delete-content {
  69 + text-align: center;
  70 + font-size: 16px;
  71 + padding: 20px 0;
  72 +}
  73 +</style>
0 74 \ No newline at end of file
... ...
src/components/system/editFeePrintSpec.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('feePrintSpecManage.editTitle')" :visible.sync="visible" width="50%" @close="resetForm">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('feePrintSpecManage.spec')" prop="specCd">
  5 + <el-select v-model="formData.specCd" style="width:100%" :placeholder="$t('feePrintSpecManage.specPlaceholder')">
  6 + <el-option v-for="item in specOptions" :key="item.value" :label="item.label" :value="item.value">
  7 + </el-option>
  8 + </el-select>
  9 + </el-form-item>
  10 +
  11 + <el-form-item :label="$t('feePrintSpecManage.name')" prop="printName">
  12 + <el-input v-model="formData.printName" :placeholder="$t('feePrintSpecManage.namePlaceholder')">
  13 + </el-input>
  14 + </el-form-item>
  15 +
  16 + <el-form-item :label="$t('feePrintSpecManage.image')" prop="qrImg">
  17 + <upload-image-url ref="uploadImage" :image-count="1" @notifyUploadCoverImage="handleImageChange">
  18 + </upload-image-url>
  19 + </el-form-item>
  20 +
  21 + <el-form-item :label="$t('feePrintSpecManage.content')">
  22 + <el-input type="textarea" :rows="5" v-model="formData.content"
  23 + :placeholder="$t('feePrintSpecManage.contentPlaceholder')">
  24 + </el-input>
  25 + </el-form-item>
  26 + </el-form>
  27 +
  28 + <span slot="footer" class="dialog-footer">
  29 + <el-button @click="visible = false">
  30 + {{ $t('common.cancel') }}
  31 + </el-button>
  32 + <el-button type="primary" @click="submitForm" :loading="submitting">
  33 + {{ $t('common.confirm') }}
  34 + </el-button>
  35 + </span>
  36 + </el-dialog>
  37 +</template>
  38 +
  39 +<script>
  40 +import { updateFeePrintSpec } from '@/api/system/feePrintSpecManageApi'
  41 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  42 +import { getCommunityId } from '@/api/community/communityApi'
  43 +
  44 +export default {
  45 + name: 'EditFeePrintSpec',
  46 + components: {
  47 + UploadImageUrl
  48 + },
  49 + data() {
  50 + return {
  51 + visible: false,
  52 + submitting: false,
  53 + formData: {
  54 + printId: '',
  55 + specCd: '',
  56 + printName: '',
  57 + qrImg: '',
  58 + content: '',
  59 + communityId: ''
  60 + },
  61 + rules: {
  62 + specCd: [
  63 + { required: true, message: this.$t('feePrintSpecManage.specRequired'), trigger: 'blur' }
  64 + ],
  65 + printName: [
  66 + { required: true, message: this.$t('feePrintSpecManage.nameRequired'), trigger: 'blur' },
  67 + { max: 128, message: this.$t('feePrintSpecManage.nameMaxLength'), trigger: 'blur' }
  68 + ]
  69 + },
  70 + specOptions: [
  71 + { value: '1010', label: this.$t('feePrintSpecManage.reminderPrint') },
  72 + { value: '2020', label: this.$t('feePrintSpecManage.receiptPrint') }
  73 + ]
  74 + }
  75 + },
  76 + methods: {
  77 + open(row) {
  78 + this.visible = true
  79 + this.formData = {
  80 + ...row,
  81 + communityId: getCommunityId()
  82 + }
  83 + this.$nextTick(() => {
  84 + if (row.qrImg) {
  85 + setTimeout(() => {
  86 + this.$refs.uploadImage.setImages([row.qrImg ])
  87 + }, 500)
  88 + } else {
  89 + this.$refs.uploader.clear()
  90 + }
  91 + })
  92 + },
  93 + handleImageChange(images) {
  94 + if (images && images.length > 0) {
  95 + this.formData.qrImg = images[0]
  96 + } else {
  97 + this.formData.qrImg = ''
  98 + }
  99 + },
  100 + submitForm() {
  101 + this.$refs.form.validate(async valid => {
  102 + if (!valid) return
  103 +
  104 + this.submitting = true
  105 + try {
  106 + await updateFeePrintSpec(this.formData)
  107 + this.$message.success(this.$t('feePrintSpecManage.editSuccess'))
  108 + this.visible = false
  109 + this.$emit('success')
  110 + } catch (error) {
  111 + this.$message.error(error.message || this.$t('feePrintSpecManage.editFailed'))
  112 + } finally {
  113 + this.submitting = false
  114 + }
  115 + })
  116 + },
  117 + resetForm() {
  118 + this.$refs.form.resetFields()
  119 + this.formData = {
  120 + printId: '',
  121 + specCd: '',
  122 + printName: '',
  123 + qrImg: '',
  124 + content: '',
  125 + communityId: ''
  126 + }
  127 + }
  128 + }
  129 +}
  130 +</script>
0 131 \ No newline at end of file
... ...
src/components/system/editPaymentPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('paymentPool.edit.title')" :visible.sync="visible" width="50%" @close="handleClose">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('paymentPool.edit.paymentName')" prop="paymentName">
  5 + <el-input v-model="formData.paymentName" :placeholder="$t('paymentPool.edit.paymentNamePlaceholder')" />
  6 + </el-form-item>
  7 +
  8 + <el-form-item :label="$t('paymentPool.edit.paymentType')" prop="paymentType">
  9 + <el-select v-model="formData.paymentType" :placeholder="$t('paymentPool.edit.paymentTypePlaceholder')"
  10 + style="width:100%" disabled>
  11 + <el-option v-for="item in paymentTypes" :key="item.paymentType" :label="item.name"
  12 + :value="item.paymentType" />
  13 + </el-select>
  14 + </el-form-item>
  15 +
  16 + <el-form-item v-for="(item, index) in paymentKeys" :key="index" :label="item.name">
  17 + <el-input v-model="item.columnValue" type="textarea" :placeholder="item.remark" :rows="3" />
  18 + </el-form-item>
  19 +
  20 + <el-form-item v-if="formData.paymentType === 'WECHAT'" :label="$t('paymentPool.edit.certFile')">
  21 + <upload-file ref="uploadFile" :call-back-listener="'editPaymentPool'" :call-back-function="'notifyCert'" />
  22 + <div v-if="formData.certPath" class="cert-tip">
  23 + {{ $t('paymentPool.edit.currentCert') }}: {{ formData.certPath }}
  24 + </div>
  25 + </el-form-item>
  26 +
  27 + <el-form-item :label="$t('paymentPool.edit.payRange')" prop="payType">
  28 + <el-select v-model="formData.payType" :placeholder="$t('paymentPool.edit.payRangePlaceholder')"
  29 + style="width:100%" disabled>
  30 + <el-option :label="$t('paymentPool.edit.communityFee')" value="1001" />
  31 + <el-option :label="$t('paymentPool.edit.tempCarFee')" value="2002" />
  32 + <el-option :label="$t('paymentPool.edit.specifiedFee')" value="3003" />
  33 + </el-select>
  34 + </el-form-item>
  35 +
  36 + <el-form-item v-if="formData.payType === '3003'" :label="$t('paymentPool.edit.feeItems')">
  37 + <el-checkbox-group v-model="formData.configIds">
  38 + <el-checkbox v-for="item in feeConfigs" :key="item.configId" :label="item.configId">
  39 + {{ item.feeName }}
  40 + </el-checkbox>
  41 + </el-checkbox-group>
  42 + </el-form-item>
  43 +
  44 + <el-form-item :label="$t('paymentPool.edit.state')" prop="state">
  45 + <el-select v-model="formData.state" :placeholder="$t('paymentPool.edit.statePlaceholder')" style="width:100%">
  46 + <el-option :label="$t('paymentPool.edit.enable')" value="Y" />
  47 + <el-option :label="$t('paymentPool.edit.disable')" value="N" />
  48 + </el-select>
  49 + </el-form-item>
  50 +
  51 + <el-form-item :label="$t('paymentPool.edit.remark')">
  52 + <el-input v-model="formData.remark" type="textarea" :placeholder="$t('paymentPool.edit.remarkPlaceholder')"
  53 + :rows="3" />
  54 + </el-form-item>
  55 + </el-form>
  56 +
  57 + <div slot="footer" class="dialog-footer">
  58 + <el-button @click="visible = false">
  59 + {{ $t('common.cancel') }}
  60 + </el-button>
  61 + <el-button type="primary" @click="handleSubmit">
  62 + {{ $t('common.confirm') }}
  63 + </el-button>
  64 + </div>
  65 + </el-dialog>
  66 +</template>
  67 +
  68 +<script>
  69 +import { updatePaymentPool, listPaymentKey, listFeeConfigs, getPaymentPoolDetail,listPaymentAdapt } from '@/api/system/paymentPoolApi'
  70 +import UploadFile from '@/components/upload/FileUpload'
  71 +import { getCommunityId } from '@/api/community/communityApi'
  72 +
  73 +export default {
  74 + name: 'EditPaymentPool',
  75 + components: {
  76 + UploadFile
  77 + },
  78 + data() {
  79 + return {
  80 + visible: false,
  81 + formData: {
  82 + ppId: '',
  83 + paymentName: '',
  84 + paymentType: '',
  85 + certPath: '',
  86 + state: '',
  87 + remark: '',
  88 + payType: '',
  89 + configIds: [],
  90 + communityId: ''
  91 + },
  92 + paymentTypes: [],
  93 + paymentKeys: [],
  94 + feeConfigs: [],
  95 + rules: {
  96 + paymentName: [
  97 + { required: true, message: this.$t('paymentPool.validate.paymentNameRequired'), trigger: 'blur' },
  98 + { max: 64, message: this.$t('paymentPool.validate.paymentNameMaxLength'), trigger: 'blur' }
  99 + ],
  100 + paymentType: [
  101 + { required: true, message: this.$t('paymentPool.validate.paymentTypeRequired'), trigger: 'change' }
  102 + ],
  103 + state: [
  104 + { required: true, message: this.$t('paymentPool.validate.stateRequired'), trigger: 'change' }
  105 + ]
  106 + }
  107 + }
  108 + },
  109 + created() {
  110 + this.formData.communityId = getCommunityId()
  111 + this.getPaymentTypes()
  112 + this.$on('notifyCert', this.handleNotifyCert)
  113 + },
  114 + methods: {
  115 + open(row) {
  116 + this.visible = true
  117 + this.formData.ppId = row.ppId
  118 + this.getPaymentPoolDetail()
  119 + this.getFeeConfigs()
  120 + },
  121 + handleClose() {
  122 + this.$refs.form.resetFields()
  123 + this.formData = {
  124 + ppId: '',
  125 + paymentName: '',
  126 + paymentType: '',
  127 + certPath: '',
  128 + state: '',
  129 + remark: '',
  130 + payType: '',
  131 + configIds: [],
  132 + communityId: getCommunityId()
  133 + }
  134 + this.paymentKeys = []
  135 + if (this.$refs.uploadFile) {
  136 + this.$refs.uploadFile.clear()
  137 + }
  138 + },
  139 + async getPaymentTypes() {
  140 + try {
  141 + const { data } = await listPaymentAdapt({
  142 + page: 1,
  143 + row: 100,
  144 + })
  145 + this.paymentTypes = data
  146 + } catch (error) {
  147 + console.error('获取支付类型失败:', error)
  148 + }
  149 + },
  150 + async getFeeConfigs() {
  151 + try {
  152 + const params = {
  153 + page: 1,
  154 + row: 100,
  155 + isDefault: 'F',
  156 + communityId: this.formData.communityId
  157 + }
  158 + const { data } = await listFeeConfigs(params)
  159 + this.feeConfigs = data
  160 + } catch (error) {
  161 + console.error('获取费用配置失败:', error)
  162 + }
  163 + },
  164 + async getPaymentPoolDetail() {
  165 + try {
  166 + const params = {
  167 + ppId: this.formData.ppId,
  168 + communityId: this.formData.communityId
  169 + }
  170 + const { data } = await getPaymentPoolDetail(params)
  171 + this.formData = {
  172 + ...this.formData,
  173 + paymentName: data[0].paymentName,
  174 + paymentType: data[0].paymentType,
  175 + certPath: data[0].certPath,
  176 + state: data[0].state,
  177 + remark: data[0].remark,
  178 + payType: data[0].payType
  179 + }
  180 +
  181 + // 加载支付密钥
  182 + await this.loadPaymentKeys()
  183 +
  184 + // 设置支付密钥值
  185 + if (data[0].values) {
  186 + data[0].values.forEach(value => {
  187 + const key = this.paymentKeys.find(k => k.columnKey === value.columnKey)
  188 + if (key) {
  189 + key.columnValue = value.columnValue
  190 + }
  191 + })
  192 + }
  193 +
  194 + // 设置费用项
  195 + if (data[0].configs) {
  196 + this.formData.configIds = data[0].configs.map(c => c.configId)
  197 + }
  198 +
  199 + // 如果有证书路径,通知上传组件
  200 + if (this.formData.certPath && this.$refs.uploadFile) {
  201 + this.$refs.uploadFile.fileName = this.formData.certPath
  202 + this.$refs.uploadFile.realFileName = this.formData.certPath
  203 + this.$refs.uploadFile.progress = 100
  204 + }
  205 + } catch (error) {
  206 + console.error('获取支付池详情失败:', error)
  207 + }
  208 + },
  209 + async loadPaymentKeys() {
  210 + try {
  211 + const params = {
  212 + paymentType: this.formData.paymentType,
  213 + page: 1,
  214 + row: 100
  215 + }
  216 + const { data } = await listPaymentKey(params)
  217 + this.paymentKeys = data.map(item => ({
  218 + ...item,
  219 + columnValue: ''
  220 + }))
  221 + } catch (error) {
  222 + console.error('获取支付密钥失败:', error)
  223 + }
  224 + },
  225 + handleNotifyCert(param) {
  226 + this.formData.certPath = param.realFileName
  227 + },
  228 + handleSubmit() {
  229 + this.$refs.form.validate(async valid => {
  230 + if (!valid) return
  231 +
  232 + try {
  233 + const params = {
  234 + ...this.formData,
  235 + values: this.paymentKeys.map(item => ({
  236 + columnKey: item.columnKey,
  237 + columnValue: item.columnValue
  238 + }))
  239 + }
  240 + await updatePaymentPool(params)
  241 + this.$message.success(this.$t('paymentPool.edit.success'))
  242 + this.visible = false
  243 + this.$emit('success')
  244 + } catch (error) {
  245 + this.$message.error(error.message || this.$t('paymentPool.edit.error'))
  246 + }
  247 + })
  248 + }
  249 + }
  250 +}
  251 +</script>
  252 +
  253 +<style lang="scss" scoped>
  254 +.cert-tip {
  255 + margin-top: 5px;
  256 + font-size: 12px;
  257 + color: #909399;
  258 +}
  259 +</style>
0 260 \ No newline at end of file
... ...
src/components/system/editSmallWechat.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('smallWeChatManage.editTitle')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  9 + <el-form-item :label="$t('smallWeChatManage.name')" prop="name">
  10 + <el-input
  11 + v-model="formData.name"
  12 + :placeholder="$t('smallWeChatManage.namePlaceholder')"
  13 + />
  14 + </el-form-item>
  15 + <el-form-item label="APPID" prop="appId">
  16 + <el-input
  17 + v-model="formData.appId"
  18 + :placeholder="$t('smallWeChatManage.appIdPlaceholder')"
  19 + />
  20 + </el-form-item>
  21 + <el-form-item :label="$t('smallWeChatManage.appSecret')" prop="appSecret">
  22 + <el-input
  23 + v-model="formData.appSecret"
  24 + :placeholder="$t('smallWeChatManage.appSecretPlaceholder')"
  25 + show-password
  26 + />
  27 + </el-form-item>
  28 + <el-form-item :label="$t('smallWeChatManage.remarks')">
  29 + <el-input
  30 + v-model="formData.remarks"
  31 + type="textarea"
  32 + :placeholder="$t('smallWeChatManage.remarksPlaceholder')"
  33 + :rows="3"
  34 + />
  35 + </el-form-item>
  36 + </el-form>
  37 +
  38 + <div slot="footer" class="dialog-footer">
  39 + <el-button @click="visible = false">{{ $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 { updateSmallWeChat } from '@/api/system/smallWeChatManageApi'
  47 +import { getCommunityId } from '@/api/community/communityApi'
  48 +import { getDict } from '@/api/community/communityApi'
  49 +
  50 +export default {
  51 + name: 'EditSmallWechat',
  52 + data() {
  53 + return {
  54 + visible: false,
  55 + formData: {
  56 + wechatId: '',
  57 + name: '',
  58 + appId: '',
  59 + appSecret: '',
  60 + remarks: '',
  61 + objType: '1000',
  62 + objId: '',
  63 + payPassword: '1',
  64 + mchId: '1',
  65 + mchName: '1',
  66 + certPath: ''
  67 + },
  68 + rules: {
  69 + name: [
  70 + { required: true, message: this.$t('smallWeChatManage.nameRequired'), trigger: 'blur' },
  71 + { max: 100, message: this.$t('smallWeChatManage.nameMaxLength'), trigger: 'blur' }
  72 + ],
  73 + appId: [
  74 + { required: true, message: this.$t('smallWeChatManage.appIdRequired'), trigger: 'blur' },
  75 + { max: 100, message: this.$t('smallWeChatManage.appIdMaxLength'), trigger: 'blur' }
  76 + ],
  77 + appSecret: [
  78 + { required: true, message: this.$t('smallWeChatManage.appSecretRequired'), trigger: 'blur' },
  79 + { max: 200, message: this.$t('smallWeChatManage.appSecretMaxLength'), trigger: 'blur' }
  80 + ],
  81 + wechatId: [
  82 + { required: true, message: this.$t('smallWeChatManage.wechatIdRequired'), trigger: 'blur' }
  83 + ]
  84 + },
  85 + objTypes: []
  86 + }
  87 + },
  88 + methods: {
  89 + open(data) {
  90 + this.formData = { ...data }
  91 + this.formData.objId = getCommunityId()
  92 + this.getDictData()
  93 + this.visible = true
  94 + },
  95 + async getDictData() {
  96 + try {
  97 + const objTypes = await getDict('small_wechat', 'obj_type')
  98 + this.objTypes = objTypes
  99 + } catch (error) {
  100 + console.error('Failed to get dict data:', error)
  101 + }
  102 + },
  103 + handleClose() {
  104 + this.$refs.form.resetFields()
  105 + this.formData = {
  106 + wechatId: '',
  107 + name: '',
  108 + appId: '',
  109 + appSecret: '',
  110 + remarks: '',
  111 + objType: '1000',
  112 + objId: '',
  113 + payPassword: '1',
  114 + mchId: '1',
  115 + mchName: '1',
  116 + certPath: ''
  117 + }
  118 + },
  119 + handleSubmit() {
  120 + this.$refs.form.validate(async valid => {
  121 + if (valid) {
  122 + try {
  123 + await updateSmallWeChat(this.formData)
  124 + this.$message.success(this.$t('smallWeChatManage.editSuccess'))
  125 + this.visible = false
  126 + this.$emit('success')
  127 + } catch (error) {
  128 + this.$message.error(error.message || this.$t('smallWeChatManage.editFailed'))
  129 + }
  130 + }
  131 + })
  132 + }
  133 + }
  134 +}
  135 +</script>
0 136 \ No newline at end of file
... ...
src/components/system/feeConfigDetailHis.vue 0 → 100644
  1 +<template>
  2 + <div class="fee-config-detail-his">
  3 + <el-table
  4 + :data="feeConfigDetailHisInfo.feeDetails"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + prop="feeTypeCdName"
  10 + :label="$t('feeConfigDetailHis.feeTypeCdName')"
  11 + align="center">
  12 + </el-table-column>
  13 + <el-table-column
  14 + prop="feeName"
  15 + :label="$t('feeConfigDetailHis.feeName')"
  16 + align="center">
  17 + </el-table-column>
  18 + <el-table-column
  19 + prop="feeFlagName"
  20 + :label="$t('feeConfigDetailHis.feeFlagName')"
  21 + align="center">
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="billTypeName"
  25 + :label="$t('feeConfigDetailHis.billTypeName')"
  26 + align="center">
  27 + </el-table-column>
  28 + <el-table-column
  29 + :label="$t('feeConfigDetailHis.paymentCd')"
  30 + align="center">
  31 + <template slot-scope="scope">
  32 + {{ scope.row.paymentCd === '1200' ? $t('feeConfigDetailHis.prePayment') : $t('feeConfigDetailHis.postPayment') }}
  33 + </template>
  34 + </el-table-column>
  35 + <el-table-column
  36 + prop="paymentCycle"
  37 + :label="$t('feeConfigDetailHis.paymentCycle')"
  38 + align="center">
  39 + </el-table-column>
  40 + <el-table-column
  41 + :label="$t('feeConfigDetailHis.validityPeriod')"
  42 + align="center">
  43 + <template slot-scope="scope">
  44 + <div>{{ scope.row.startTime }}</div>
  45 + <div>{{ scope.row.endTime }}</div>
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column
  49 + :label="$t('feeConfigDetailHis.squarePrice')"
  50 + align="center">
  51 + <template slot-scope="scope">
  52 + {{ scope.row.computingFormula === '2002' ? '-' : scope.row.squarePrice }}
  53 + </template>
  54 + </el-table-column>
  55 + <el-table-column
  56 + prop="additionalAmount"
  57 + :label="$t('feeConfigDetailHis.additionalAmount')"
  58 + align="center">
  59 + </el-table-column>
  60 + <el-table-column
  61 + :label="$t('feeConfigDetailHis.deductFrom')"
  62 + align="center">
  63 + <template slot-scope="scope">
  64 + {{ scope.row.deductFrom === 'Y' ? $t('common.yes') : $t('common.no') }}
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column
  68 + :label="$t('feeConfigDetailHis.payOnline')"
  69 + align="center">
  70 + <template slot-scope="scope">
  71 + {{ scope.row.payOnline === 'Y' ? $t('common.yes') : $t('common.no') }}
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column
  75 + :label="$t('feeConfigDetailHis.scale')"
  76 + align="center">
  77 + <template slot-scope="scope">
  78 + <div v-if="scope.row.scale === '1'">{{ $t('feeConfigDetailHis.round') }}</div>
  79 + <div v-if="scope.row.scale === '3'">{{ $t('feeConfigDetailHis.roundUp') }}</div>
  80 + <div v-if="scope.row.scale === '4'">{{ $t('feeConfigDetailHis.roundDown') }}</div>
  81 + </template>
  82 + </el-table-column>
  83 + <el-table-column
  84 + prop="decimalPlace"
  85 + :label="$t('feeConfigDetailHis.decimalPlace')"
  86 + align="center">
  87 + </el-table-column>
  88 + <el-table-column
  89 + :label="$t('feeConfigDetailHis.operate')"
  90 + align="center">
  91 + <template slot-scope="scope">
  92 + {{ _getHisConfigOperate(scope.row) }}
  93 + </template>
  94 + </el-table-column>
  95 + <el-table-column
  96 + prop="userName"
  97 + :label="$t('feeConfigDetailHis.userName')"
  98 + align="center">
  99 + <template slot-scope="scope">
  100 + {{ scope.row.userName || '-' }}
  101 + </template>
  102 + </el-table-column>
  103 + <el-table-column
  104 + prop="createTime"
  105 + :label="$t('feeConfigDetailHis.createTime')"
  106 + align="center">
  107 + <template slot-scope="scope">
  108 + {{ scope.row.createTime || '-' }}
  109 + </template>
  110 + </el-table-column>
  111 + </el-table>
  112 +
  113 + <el-pagination
  114 + @size-change="handleSizeChange"
  115 + @current-change="handleCurrentChange"
  116 + :current-page="page.current"
  117 + :page-sizes="[10, 20, 30, 50]"
  118 + :page-size="page.size"
  119 + layout="total, sizes, prev, pager, next, jumper"
  120 + :total="page.total">
  121 + </el-pagination>
  122 + </div>
  123 +</template>
  124 +
  125 +<script>
  126 +import { queryHisFeeConfig } from '@/api/system/operateDataLogApi'
  127 +
  128 +export default {
  129 + name: 'FeeConfigDetailHis',
  130 + data() {
  131 + return {
  132 + loading: false,
  133 + feeConfigDetailHisInfo: {
  134 + feeDetails: [],
  135 + configId: '',
  136 + staffNameLike: '',
  137 + feeNameLike: '',
  138 + logStartTime: '',
  139 + logEndTime: ''
  140 + },
  141 + page: {
  142 + current: 1,
  143 + size: 10,
  144 + total: 0
  145 + }
  146 + }
  147 + },
  148 + methods: {
  149 + open(conditions) {
  150 + this.feeConfigDetailHisInfo = {
  151 + ...this.feeConfigDetailHisInfo,
  152 + ...conditions
  153 + }
  154 + this._loadFeeConfigDetailHisData()
  155 + },
  156 + async _loadFeeConfigDetailHisData() {
  157 + try {
  158 + this.loading = true
  159 + const params = {
  160 + page: this.page.current,
  161 + row: this.page.size,
  162 + configId: this.feeConfigDetailHisInfo.configId,
  163 + staffNameLike: this.feeConfigDetailHisInfo.staffNameLike,
  164 + feeNameLike: this.feeConfigDetailHisInfo.feeNameLike,
  165 + logStartTime: this.feeConfigDetailHisInfo.logStartTime,
  166 + logEndTime: this.feeConfigDetailHisInfo.logEndTime
  167 + }
  168 +
  169 + const { data, total } = await queryHisFeeConfig(params)
  170 + this.feeConfigDetailHisInfo.feeDetails = data
  171 + this.page.total = total
  172 + } catch (error) {
  173 + console.error('Failed to load fee config history:', error)
  174 + } finally {
  175 + this.loading = false
  176 + }
  177 + },
  178 + _getHisConfigOperate(fee) {
  179 + const feeCount = this.feeConfigDetailHisInfo.feeDetails.filter(item => item.bId === fee.bId).length
  180 +
  181 + if (feeCount <= 1) {
  182 + if (fee.operate === 'ADD') return this.$t('feeConfigDetailHis.add')
  183 + if (fee.operate === 'DEL') return this.$t('feeConfigDetailHis.delete')
  184 + return '-'
  185 + }
  186 +
  187 + if (fee.operate === 'ADD') return this.$t('feeConfigDetailHis.modifyNew')
  188 + if (fee.operate === 'DEL') return this.$t('feeConfigDetailHis.modifyOld')
  189 + return '-'
  190 + },
  191 + handleSizeChange(size) {
  192 + this.page.size = size
  193 + this._loadFeeConfigDetailHisData()
  194 + },
  195 + handleCurrentChange(current) {
  196 + this.page.current = current
  197 + this._loadFeeConfigDetailHisData()
  198 + }
  199 + }
  200 +}
  201 +</script>
  202 +
  203 +<style scoped>
  204 +.fee-config-detail-his {
  205 + padding: 20px;
  206 +}
  207 +
  208 +.el-pagination {
  209 + margin-top: 20px;
  210 + text-align: right;
  211 +}
  212 +</style>
0 213 \ No newline at end of file
... ...
src/components/system/feeDetailHis.vue 0 → 100644
  1 +<template>
  2 + <div class="fee-detail-his">
  3 + <el-table
  4 + :data="feeDetailHisInfo.fees"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + :label="$t('feeDetailHis.feeName')"
  10 + align="center">
  11 + <template slot-scope="scope">
  12 + {{ scope.row.feeName }}
  13 + <span v-if="scope.row.payerObjName">({{ scope.row.payerObjName }})</span>
  14 + </template>
  15 + </el-table-column>
  16 + <el-table-column
  17 + :label="$t('feeDetailHis.startTime')"
  18 + align="center">
  19 + <template slot-scope="scope">
  20 + {{ scope.row.startTime || '-' }}
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column
  24 + :label="$t('feeDetailHis.endTime')"
  25 + align="center">
  26 + <template slot-scope="scope">
  27 + {{ scope.row.endTime || '-' }}
  28 + </template>
  29 + </el-table-column>
  30 + <el-table-column
  31 + :label="$t('feeDetailHis.operate')"
  32 + align="center">
  33 + <template slot-scope="scope">
  34 + {{ _getFeeHisOperate(scope.row) }}
  35 + </template>
  36 + </el-table-column>
  37 + <el-table-column
  38 + :label="$t('feeDetailHis.userName')"
  39 + align="center">
  40 + <template slot-scope="scope">
  41 + {{ scope.row.userName || '-' }}
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column
  45 + :label="$t('feeDetailHis.createTime')"
  46 + align="center">
  47 + <template slot-scope="scope">
  48 + {{ scope.row.createTime }}
  49 + </template>
  50 + </el-table-column>
  51 + </el-table>
  52 +
  53 + <el-pagination
  54 + @size-change="handleSizeChange"
  55 + @current-change="handleCurrentChange"
  56 + :current-page="page.current"
  57 + :page-sizes="[10, 20, 30, 50]"
  58 + :page-size="page.size"
  59 + layout="total, sizes, prev, pager, next, jumper"
  60 + :total="page.total">
  61 + </el-pagination>
  62 + </div>
  63 +</template>
  64 +
  65 +<script>
  66 +import { queryHisFee } from '@/api/system/operateDataLogApi'
  67 +
  68 +export default {
  69 + name: 'FeeDetailHis',
  70 + data() {
  71 + return {
  72 + loading: false,
  73 + feeDetailHisInfo: {
  74 + fees: [],
  75 + feeId: '',
  76 + staffNameLike: '',
  77 + feeNameLike: '',
  78 + payerObjName: '',
  79 + logStartTime: '',
  80 + logEndTime: ''
  81 + },
  82 + page: {
  83 + current: 1,
  84 + size: 10,
  85 + total: 0
  86 + }
  87 + }
  88 + },
  89 + methods: {
  90 + open(conditions) {
  91 + this.feeDetailHisInfo = {
  92 + ...this.feeDetailHisInfo,
  93 + ...conditions
  94 + }
  95 + this._loadFeeDetailHisData()
  96 + },
  97 + async _loadFeeDetailHisData() {
  98 + try {
  99 + this.loading = true
  100 + const params = {
  101 + page: this.page.current,
  102 + row: this.page.size,
  103 + feeId: this.feeDetailHisInfo.feeId,
  104 + staffNameLike: this.feeDetailHisInfo.staffNameLike,
  105 + feeNameLike: this.feeDetailHisInfo.feeNameLike,
  106 + payerObjName: this.feeDetailHisInfo.payerObjName,
  107 + logStartTime: this.feeDetailHisInfo.logStartTime,
  108 + logEndTime: this.feeDetailHisInfo.logEndTime
  109 + }
  110 +
  111 + const { data, total } = await queryHisFee(params)
  112 + this.feeDetailHisInfo.fees = data
  113 + this.page.total = total
  114 + } catch (error) {
  115 + console.error('Failed to load fee history:', error)
  116 + } finally {
  117 + this.loading = false
  118 + }
  119 + },
  120 + _getFeeHisOperate(fee) {
  121 + const feeCount = this.feeDetailHisInfo.fees.filter(item => item.bId === fee.bId).length
  122 +
  123 + if (feeCount <= 1) {
  124 + if (fee.operate === 'ADD') return this.$t('feeDetailHis.add')
  125 + if (fee.operate === 'DEL') return this.$t('feeDetailHis.delete')
  126 + return '-'
  127 + }
  128 +
  129 + if (fee.operate === 'ADD') return this.$t('feeDetailHis.modifyNew')
  130 + if (fee.operate === 'DEL') return this.$t('feeDetailHis.modifyOld')
  131 + return '-'
  132 + },
  133 + handleSizeChange(size) {
  134 + this.page.size = size
  135 + this._loadFeeDetailHisData()
  136 + },
  137 + handleCurrentChange(current) {
  138 + this.page.current = current
  139 + this._loadFeeDetailHisData()
  140 + }
  141 + }
  142 +}
  143 +</script>
  144 +
  145 +<style scoped>
  146 +.fee-detail-his {
  147 + padding: 20px;
  148 +}
  149 +
  150 +.el-pagination {
  151 + margin-top: 20px;
  152 + text-align: right;
  153 +}
  154 +</style>
0 155 \ No newline at end of file
... ...
src/components/system/ownerDetailHis.vue 0 → 100644
  1 +<template>
  2 + <div class="owner-detail-his">
  3 + <el-table
  4 + :data="ownerDetailHisInfo.owners"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + :label="$t('ownerDetailHis.operate')"
  10 + align="center">
  11 + <template slot-scope="scope">
  12 + {{ _getHisOwnerOperate(scope.row) }}
  13 + </template>
  14 + </el-table-column>
  15 + <el-table-column
  16 + :label="$t('ownerDetailHis.userName')"
  17 + align="center">
  18 + <template slot-scope="scope">
  19 + {{ scope.row.userName || '-' }}
  20 + </template>
  21 + </el-table-column>
  22 + <el-table-column
  23 + :label="$t('ownerDetailHis.createTime')"
  24 + align="center">
  25 + <template slot-scope="scope">
  26 + {{ scope.row.createTime }}
  27 + </template>
  28 + </el-table-column>
  29 + <el-table-column
  30 + :label="$t('ownerDetailHis.name')"
  31 + align="center">
  32 + <template slot-scope="scope">
  33 + {{ scope.row.name }}({{ scope.row.link }})
  34 + </template>
  35 + </el-table-column>
  36 + <el-table-column
  37 + :label="$t('ownerDetailHis.sex')"
  38 + align="center">
  39 + <template slot-scope="scope">
  40 + {{ scope.row.sex === 0 ? $t('ownerDetailHis.male') : $t('ownerDetailHis.female') }}
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column
  44 + :label="$t('ownerDetailHis.idCard')"
  45 + align="center">
  46 + <template slot-scope="scope">
  47 + {{ scope.row.idCard || '-' }}
  48 + </template>
  49 + </el-table-column>
  50 + <el-table-column
  51 + :label="$t('ownerDetailHis.address')"
  52 + align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.address || '-' }}
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column
  58 + v-for="(item,index) in ownerDetailHisInfo.listColumns"
  59 + :key="index"
  60 + :label="item"
  61 + align="center">
  62 + <template slot-scope="scope">
  63 + {{ scope.row.listValues[index] || '-' }}
  64 + </template>
  65 + </el-table-column>
  66 + </el-table>
  67 +
  68 + <el-pagination
  69 + @size-change="handleSizeChange"
  70 + @current-change="handleCurrentChange"
  71 + :current-page="page.current"
  72 + :page-sizes="[10, 20, 30, 50]"
  73 + :page-size="page.size"
  74 + layout="total, sizes, prev, pager, next, jumper"
  75 + :total="page.total">
  76 + </el-pagination>
  77 + </div>
  78 +</template>
  79 +
  80 +<script>
  81 +import { queryHisOwner, getAttrSpec } from '@/api/system/operateDataLogApi'
  82 +
  83 +export default {
  84 + name: 'OwnerDetailHis',
  85 + data() {
  86 + return {
  87 + loading: false,
  88 + ownerDetailHisInfo: {
  89 + owners: [],
  90 + ownerId: '',
  91 + ownerName: '',
  92 + carNum: '',
  93 + listColumns: [],
  94 + logStartTime: '',
  95 + logEndTime: '',
  96 + ownerNameLike: '',
  97 + staffNameLike: ''
  98 + },
  99 + page: {
  100 + current: 1,
  101 + size: 10,
  102 + total: 0
  103 + }
  104 + }
  105 + },
  106 + methods: {
  107 + async open(conditions) {
  108 + this.ownerDetailHisInfo = {
  109 + ...this.ownerDetailHisInfo,
  110 + ...conditions
  111 + }
  112 + await this._getColumns()
  113 + this._loadOwnerDetailHisData()
  114 + },
  115 + async _loadOwnerDetailHisData() {
  116 + try {
  117 + this.loading = true
  118 + const params = {
  119 + page: this.page.current,
  120 + row: this.page.size,
  121 + memberId: this.ownerDetailHisInfo.ownerId,
  122 + ownerNameLike: this.ownerDetailHisInfo.ownerNameLike,
  123 + logStartTime: this.ownerDetailHisInfo.logStartTime,
  124 + logEndTime: this.ownerDetailHisInfo.logEndTime,
  125 + staffNameLike: this.ownerDetailHisInfo.staffNameLike
  126 + }
  127 +
  128 + const { data, total } = await queryHisOwner(params)
  129 + this.ownerDetailHisInfo.owners = data
  130 + this._dealOwnerAttr(data)
  131 + this.page.total = total
  132 + } catch (error) {
  133 + console.error('Failed to load owner history:', error)
  134 + } finally {
  135 + this.loading = false
  136 + }
  137 + },
  138 + _getHisOwnerOperate(owner) {
  139 + const ownerCount = this.ownerDetailHisInfo.owners.filter(item => item.bId === owner.bId).length
  140 +
  141 + if (ownerCount <= 1) {
  142 + if (owner.operate === 'ADD') return this.$t('ownerDetailHis.add')
  143 + if (owner.operate === 'DEL') return this.$t('ownerDetailHis.delete')
  144 + return '-'
  145 + }
  146 +
  147 + if (owner.operate === 'ADD') return this.$t('ownerDetailHis.modifyNew')
  148 + if (owner.operate === 'DEL') return this.$t('ownerDetailHis.modifyOld')
  149 + return '-'
  150 + },
  151 + async _getColumns() {
  152 + try {
  153 + const data = await getAttrSpec('building_owner_attr')
  154 + this.ownerDetailHisInfo.listColumns = data
  155 + .filter(item => item.listShow === 'Y')
  156 + .map(item => item.specName)
  157 + } catch (error) {
  158 + console.error('Failed to get columns:', error)
  159 + }
  160 + },
  161 + _dealOwnerAttr(owners) {
  162 + if (!owners) return
  163 +
  164 + owners.forEach(item => {
  165 + this._getColumnsValue(item)
  166 + })
  167 + },
  168 + _getColumnsValue(owner) {
  169 + owner.listValues = []
  170 + if (!owner['ownerAttrDtos'] || owner.ownerAttrDtos.length < 1) {
  171 + this.ownerDetailHisInfo.listColumns.forEach(() => {
  172 + owner.listValues.push('')
  173 + })
  174 + return
  175 + }
  176 +
  177 + this.ownerDetailHisInfo.listColumns.forEach(value => {
  178 + let tmpValue = ''
  179 + owner.ownerAttrDtos.forEach(attrItem => {
  180 + if (value === attrItem.specName) {
  181 + tmpValue = attrItem.valueName
  182 + }
  183 + })
  184 + owner.listValues.push(tmpValue)
  185 + })
  186 + },
  187 + handleSizeChange(size) {
  188 + this.page.size = size
  189 + this._loadOwnerDetailHisData()
  190 + },
  191 + handleCurrentChange(current) {
  192 + this.page.current = current
  193 + this._loadOwnerDetailHisData()
  194 + }
  195 + }
  196 +}
  197 +</script>
  198 +
  199 +<style scoped>
  200 +.owner-detail-his {
  201 + padding: 20px;
  202 +}
  203 +
  204 +.el-pagination {
  205 + margin-top: 20px;
  206 + text-align: right;
  207 +}
  208 +</style>
0 209 \ No newline at end of file
... ...
src/components/system/roomDetailHis.vue 0 → 100644
  1 +<template>
  2 + <div class="room-detail-his">
  3 + <el-table
  4 + :data="roomDetailHisInfo.rooms"
  5 + border
  6 + style="width: 100%"
  7 + v-loading="loading">
  8 + <el-table-column
  9 + :label="$t('roomDetailHis.operate')"
  10 + align="center">
  11 + <template slot-scope="scope">
  12 + {{ _getRoomHisOperate(scope.row) }}
  13 + </template>
  14 + </el-table-column>
  15 + <el-table-column
  16 + :label="$t('roomDetailHis.userName')"
  17 + align="center">
  18 + <template slot-scope="scope">
  19 + {{ scope.row.userName || '-' }}
  20 + </template>
  21 + </el-table-column>
  22 + <el-table-column
  23 + :label="$t('roomDetailHis.createTime')"
  24 + align="center">
  25 + <template slot-scope="scope">
  26 + {{ scope.row.createTime }}
  27 + </template>
  28 + </el-table-column>
  29 + <el-table-column
  30 + :label="$t('roomDetailHis.roomNum')"
  31 + align="center">
  32 + <template slot-scope="scope">
  33 + {{ scope.row.floorNum }}-{{ scope.row.unitNum }}-{{ scope.row.roomNum }}
  34 + </template>
  35 + </el-table-column>
  36 + <el-table-column
  37 + :label="$t('roomDetailHis.layer')"
  38 + align="center">
  39 + <template slot-scope="scope">
  40 + {{ scope.row.layer }}
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column
  44 + :label="$t('roomDetailHis.roomSubTypeName')"
  45 + align="center">
  46 + <template slot-scope="scope">
  47 + {{ scope.row.roomSubTypeName }}
  48 + </template>
  49 + </el-table-column>
  50 + <el-table-column
  51 + :label="$t('roomDetailHis.area')"
  52 + align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.builtUpArea }}/{{ scope.row.roomArea }}
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column
  58 + :label="$t('roomDetailHis.roomRent')"
  59 + align="center">
  60 + <template slot-scope="scope">
  61 + {{ scope.row.roomRent }}
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column
  65 + :label="$t('roomDetailHis.stateName')"
  66 + align="center">
  67 + <template slot-scope="scope">
  68 + {{ scope.row.stateName }}
  69 + </template>
  70 + </el-table-column>
  71 + </el-table>
  72 +
  73 + <el-pagination
  74 + @size-change="handleSizeChange"
  75 + @current-change="handleCurrentChange"
  76 + :current-page="page.current"
  77 + :page-sizes="[10, 20, 30, 50]"
  78 + :page-size="page.size"
  79 + layout="total, sizes, prev, pager, next, jumper"
  80 + :total="page.total">
  81 + </el-pagination>
  82 + </div>
  83 +</template>
  84 +
  85 +<script>
  86 +import { queryHisRoom } from '@/api/system/operateDataLogApi'
  87 +
  88 +export default {
  89 + name: 'RoomDetailHis',
  90 + data() {
  91 + return {
  92 + loading: false,
  93 + roomDetailHisInfo: {
  94 + rooms: [],
  95 + roomId: '',
  96 + roomName: '',
  97 + logStartTime: '',
  98 + logEndTime: '',
  99 + staffNameLike: '',
  100 + payerObjName: ''
  101 + },
  102 + page: {
  103 + current: 1,
  104 + size: 10,
  105 + total: 0
  106 + }
  107 + }
  108 + },
  109 + methods: {
  110 + open(conditions) {
  111 + this.roomDetailHisInfo = {
  112 + ...this.roomDetailHisInfo,
  113 + ...conditions
  114 + }
  115 + this._loadRoomDetailHisData()
  116 + },
  117 + async _loadRoomDetailHisData() {
  118 + try {
  119 + this.loading = true
  120 + const params = {
  121 + page: this.page.current,
  122 + row: this.page.size,
  123 + roomId: this.roomDetailHisInfo.roomId,
  124 + roomName: this.roomDetailHisInfo.roomName,
  125 + logStartTime: this.roomDetailHisInfo.logStartTime,
  126 + logEndTime: this.roomDetailHisInfo.logEndTime,
  127 + staffNameLike: this.roomDetailHisInfo.staffNameLike,
  128 + payerObjName: this.roomDetailHisInfo.payerObjName
  129 + }
  130 +
  131 + const { data, total } = await queryHisRoom(params)
  132 + this.roomDetailHisInfo.rooms = data
  133 + this.page.total = total
  134 + } catch (error) {
  135 + console.error('Failed to load room history:', error)
  136 + } finally {
  137 + this.loading = false
  138 + }
  139 + },
  140 + _getRoomHisOperate(room) {
  141 + const roomCount = this.roomDetailHisInfo.rooms.filter(item => item.bId === room.bId).length
  142 +
  143 + if (roomCount <= 1) {
  144 + if (room.operate === 'ADD') return this.$t('roomDetailHis.add')
  145 + if (room.operate === 'DEL') return this.$t('roomDetailHis.delete')
  146 + return '-'
  147 + }
  148 +
  149 + if (room.operate === 'ADD') return this.$t('roomDetailHis.modifyNew')
  150 + if (room.operate === 'DEL') return this.$t('roomDetailHis.modifyOld')
  151 + return '-'
  152 + },
  153 + handleSizeChange(size) {
  154 + this.page.size = size
  155 + this._loadRoomDetailHisData()
  156 + },
  157 + handleCurrentChange(current) {
  158 + this.page.current = current
  159 + this._loadRoomDetailHisData()
  160 + }
  161 + }
  162 +}
  163 +</script>
  164 +
  165 +<style scoped>
  166 +.room-detail-his {
  167 + padding: 20px;
  168 +}
  169 +
  170 +.el-pagination {
  171 + margin-top: 20px;
  172 + text-align: right;
  173 +}
  174 +</style>
0 175 \ No newline at end of file
... ...
src/components/system/uploadFile.vue 0 → 100644
  1 +<template>
  2 + <div class="upload-file-wrapper">
  3 + <div class="progress" v-if="progress > 0">
  4 + <el-progress :percentage="progress" :stroke-width="2" />
  5 + </div>
  6 + <div class="file-name" v-if="fileName">
  7 + {{ fileName }}
  8 + </div>
  9 + <el-upload
  10 + class="upload-demo"
  11 + action=""
  12 + :auto-upload="false"
  13 + :show-file-list="false"
  14 + :on-change="handleFileChange"
  15 + >
  16 + <el-button size="small" type="primary">
  17 + {{ $t('common.upload') }}
  18 + </el-button>
  19 + </el-upload>
  20 + </div>
  21 +</template>
  22 +
  23 +<script>
  24 +import { uploadFile } from '@/api/system/paymentPoolApi'
  25 +
  26 +export default {
  27 + name: 'UploadFile',
  28 + props: {
  29 + callBackListener: {
  30 + type: String,
  31 + default: ''
  32 + },
  33 + callBackFunction: {
  34 + type: String,
  35 + default: ''
  36 + }
  37 + },
  38 + data() {
  39 + return {
  40 + progress: 0,
  41 + fileName: '',
  42 + realFileName: ''
  43 + }
  44 + },
  45 + methods: {
  46 + clear() {
  47 + this.progress = 0
  48 + this.fileName = ''
  49 + this.realFileName = ''
  50 + },
  51 + handleFileChange(file) {
  52 + if (file.size > 20 * 1024 * 1024) {
  53 + this.$message.error(this.$t('uploadFile.sizeLimit'))
  54 + return false
  55 + }
  56 +
  57 + this.fileName = file.name
  58 + this.doUpload(file.raw)
  59 + },
  60 + async doUpload(file) {
  61 + const formData = new FormData()
  62 + formData.append('uploadFile', file)
  63 +
  64 + try {
  65 + const config = {
  66 + onUploadProgress: progressEvent => {
  67 + const percent = Math.round(
  68 + (progressEvent.loaded * 100) / progressEvent.total
  69 + )
  70 + this.progress = percent < 90 ? percent : 90
  71 + }
  72 + }
  73 +
  74 + const { data } = await uploadFile(formData, config)
  75 + this.progress = 100
  76 + this.realFileName = data.realFileName
  77 + this.$emit('notify', data)
  78 +
  79 + if (this.callBackListener && this.callBackFunction) {
  80 + this.$emit(this.callBackFunction, data)
  81 + }
  82 +
  83 + this.$message.success(this.$t('uploadFile.success'))
  84 + } catch (error) {
  85 + this.$message.error(this.$t('uploadFile.error'))
  86 + console.error('上传文件失败:', error)
  87 + }
  88 + }
  89 + }
  90 +}
  91 +</script>
  92 +
  93 +<style lang="scss" scoped>
  94 +.upload-file-wrapper {
  95 + .progress {
  96 + margin-bottom: 10px;
  97 + }
  98 +
  99 + .file-name {
  100 + margin-bottom: 10px;
  101 + font-size: 14px;
  102 + color: #606266;
  103 + }
  104 +}
  105 +</style>
0 106 \ No newline at end of file
... ...
src/components/system/uploadImageUrl.vue 0 → 100644
  1 +<template>
  2 + <div class="upload-image-container">
  3 + <div class="image-preview" v-for="(image, index) in images" :key="index">
  4 + <el-image
  5 + style="width: 100px; height: 100px; margin-right: 10px;"
  6 + :src="image.url"
  7 + fit="cover"
  8 + :preview-src-list="previewList">
  9 + </el-image>
  10 + <i class="el-icon-delete delete-icon" @click="removeImage(index)"></i>
  11 + </div>
  12 +
  13 + <el-upload
  14 + v-if="images.length < imageCount"
  15 + class="upload-button"
  16 + action=""
  17 + :show-file-list="false"
  18 + :before-upload="beforeUpload"
  19 + :http-request="handleUpload">
  20 + <i class="el-icon-plus"></i>
  21 + </el-upload>
  22 + </div>
  23 +</template>
  24 +
  25 +<script>
  26 +import { uploadFile } from '@/api/common'
  27 +
  28 +export default {
  29 + name: 'UploadImageUrl',
  30 + props: {
  31 + imageCount: {
  32 + type: Number,
  33 + default: 1
  34 + }
  35 + },
  36 + data() {
  37 + return {
  38 + images: [],
  39 + previewList: []
  40 + }
  41 + },
  42 + methods: {
  43 + beforeUpload(file) {
  44 + const isImage = file.type.indexOf('image/') === 0
  45 + const isLt2M = file.size / 1024 / 1024 < 2
  46 +
  47 + if (!isImage) {
  48 + this.$message.error(this.$t('upload.imageTypeError'))
  49 + }
  50 + if (!isLt2M) {
  51 + this.$message.error(this.$t('upload.imageSizeError'))
  52 + }
  53 + return isImage && isLt2M
  54 + },
  55 + async handleUpload({ file }) {
  56 + try {
  57 + const formData = new FormData()
  58 + formData.append('uploadFile', file)
  59 +
  60 + const response = await uploadFile(formData)
  61 + this.images.push(response.data)
  62 + this.previewList = this.images.map(img => img.url)
  63 + this.$emit('change', this.images)
  64 + } catch (error) {
  65 + this.$message.error(error.message || this.$t('upload.uploadFailed'))
  66 + }
  67 + },
  68 + removeImage(index) {
  69 + this.images.splice(index, 1)
  70 + this.previewList = this.images.map(img => img.url)
  71 + this.$emit('change', this.images)
  72 + },
  73 + clear() {
  74 + this.images = []
  75 + this.previewList = []
  76 + this.$emit('change', [])
  77 + },
  78 + setImages(urls) {
  79 + this.images = urls.map(url => ({ url }))
  80 + this.previewList = this.images.map(img => img.url)
  81 + this.$emit('change', this.images)
  82 + }
  83 + }
  84 +}
  85 +</script>
  86 +
  87 +<style lang="scss" scoped>
  88 +.upload-image-container {
  89 + display: flex;
  90 + flex-wrap: wrap;
  91 + align-items: center;
  92 +
  93 + .image-preview {
  94 + position: relative;
  95 + margin-right: 10px;
  96 + margin-bottom: 10px;
  97 +
  98 + .delete-icon {
  99 + position: absolute;
  100 + top: -10px;
  101 + right: 0;
  102 + color: #f56c6c;
  103 + font-size: 18px;
  104 + cursor: pointer;
  105 + background: white;
  106 + border-radius: 50%;
  107 + padding: 2px;
  108 + }
  109 + }
  110 +
  111 + .upload-button {
  112 + width: 100px;
  113 + height: 100px;
  114 + line-height: 100px;
  115 + text-align: center;
  116 + border: 1px dashed #d9d9d9;
  117 + border-radius: 6px;
  118 + cursor: pointer;
  119 +
  120 + &:hover {
  121 + border-color: #409EFF;
  122 + }
  123 +
  124 + i {
  125 + font-size: 28px;
  126 + color: #8c939d;
  127 + }
  128 + }
  129 +}
  130 +</style>
0 131 \ No newline at end of file
... ...
src/i18n/systemI18n.js
1 1 import { messages as communitySettingManageMessages } from '../views/system/communitySettingManageLang'
2 2 import { messages as storeInfoManageMessages } from '../views/system/storeInfoManageLang'
  3 +import { messages as publicWeChatManageMessages } from '../views/system/publicWeChatManageLang'
  4 +import { messages as smallWeChatManageMessages } from '../views/system/smallWeChatManageLang'
  5 +import { messages as paymentPoolMessages } from '../views/system/paymentPoolLang'
  6 +import { messages as operateDataLogMessages } from '../views/system/operateDataLogLang'
  7 +import { messages as historyFeeDetailImportMessages } from '../views/system/historyFeeDetailImportLang'
  8 +import { messages as feePrintSpecManageMessages } from '../views/system/feePrintSpecManageLang'
3 9 export const messages = {
4 10 en: {
5 11 ...communitySettingManageMessages.en,
6 12 ...storeInfoManageMessages.en,
  13 + ...publicWeChatManageMessages.en,
  14 + ...smallWeChatManageMessages.en,
  15 + ...paymentPoolMessages.en,
  16 + ...operateDataLogMessages.en,
  17 + ...historyFeeDetailImportMessages.en,
  18 + ...feePrintSpecManageMessages.en,
7 19 },
8 20 zh: {
9 21 ...communitySettingManageMessages.zh,
10 22 ...storeInfoManageMessages.zh,
  23 + ...publicWeChatManageMessages.zh,
  24 + ...smallWeChatManageMessages.zh,
  25 + ...paymentPoolMessages.zh,
  26 + ...operateDataLogMessages.zh,
  27 + ...historyFeeDetailImportMessages.zh,
  28 + ...feePrintSpecManageMessages.zh,
11 29 }
12 30 }
13 31 \ No newline at end of file
... ...
src/router/systemRouter.js
... ... @@ -15,8 +15,38 @@ export default [
15 15 component: () => import('@/views/system/workflowSettingManageList.vue')
16 16 },
17 17 {
18   - path:'/pages/common/storeInfoManage',
19   - name:'/pages/common/storeInfoManage',
  18 + path: '/pages/common/storeInfoManage',
  19 + name: '/pages/common/storeInfoManage',
20 20 component: () => import('@/views/system/storeInfoManageList.vue')
21   - },
  21 + },
  22 + {
  23 + path: '/pages/property/publicWeChatManage',
  24 + name: '/pages/property/publicWeChatManage',
  25 + component: () => import('@/views/system/publicWeChatManageList.vue')
  26 + },
  27 + {
  28 + path: '/pages/property/smallWeChatManage',
  29 + name: '/pages/property/smallWeChatManage',
  30 + component: () => import('@/views/system/smallWeChatManageList.vue')
  31 + },
  32 + {
  33 + path: '/pages/fee/paymentPool',
  34 + name: '/pages/fee/paymentPool',
  35 + component: () => import('@/views/system/paymentPoolList.vue')
  36 + },
  37 + {
  38 + path: '/pages/log/operateDataLog',
  39 + name: '/pages/log/operateDataLog',
  40 + component: () => import('@/views/system/operateDataLogList.vue')
  41 + },
  42 + {
  43 + path: '/pages/property/historyFeeDetailImport',
  44 + name: '/pages/property/historyFeeDetailImport',
  45 + component: () => import('@/views/system/historyFeeDetailImportList.vue')
  46 + },
  47 + {
  48 + path: '/pages/property/feePrintSpecManage',
  49 + name: '/pages/property/feePrintSpecManage',
  50 + component: () => import('@/views/system/feePrintSpecManageList.vue')
  51 + },
22 52 ]
23 53 \ No newline at end of file
... ...
src/views/system/feePrintSpecManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + feePrintSpecManage: {
  4 + title: 'Print Configuration',
  5 + add: 'Add',
  6 + edit: 'Edit',
  7 + delete: 'Delete',
  8 + image: 'Image',
  9 + name: 'Name',
  10 + spec: 'Specification',
  11 + code: 'Code',
  12 + operation: 'Operation',
  13 + reminderPrint: 'Reminder Print',
  14 + receiptPrint: 'Receipt Print',
  15 + addTitle: 'Add Print Configuration',
  16 + editTitle: 'Edit Print Configuration',
  17 + deleteTitle: 'Delete Confirmation',
  18 + deleteConfirm: 'Are you sure to delete this print configuration?',
  19 + deleteSuccess: 'Delete successfully',
  20 + deleteFailed: 'Delete failed',
  21 + addSuccess: 'Add successfully',
  22 + addFailed: 'Add failed',
  23 + editSuccess: 'Edit successfully',
  24 + editFailed: 'Edit failed',
  25 + fetchError: 'Failed to fetch data',
  26 + specPlaceholder: 'Please select specification',
  27 + namePlaceholder: 'Please enter name',
  28 + contentPlaceholder: 'Optional, please enter content',
  29 + specRequired: 'Specification is required',
  30 + nameRequired: 'Name is required',
  31 + nameMaxLength: 'Name cannot exceed 128 characters',
  32 + content: 'Content'
  33 + }
  34 + },
  35 + zh: {
  36 + feePrintSpecManage: {
  37 + title: '打印配置信息',
  38 + add: '添加',
  39 + edit: '修改',
  40 + delete: '删除',
  41 + image: '图片',
  42 + name: '名称',
  43 + spec: '规格',
  44 + code: '编码',
  45 + operation: '操作',
  46 + reminderPrint: '催缴打印说明',
  47 + receiptPrint: '收据打印说明',
  48 + addTitle: '添加打印配置',
  49 + editTitle: '修改打印配置',
  50 + deleteTitle: '删除确认',
  51 + deleteConfirm: '确定删除打印配置吗?',
  52 + deleteSuccess: '删除成功',
  53 + deleteFailed: '删除失败',
  54 + addSuccess: '添加成功',
  55 + addFailed: '添加失败',
  56 + editSuccess: '修改成功',
  57 + editFailed: '修改失败',
  58 + fetchError: '获取数据失败',
  59 + specPlaceholder: '请选择规格',
  60 + namePlaceholder: '请输入名称',
  61 + contentPlaceholder: '选填,请输入内容',
  62 + specRequired: '规格不能为空',
  63 + nameRequired: '名称不能为空',
  64 + nameMaxLength: '名称不能超过128个字符',
  65 + content: '内容'
  66 + }
  67 + }
  68 +}
0 69 \ No newline at end of file
... ...
src/views/system/feePrintSpecManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="fee-print-spec-manage-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between">
  5 + <span>{{ $t('feePrintSpecManage.title') }}</span>
  6 + <el-button type="primary" size="small" class="float-right" @click="openAddDialog">
  7 + <i class="el-icon-plus"></i>
  8 + {{ $t('feePrintSpecManage.add') }}
  9 + </el-button>
  10 + </div>
  11 +
  12 + <el-table :data="tableData" border style="width: 100%" v-loading="loading">
  13 + <el-table-column prop="qrImg" :label="$t('feePrintSpecManage.image')" align="center">
  14 + <template slot-scope="scope">
  15 + <el-image v-if="scope.row.qrImg" style="width: 100px; height: 100px; border-radius: 5px;"
  16 + :src="scope.row.qrImg" :preview-src-list="[scope.row.qrImg]">
  17 + </el-image>
  18 + </template>
  19 + </el-table-column>
  20 + <el-table-column prop="printName" :label="$t('feePrintSpecManage.name')" align="center">
  21 + </el-table-column>
  22 + <el-table-column prop="specCd" :label="$t('feePrintSpecManage.spec')" align="center">
  23 + <template slot-scope="scope">
  24 + {{ scope.row.specCd === '1010' ? $t('feePrintSpecManage.reminderPrint') :
  25 + $t('feePrintSpecManage.receiptPrint') }}
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column prop="printId" :label="$t('feePrintSpecManage.code')" align="center">
  29 + </el-table-column>
  30 + <el-table-column :label="$t('feePrintSpecManage.operation')" align="center" width="200">
  31 + <template slot-scope="scope">
  32 + <el-button size="mini" @click="openEditDialog(scope.row)">
  33 + {{ $t('feePrintSpecManage.edit') }}
  34 + </el-button>
  35 + <el-button size="mini" type="danger" @click="openDeleteDialog(scope.row)">
  36 + {{ $t('feePrintSpecManage.delete') }}
  37 + </el-button>
  38 + </template>
  39 + </el-table-column>
  40 + </el-table>
  41 +
  42 + <el-pagination class="pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange"
  43 + :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  44 + layout="total, sizes, prev, pager, next, jumper" :total="pagination.total">
  45 + </el-pagination>
  46 + </el-card>
  47 +
  48 + <add-fee-print-spec ref="addDialog" @success="fetchData"></add-fee-print-spec>
  49 + <edit-fee-print-spec ref="editDialog" @success="fetchData"></edit-fee-print-spec>
  50 + <delete-fee-print-spec ref="deleteDialog" @success="fetchData"></delete-fee-print-spec>
  51 + </div>
  52 +</template>
  53 +
  54 +<script>
  55 +import { queryFeePrintSpec } from '@/api/system/feePrintSpecManageApi'
  56 +import AddFeePrintSpec from '@/components/system/addFeePrintSpec'
  57 +import EditFeePrintSpec from '@/components/system/editFeePrintSpec'
  58 +import DeleteFeePrintSpec from '@/components/system/deleteFeePrintSpec'
  59 +import { getCommunityId } from '@/api/community/communityApi'
  60 +
  61 +export default {
  62 + name: 'FeePrintSpecManageList',
  63 + components: {
  64 + AddFeePrintSpec,
  65 + EditFeePrintSpec,
  66 + DeleteFeePrintSpec
  67 + },
  68 + data() {
  69 + return {
  70 + loading: false,
  71 + tableData: [],
  72 + pagination: {
  73 + current: 1,
  74 + size: 10,
  75 + total: 0
  76 + },
  77 + queryParams: {
  78 + communityId: '',
  79 + specCd: ''
  80 + }
  81 + }
  82 + },
  83 + created() {
  84 + this.queryParams.communityId = getCommunityId()
  85 + this.fetchData()
  86 + },
  87 + methods: {
  88 + async fetchData() {
  89 + try {
  90 + this.loading = true
  91 + const params = {
  92 + page: this.pagination.current,
  93 + row: this.pagination.size,
  94 + ...this.queryParams
  95 + }
  96 + const { data, total } = await queryFeePrintSpec(params)
  97 + this.tableData = data
  98 + this.pagination.total = total
  99 + } catch (error) {
  100 + this.$message.error(this.$t('feePrintSpecManage.fetchError'))
  101 + } finally {
  102 + this.loading = false
  103 + }
  104 + },
  105 + handleSizeChange(val) {
  106 + this.pagination.size = val
  107 + this.fetchData()
  108 + },
  109 + handleCurrentChange(val) {
  110 + this.pagination.current = val
  111 + this.fetchData()
  112 + },
  113 + openAddDialog() {
  114 + this.$refs.addDialog.open()
  115 + },
  116 + openEditDialog(row) {
  117 + this.$refs.editDialog.open(row)
  118 + },
  119 + openDeleteDialog(row) {
  120 + this.$refs.deleteDialog.open(row)
  121 + }
  122 + }
  123 +}
  124 +</script>
  125 +
  126 +<style lang="scss" scoped>
  127 +.fee-print-spec-manage-container {
  128 + padding: 20px;
  129 +
  130 + .box-card {
  131 + margin-bottom: 20px;
  132 + }
  133 +
  134 + .float-right {
  135 + float: right;
  136 + }
  137 +
  138 + .pagination {
  139 + margin-top: 20px;
  140 + text-align: right;
  141 + }
  142 +}
  143 +</style>
0 144 \ No newline at end of file
... ...
src/views/system/historyFeeDetailImportLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + historyFeeDetailImport: {
  4 + assetInfo: 'Asset Information',
  5 + feeObject: 'Fee Object',
  6 + selectFeeObject: 'Required, please select fee object',
  7 + house: 'House',
  8 + car: 'Car',
  9 + selectFile: 'Select File',
  10 + requiredFile: 'Required, please select data file',
  11 + clickUpload: 'Click to upload',
  12 + description: 'Description',
  13 + importTip: 'Note: This is for importing historical payment data from previous property systems to facilitate future accounting checks. It should only be used during property data initialization. Please carefully check the data before importing. Once imported, payment history cannot be deleted from the frontend and can only be removed by engineers from the database.',
  14 + import: 'Import',
  15 + houseTemplate: 'House Template',
  16 + carTemplate: 'Car Template',
  17 + fileRequired: 'File is required',
  18 + invalidFileType: 'Invalid file type, only Excel files are allowed',
  19 + fileSizeLimit: 'File size cannot exceed 2MB',
  20 + importSuccess: 'Import successful',
  21 + importError: 'Import failed',
  22 + requiredSelect: 'Required, please select'
  23 + }
  24 + },
  25 + zh: {
  26 + historyFeeDetailImport: {
  27 + assetInfo: '资产信息',
  28 + feeObject: '费用对象',
  29 + selectFeeObject: '必填,请选择费用对象',
  30 + house: '房屋',
  31 + car: '车辆',
  32 + selectFile: '选择文件',
  33 + requiredFile: '必填,请选择数据文件',
  34 + clickUpload: '点击上传',
  35 + description: '说明',
  36 + importTip: '请注意,这里是为了将物业之前系统缴费历史数据导入,方便物业后期查账使用,只有在物业数据初始化时使用,导入前请仔细检查数据,一旦导入前台无法删除缴费历史,只有工程师从数据库删除',
  37 + import: '导入',
  38 + houseTemplate: '房屋模板',
  39 + carTemplate: '车辆模板',
  40 + fileRequired: '文件不能为空',
  41 + invalidFileType: '不是有效的Excel格式',
  42 + fileSizeLimit: 'Excel文件大小不能超过2M',
  43 + importSuccess: '处理成功',
  44 + importError: '导入失败',
  45 + requiredSelect: '必填,请选择'
  46 + }
  47 + }
  48 +}
0 49 \ No newline at end of file
... ...
src/views/system/historyFeeDetailImportList.vue 0 → 100644
  1 +<template>
  2 + <div class="history-fee-detail-import-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('historyFeeDetailImport.assetInfo') }}</span>
  6 + <div class="card-header-right">
  7 + <el-button type="primary" size="small" @click="_openDownloadHcExcelTemplate">
  8 + <i class="el-icon-download"></i>{{ $t('historyFeeDetailImport.houseTemplate') }}
  9 + </el-button>
  10 + <el-button type="primary" size="small" @click="_openDownloadHcCarExcelTemplate">
  11 + <i class="el-icon-download"></i>{{ $t('historyFeeDetailImport.carTemplate') }}
  12 + </el-button>
  13 + </div>
  14 + </div>
  15 +
  16 + <el-row :gutter="20">
  17 + <el-col :span="24">
  18 + <el-form label-position="left" label-width="120px">
  19 + <el-form-item :label="$t('historyFeeDetailImport.feeObject')">
  20 + <el-select
  21 + v-model="historyFeeDetailImportInfo.objType"
  22 + style="width:100%"
  23 + :placeholder="$t('historyFeeDetailImport.selectFeeObject')">
  24 + <el-option
  25 + disabled
  26 + value=""
  27 + :label="$t('historyFeeDetailImport.requiredSelect')">
  28 + </el-option>
  29 + <el-option
  30 + value="3333"
  31 + :label="$t('historyFeeDetailImport.house')">
  32 + </el-option>
  33 + <el-option
  34 + value="6666"
  35 + :label="$t('historyFeeDetailImport.car')">
  36 + </el-option>
  37 + </el-select>
  38 + </el-form-item>
  39 +
  40 + <el-form-item :label="$t('historyFeeDetailImport.selectFile')">
  41 + <el-upload
  42 + class="upload-demo"
  43 + action=""
  44 + :auto-upload="false"
  45 + :on-change="getExcelTemplate"
  46 + :show-file-list="false">
  47 + <el-button size="small" type="primary">
  48 + {{ $t('historyFeeDetailImport.clickUpload') }}
  49 + </el-button>
  50 + <div slot="tip" class="el-upload__tip">
  51 + {{ historyFeeDetailImportInfo.excelTemplate ?
  52 + historyFeeDetailImportInfo.excelTemplate.name :
  53 + $t('historyFeeDetailImport.requiredFile') }}
  54 + </div>
  55 + </el-upload>
  56 + </el-form-item>
  57 +
  58 + <el-form-item :label="$t('historyFeeDetailImport.description')">
  59 + <div class="description-text">
  60 + {{ $t('historyFeeDetailImport.importTip') }}
  61 + </div>
  62 + </el-form-item>
  63 + </el-form>
  64 + </el-col>
  65 + </el-row>
  66 +
  67 + <el-row>
  68 + <el-col :span="24" class="text-right">
  69 + <el-button
  70 + type="primary"
  71 + @click="_importData"
  72 + :disabled="!historyFeeDetailImportInfo.excelTemplate || !historyFeeDetailImportInfo.objType">
  73 + {{ $t('historyFeeDetailImport.import') }}
  74 + </el-button>
  75 + </el-col>
  76 + </el-row>
  77 + </el-card>
  78 + </div>
  79 +</template>
  80 +
  81 +<script>
  82 +import { importData } from '@/api/system/historyFeeDetailImportApi'
  83 +import { getCommunityId } from '@/api/community/communityApi'
  84 +
  85 +export default {
  86 + name: 'HistoryFeeDetailImportList',
  87 + data() {
  88 + return {
  89 + historyFeeDetailImportInfo: {
  90 + communityId: '',
  91 + excelTemplate: null,
  92 + objType: ''
  93 + }
  94 + }
  95 + },
  96 + created() {
  97 + this.historyFeeDetailImportInfo.communityId = getCommunityId()
  98 + },
  99 + methods: {
  100 + _openDownloadHcExcelTemplate() {
  101 + window.open('/import/importFeeDetail.xlsx')
  102 + },
  103 + _openDownloadHcCarExcelTemplate() {
  104 + window.open('/import/importCarFeeDetail.xlsx')
  105 + },
  106 + getExcelTemplate(file) {
  107 + this.historyFeeDetailImportInfo.excelTemplate = file.raw
  108 + },
  109 + async _importData() {
  110 + if (!this.validateForm()) {
  111 + return
  112 + }
  113 +
  114 + const param = new FormData()
  115 + param.append('uploadFile', this.historyFeeDetailImportInfo.excelTemplate)
  116 + param.append('communityId', this.historyFeeDetailImportInfo.communityId)
  117 + param.append('objType', this.historyFeeDetailImportInfo.objType)
  118 +
  119 + const _importAdapt = this.historyFeeDetailImportInfo.objType === '6666' ?
  120 + 'importCarHistoryFeeDetail' : 'importRoomHistoryFeeDetail'
  121 + param.append('importAdapt', _importAdapt)
  122 +
  123 + try {
  124 + const res = await importData(param)
  125 + if (res.code === 0) {
  126 + this.$message.success(this.$t('historyFeeDetailImport.importSuccess'))
  127 + this.historyFeeDetailImportInfo.excelTemplate = null
  128 + this.$router.push({
  129 + path: '/pages/property/assetImportLogDetail',
  130 + query: {
  131 + logId: res.data.logId,
  132 + logType: _importAdapt
  133 + }
  134 + })
  135 + } else {
  136 + this.$message.error(res.msg)
  137 + }
  138 + } catch (error) {
  139 + this.$message.error(this.$t('historyFeeDetailImport.importError'))
  140 + }
  141 + },
  142 + validateForm() {
  143 + if (!this.historyFeeDetailImportInfo.excelTemplate) {
  144 + this.$message.error(this.$t('historyFeeDetailImport.fileRequired'))
  145 + return false
  146 + }
  147 +
  148 + if (!this.checkFileType(this.historyFeeDetailImportInfo.excelTemplate.name)) {
  149 + this.$message.error(this.$t('historyFeeDetailImport.invalidFileType'))
  150 + return false
  151 + }
  152 +
  153 + if (!this.checkFileSize(this.historyFeeDetailImportInfo.excelTemplate.size)) {
  154 + this.$message.error(this.$t('historyFeeDetailImport.fileSizeLimit'))
  155 + return false
  156 + }
  157 +
  158 + return true
  159 + },
  160 + checkFileType(fileName) {
  161 + const fileExt = fileName.split('.').pop().toLowerCase()
  162 + return ['xls', 'xlsx'].includes(fileExt)
  163 + },
  164 + checkFileSize(fileSize) {
  165 + return fileSize <= 2 * 1024 * 1024 // 2MB
  166 + }
  167 + }
  168 +}
  169 +</script>
  170 +
  171 +<style lang="scss" scoped>
  172 +.history-fee-detail-import-container {
  173 + padding: 20px;
  174 +
  175 + .box-card {
  176 + margin-bottom: 20px;
  177 + }
  178 +
  179 + .card-header-right {
  180 + float: right;
  181 + }
  182 +
  183 + .description-text {
  184 + color: #606266;
  185 + font-size: 14px;
  186 + line-height: 1.5;
  187 + }
  188 +
  189 + .text-right {
  190 + text-align: right;
  191 + margin-top: 20px;
  192 + }
  193 +
  194 + .el-upload__tip {
  195 + margin-left: 10px;
  196 + display: inline-block;
  197 + vertical-align: middle;
  198 + }
  199 +}
  200 +</style>
0 201 \ No newline at end of file
... ...
src/views/system/operateDataLogLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + operateDataLog: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + logStartTime: 'Please select the start time',
  7 + logEndTime: 'Please select the end time',
  8 + staffNameLike: 'Please enter the operator',
  9 + feeNameLike: 'Please enter the fee item name',
  10 + payerObjName: 'Please enter the house name, license plate number or contract number',
  11 + ownerNameLike: 'Please enter the owner name',
  12 + roomName: 'Please enter the house name Building-Unit-Room',
  13 + carNumLike: 'Please enter the license plate number',
  14 + contractCode: 'Please enter the contract number'
  15 + },
  16 + },
  17 + feeConfigDetailHis: {
  18 + feeTypeCdName: 'fee type',
  19 + feeName: 'fee item',
  20 + feeFlagName: 'fee flag',
  21 + billTypeName: 'bill type',
  22 + paymentCd: 'payment type',
  23 + prePayment: 'pre payment',
  24 + postPayment: 'post payment',
  25 + paymentCycle: 'payment cycle(unit: month)',
  26 + validityPeriod: 'validity period',
  27 + squarePrice: 'square price(unit: yuan)',
  28 + additionalAmount: 'additional/fixed fee(unit: yuan)',
  29 + deductFrom: 'deduct from',
  30 + payOnline: 'pay online',
  31 + scale: 'scale',
  32 + round: 'round',
  33 + roundUp: 'round up',
  34 + roundDown: 'round down',
  35 + decimalPlace: 'decimal place',
  36 + operate: 'action',
  37 + userName: 'operator',
  38 + createTime: 'create time',
  39 + add: 'add',
  40 + delete: 'delete',
  41 + modifyNew: 'modify(new)',
  42 + modifyOld: 'modify(old)'
  43 + },
  44 + feeDetailHis: {
  45 + feeName: 'fee item',
  46 + startTime: 'create time',
  47 + endTime: 'start time',
  48 + operate: 'action',
  49 + userName: 'operator',
  50 + createTime: 'create time',
  51 + add: 'add',
  52 + delete: 'delete',
  53 + modifyNew: 'modify(new)',
  54 + modifyOld: 'modify(old)'
  55 + },
  56 + ownerDetailHis: {
  57 + operate: 'action',
  58 + userName: 'operator',
  59 + createTime: 'create time',
  60 + name: 'name',
  61 + sex: 'sex',
  62 + male: 'male',
  63 + female: 'female',
  64 + idCard: 'id card',
  65 + address: 'address',
  66 + add: 'add',
  67 + delete: 'delete',
  68 + modifyNew: 'modify(new)',
  69 + modifyOld: 'modify(old)'
  70 + },
  71 + roomDetailHis: {
  72 + operate: 'action',
  73 + userName: 'operator',
  74 + createTime: 'create time',
  75 + roomNum: 'room number',
  76 + layer: 'layer',
  77 + roomSubTypeName: 'type',
  78 + area: 'area',
  79 + roomRent: 'rent',
  80 + stateName: 'state',
  81 + add: 'add',
  82 + delete: 'delete',
  83 + modifyNew: 'modify(new)',
  84 + modifyOld: 'modify(old)'
  85 + },
  86 + carDetailHis: {
  87 + carNum: 'car number',
  88 + leaseType: 'lease type',
  89 + tempCar: 'temp car',
  90 + carTypeName: 'car type',
  91 + carColor: 'color',
  92 + owner: 'owner',
  93 + parkingSpace: 'parking space',
  94 + released: 'released',
  95 + validityPeriod: 'validity period',
  96 + operate: 'action',
  97 + userName: 'operator',
  98 + createTime: 'create time',
  99 + add: 'add',
  100 + delete: 'delete',
  101 + modifyNew: 'modify(new)',
  102 + modifyOld: 'modify(old)'
  103 + },
  104 + contractDetailChange: {
  105 + contractName: 'contract name',
  106 + contractCode: 'contract code',
  107 + contractTypeName: 'contract type',
  108 + partyA: 'party A',
  109 + partyB: 'party B',
  110 + planTypeName: 'change type',
  111 + changePersonName: 'change person',
  112 + createTime: 'create time',
  113 + remark: 'remark',
  114 + stateName: 'state',
  115 + operation: 'operation',
  116 + detail: 'detail'
  117 + }
  118 + },
  119 + zh: {
  120 + operateDataLog: {
  121 + search: {
  122 + title: '查询条件',
  123 + logStartTime: '请选择开始时间',
  124 + logEndTime: '请选择结束时间',
  125 + staffNameLike: '请输入操作人',
  126 + feeNameLike: '请输入费用项名称',
  127 + payerObjName: '请输入房屋名称,车牌号或者合同编号',
  128 + ownerNameLike: '请输入业主名称',
  129 + roomName: '请输入房屋名称 楼栋-单元-房屋',
  130 + carNumLike: '请输入车牌号',
  131 + contractCode: '请输入合同编号'
  132 + }
  133 + },
  134 + feeConfigDetailHis: {
  135 + feeTypeCdName: '费用类型',
  136 + feeName: '收费项目',
  137 + feeFlagName: '费用标识',
  138 + billTypeName: '催缴类型',
  139 + paymentCd: '付费类型',
  140 + prePayment: '预付费',
  141 + postPayment: '后付费',
  142 + paymentCycle: '缴费周期(单位:月)',
  143 + validityPeriod: '有效期',
  144 + squarePrice: '计费单价(单位:元)',
  145 + additionalAmount: '附加/固定费用(单位:元)',
  146 + deductFrom: '账户抵扣',
  147 + payOnline: '手机缴费',
  148 + scale: '进位方式',
  149 + round: '四舍五入',
  150 + roundUp: '向上进位',
  151 + roundDown: '向下进位',
  152 + decimalPlace: '保留小数',
  153 + operate: '动作',
  154 + userName: '操作人',
  155 + createTime: '操作时间',
  156 + add: '添加',
  157 + delete: '删除',
  158 + modifyNew: '修改(新)',
  159 + modifyOld: '修改(旧)'
  160 + },
  161 + feeDetailHis: {
  162 + feeName: '费用项',
  163 + startTime: '建账时间',
  164 + endTime: '计费起始时间',
  165 + operate: '动作',
  166 + userName: '操作人',
  167 + createTime: '操作时间',
  168 + add: '添加',
  169 + delete: '删除',
  170 + modifyNew: '修改(新)',
  171 + modifyOld: '修改(旧)'
  172 + },
  173 + ownerDetailHis: {
  174 + operate: '动作',
  175 + userName: '操作人',
  176 + createTime: '操作时间',
  177 + name: '姓名',
  178 + sex: '性别',
  179 + male: '男',
  180 + female: '女',
  181 + idCard: '身份证',
  182 + address: '家庭住址',
  183 + add: '添加',
  184 + delete: '删除',
  185 + modifyNew: '修改(新)',
  186 + modifyOld: '修改(旧)'
  187 + },
  188 + roomDetailHis: {
  189 + operate: '动作',
  190 + userName: '操作人',
  191 + createTime: '操作时间',
  192 + roomNum: '房号',
  193 + layer: '楼层',
  194 + roomSubTypeName: '类型',
  195 + area: '建筑/室内面积',
  196 + roomRent: '租金',
  197 + stateName: '房屋状态',
  198 + add: '添加',
  199 + delete: '删除',
  200 + modifyNew: '修改(新)',
  201 + modifyOld: '修改(旧)'
  202 + },
  203 + carDetailHis: {
  204 + carNum: '车牌号',
  205 + leaseType: '车牌类型',
  206 + tempCar: '临时车',
  207 + carTypeName: '车辆类型',
  208 + carColor: '颜色',
  209 + owner: '业主',
  210 + parkingSpace: '车位',
  211 + released: '车位已释放',
  212 + validityPeriod: '有效期',
  213 + operate: '动作',
  214 + userName: '操作人',
  215 + createTime: '操作时间',
  216 + add: '添加',
  217 + delete: '删除',
  218 + modifyNew: '修改(新)',
  219 + modifyOld: '修改(旧)'
  220 + },
  221 + contractDetailChange: {
  222 + contractName: '合同名称',
  223 + contractCode: '合同编号',
  224 + contractTypeName: '合同类型',
  225 + partyA: '甲方',
  226 + partyB: '乙方',
  227 + planTypeName: '变更类型',
  228 + changePersonName: '变更人',
  229 + createTime: '申请时间',
  230 + remark: '说明',
  231 + stateName: '状态',
  232 + operation: '操作',
  233 + detail: '明细'
  234 + }
  235 + },
  236 +}
0 237 \ No newline at end of file
... ...
src/views/system/operateDataLogList.vue 0 → 100644
  1 +<template>
  2 + <div class="operate-data-log-container">
  3 + <el-card class="search-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('operateDataLog.search.title') }}</span>
  6 + <el-button
  7 + type="text"
  8 + style="float: right; padding: 3px 0"
  9 + @click="_moreCondition">
  10 + {{ operateDataLogInfo.moreCondition ? $t('common.hide') : $t('common.more') }}
  11 + </el-button>
  12 + </div>
  13 +
  14 + <el-row :gutter="20">
  15 + <el-col :span="6">
  16 + <el-date-picker
  17 + v-model="operateDataLogInfo.conditions.logStartTime"
  18 + type="datetime"
  19 + :placeholder="$t('operateDataLog.search.logStartTime')"
  20 + style="width: 100%"
  21 + value-format="yyyy-MM-dd HH:mm:ss">
  22 + </el-date-picker>
  23 + </el-col>
  24 +
  25 + <el-col :span="6">
  26 + <el-date-picker
  27 + v-model="operateDataLogInfo.conditions.logEndTime"
  28 + type="datetime"
  29 + :placeholder="$t('operateDataLog.search.logEndTime')"
  30 + style="width: 100%"
  31 + value-format="yyyy-MM-dd HH:mm:ss"
  32 + :picker-options="endDateOptions">
  33 + </el-date-picker>
  34 + </el-col>
  35 +
  36 + <el-col :span="6">
  37 + <el-input
  38 + v-model="operateDataLogInfo.conditions.staffNameLike"
  39 + :placeholder="$t('operateDataLog.search.staffNameLike')">
  40 + </el-input>
  41 + </el-col>
  42 +
  43 + <el-col :span="6">
  44 + <el-button type="primary" @click="_queryDataMethod">
  45 + <i class="el-icon-search"></i>
  46 + {{ $t('common.search') }}
  47 + </el-button>
  48 + <el-button @click="_resetDataMethod">
  49 + <i class="el-icon-refresh"></i>
  50 + {{ $t('common.reset') }}
  51 + </el-button>
  52 + </el-col>
  53 + </el-row>
  54 +
  55 + <el-row :gutter="20" v-show="operateDataLogInfo.moreCondition">
  56 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'feeConfigDetailHis' || operateDataLogInfo._currentTab === 'feeDetailHis'">
  57 + <el-input
  58 + v-model="operateDataLogInfo.conditions.feeNameLike"
  59 + :placeholder="$t('operateDataLog.search.feeNameLike')">
  60 + </el-input>
  61 + </el-col>
  62 +
  63 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'feeDetailHis'">
  64 + <el-input
  65 + v-model="operateDataLogInfo.conditions.payerObjName"
  66 + :placeholder="$t('operateDataLog.search.payerObjName')">
  67 + </el-input>
  68 + </el-col>
  69 +
  70 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'ownerDetailHis'">
  71 + <el-input
  72 + v-model="operateDataLogInfo.conditions.ownerNameLike"
  73 + :placeholder="$t('operateDataLog.search.ownerNameLike')">
  74 + </el-input>
  75 + </el-col>
  76 +
  77 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'roomDetailHis'">
  78 + <el-input
  79 + v-model="operateDataLogInfo.conditions.roomName"
  80 + :placeholder="$t('operateDataLog.search.roomName')">
  81 + </el-input>
  82 + </el-col>
  83 +
  84 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'carDetailHis'">
  85 + <el-input
  86 + v-model="operateDataLogInfo.conditions.carNumLike"
  87 + :placeholder="$t('operateDataLog.search.carNumLike')">
  88 + </el-input>
  89 + </el-col>
  90 +
  91 + <el-col :span="6" v-if="operateDataLogInfo._currentTab === 'contractDetailChange'">
  92 + <el-input
  93 + v-model="operateDataLogInfo.conditions.contractCode"
  94 + :placeholder="$t('operateDataLog.search.contractCode')">
  95 + </el-input>
  96 + </el-col>
  97 + </el-row>
  98 + </el-card>
  99 +
  100 + <el-card class="table-card">
  101 + <el-tabs v-model="operateDataLogInfo._currentTab" @tab-click="changeTab">
  102 + <el-tab-pane label="费用项" name="feeConfigDetailHis"></el-tab-pane>
  103 + <el-tab-pane label="费用" name="feeDetailHis"></el-tab-pane>
  104 + <el-tab-pane label="业主" name="ownerDetailHis"></el-tab-pane>
  105 + <el-tab-pane label="房屋" name="roomDetailHis"></el-tab-pane>
  106 + <el-tab-pane label="车辆" name="carDetailHis"></el-tab-pane>
  107 + <el-tab-pane label="合同" name="contractDetailChange"></el-tab-pane>
  108 + </el-tabs>
  109 +
  110 + <component :is="currentComponent" ref="childComponent"></component>
  111 + </el-card>
  112 + </div>
  113 +</template>
  114 +
  115 +<script>
  116 +import { getCommunityId } from '@/api/community/communityApi'
  117 +import FeeConfigDetailHis from '@/components/system/feeConfigDetailHis'
  118 +import FeeDetailHis from '@/components/system/feeDetailHis'
  119 +import OwnerDetailHis from '@/components/system/ownerDetailHis'
  120 +import RoomDetailHis from '@/components/system/roomDetailHis'
  121 +import CarDetailHis from '@/components/system/carDetailHis'
  122 +import ContractDetailChange from '@/components/system/contractDetailChange'
  123 +
  124 +export default {
  125 + name: 'OperateDataLogList',
  126 + components: {
  127 + FeeConfigDetailHis,
  128 + FeeDetailHis,
  129 + OwnerDetailHis,
  130 + RoomDetailHis,
  131 + CarDetailHis,
  132 + ContractDetailChange
  133 + },
  134 + data() {
  135 + return {
  136 + communityId: '',
  137 + operateDataLogInfo: {
  138 + _currentTab: 'feeConfigDetailHis',
  139 + moreCondition: false,
  140 + conditions: {
  141 + logStartTime: '',
  142 + logEndTime: '',
  143 + staffNameLike: '',
  144 + feeNameLike: '',
  145 + payerObjName: '',
  146 + ownerNameLike: '',
  147 + roomName: '',
  148 + carNumLike: '',
  149 + contractCode: ''
  150 + }
  151 + },
  152 + endDateOptions: {
  153 + disabledDate: (time) => {
  154 + if (this.operateDataLogInfo.conditions.logStartTime) {
  155 + return time.getTime() <= new Date(this.operateDataLogInfo.conditions.logStartTime).getTime()
  156 + }
  157 + return false
  158 + }
  159 + }
  160 + }
  161 + },
  162 + computed: {
  163 + currentComponent() {
  164 + return this.operateDataLogInfo._currentTab
  165 + }
  166 + },
  167 + created() {
  168 + this.communityId = getCommunityId()
  169 + },
  170 + methods: {
  171 + changeTab(tab) {
  172 + this.operateDataLogInfo._currentTab = tab.name || tab
  173 + this.$nextTick(() => {
  174 + if (this.$refs.childComponent) {
  175 + this.$refs.childComponent.open(this.operateDataLogInfo.conditions)
  176 + }
  177 + })
  178 + },
  179 + _queryDataMethod() {
  180 + this.changeTab(this.operateDataLogInfo._currentTab)
  181 + },
  182 + _resetDataMethod() {
  183 + this.operateDataLogInfo.conditions = {
  184 + logStartTime: '',
  185 + logEndTime: '',
  186 + staffNameLike: '',
  187 + feeNameLike: '',
  188 + payerObjName: '',
  189 + ownerNameLike: '',
  190 + roomName: '',
  191 + carNumLike: '',
  192 + contractCode: ''
  193 + }
  194 + this.changeTab(this.operateDataLogInfo._currentTab)
  195 + },
  196 + _moreCondition() {
  197 + this.operateDataLogInfo.moreCondition = !this.operateDataLogInfo.moreCondition
  198 + }
  199 + }
  200 +}
  201 +</script>
  202 +
  203 +<style lang="scss" scoped>
  204 +.operate-data-log-container {
  205 + padding: 20px;
  206 +
  207 + .search-card {
  208 + margin-bottom: 20px;
  209 + }
  210 +
  211 + .table-card {
  212 + margin-bottom: 20px;
  213 + }
  214 +
  215 + .el-row {
  216 + margin-bottom: 20px;
  217 +
  218 + &:last-child {
  219 + margin-bottom: 0;
  220 + }
  221 + }
  222 +
  223 + .el-col {
  224 + border-radius: 4px;
  225 + }
  226 +}
  227 +</style>
0 228 \ No newline at end of file
... ...
src/views/system/paymentPoolLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + paymentPool: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + paymentName: 'Payment Name',
  7 + paymentType: 'Payment Vendor',
  8 + state: 'Status',
  9 + allStatus: 'All Status',
  10 + enable: 'Enable',
  11 + disable: 'Disable'
  12 + },
  13 + list: {
  14 + title: 'Payment Configuration'
  15 + },
  16 + table: {
  17 + paymentName: 'Name',
  18 + paymentType: 'Payment Vendor',
  19 + payRange: 'Payment Range',
  20 + communityFee: 'Community Fee',
  21 + tempCarFee: 'Temporary Car Fee',
  22 + specifiedFee: 'Specified Fee',
  23 + state: 'Status',
  24 + createTime: 'Create Time',
  25 + remark: 'Instruction',
  26 + enable: 'Enable',
  27 + disable: 'Disable'
  28 + },
  29 + add: {
  30 + title: 'Add Payment',
  31 + paymentName: 'Name',
  32 + paymentNamePlaceholder: 'Required, please enter name',
  33 + paymentType: 'Payment Vendor',
  34 + paymentTypePlaceholder: 'Required, please select payment vendor',
  35 + certFile: 'Merchant Certificate(.p12)',
  36 + payRange: 'Payment Range',
  37 + payRangePlaceholder: 'Required, please select payment range',
  38 + communityFee: 'Community Fee',
  39 + tempCarFee: 'Temporary Car Fee',
  40 + specifiedFee: 'Specified Fee',
  41 + feeItems: 'Fee Items',
  42 + remark: 'Instruction',
  43 + remarkPlaceholder: 'Optional, please enter instruction',
  44 + success: 'Add payment successfully',
  45 + error: 'Failed to add payment'
  46 + },
  47 + edit: {
  48 + title: 'Edit Payment',
  49 + paymentName: 'Name',
  50 + paymentNamePlaceholder: 'Required, please enter name',
  51 + paymentType: 'Payment Vendor',
  52 + paymentTypePlaceholder: 'Required, please select payment vendor',
  53 + certFile: 'Merchant Certificate(.p12)',
  54 + currentCert: 'Current Certificate',
  55 + payRange: 'Payment Range',
  56 + payRangePlaceholder: 'Required, please select payment range',
  57 + communityFee: 'Community Fee',
  58 + tempCarFee: 'Temporary Car Fee',
  59 + specifiedFee: 'Specified Fee',
  60 + feeItems: 'Fee Items',
  61 + state: 'Status',
  62 + statePlaceholder: 'Required, please select status',
  63 + enable: 'Enable',
  64 + disable: 'Disable',
  65 + remark: 'Instruction',
  66 + remarkPlaceholder: 'Optional, please enter instruction',
  67 + success: 'Edit payment successfully',
  68 + error: 'Failed to edit payment'
  69 + },
  70 + delete: {
  71 + title: 'Delete Confirmation',
  72 + confirmText: 'Are you sure to delete this payment configuration?',
  73 + success: 'Delete payment successfully',
  74 + error: 'Failed to delete payment'
  75 + },
  76 + validate: {
  77 + paymentNameRequired: 'Name is required',
  78 + paymentNameMaxLength: 'Name cannot exceed 64 characters',
  79 + paymentTypeRequired: 'Payment vendor is required',
  80 + payTypeRequired: 'Payment range is required',
  81 + stateRequired: 'Status is required'
  82 + },
  83 + fetchError: 'Failed to fetch payment data'
  84 + },
  85 + uploadFile: {
  86 + sizeLimit: 'File size cannot exceed 20MB',
  87 + success: 'File uploaded successfully',
  88 + error: 'Failed to upload file'
  89 + }
  90 + },
  91 + zh: {
  92 + paymentPool: {
  93 + search: {
  94 + title: '查询条件',
  95 + paymentName: '支付名称',
  96 + paymentType: '支付厂家',
  97 + state: '状态',
  98 + allStatus: '全部状态',
  99 + enable: '启用',
  100 + disable: '停用'
  101 + },
  102 + list: {
  103 + title: '支付配置'
  104 + },
  105 + table: {
  106 + paymentName: '名称',
  107 + paymentType: '支付厂家',
  108 + payRange: '支付范围',
  109 + communityFee: '小区费用',
  110 + tempCarFee: '临时停车费',
  111 + specifiedFee: '指定费用项',
  112 + state: '状态',
  113 + createTime: '创建时间',
  114 + remark: '使用说明',
  115 + enable: '启用',
  116 + disable: '停用'
  117 + },
  118 + add: {
  119 + title: '添加支付',
  120 + paymentName: '名称',
  121 + paymentNamePlaceholder: '必填,请填写名称',
  122 + paymentType: '支付厂家',
  123 + paymentTypePlaceholder: '必填,请选择支付厂家',
  124 + certFile: '商户证书(.p12)',
  125 + payRange: '支付范围',
  126 + payRangePlaceholder: '必填,请选择支付范围',
  127 + communityFee: '小区费用',
  128 + tempCarFee: '临时停车费',
  129 + specifiedFee: '指定费用项',
  130 + feeItems: '费用项',
  131 + remark: '使用说明',
  132 + remarkPlaceholder: '选填,请填写使用说明',
  133 + success: '添加支付成功',
  134 + error: '添加支付失败'
  135 + },
  136 + edit: {
  137 + title: '修改支付',
  138 + paymentName: '名称',
  139 + paymentNamePlaceholder: '必填,请填写名称',
  140 + paymentType: '支付厂家',
  141 + paymentTypePlaceholder: '必填,请选择支付厂家',
  142 + certFile: '商户证书(.p12)',
  143 + currentCert: '当前证书',
  144 + payRange: '支付范围',
  145 + payRangePlaceholder: '必填,请选择支付范围',
  146 + communityFee: '小区费用',
  147 + tempCarFee: '临时停车费',
  148 + specifiedFee: '指定费用项',
  149 + feeItems: '费用项',
  150 + state: '状态',
  151 + statePlaceholder: '必填,请选择状态',
  152 + enable: '启用',
  153 + disable: '停用',
  154 + remark: '使用说明',
  155 + remarkPlaceholder: '选填,请填写使用说明',
  156 + success: '修改支付成功',
  157 + error: '修改支付失败'
  158 + },
  159 + delete: {
  160 + title: '删除确认',
  161 + confirmText: '确定删除该支付配置吗?',
  162 + success: '删除支付成功',
  163 + error: '删除支付失败'
  164 + },
  165 + validate: {
  166 + paymentNameRequired: '名称不能为空',
  167 + paymentNameMaxLength: '名称不能超过64个字符',
  168 + paymentTypeRequired: '支付厂家不能为空',
  169 + payTypeRequired: '支付范围不能为空',
  170 + stateRequired: '状态不能为空'
  171 + },
  172 + fetchError: '获取支付数据失败'
  173 + },
  174 + uploadFile: {
  175 + sizeLimit: '文件大小不能超过20MB',
  176 + success: '文件上传成功',
  177 + error: '文件上传失败'
  178 + }
  179 + }
  180 +}
0 181 \ No newline at end of file
... ...
src/views/system/paymentPoolList.vue 0 → 100644
  1 +<template>
  2 + <div class="payment-pool-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('paymentPool.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.paymentName" :placeholder="$t('paymentPool.search.paymentName')" clearable />
  11 + </el-col>
  12 + <el-col :span="6">
  13 + <el-select v-model="searchForm.paymentType" :placeholder="$t('paymentPool.search.paymentType')"
  14 + style="width:100%">
  15 + <el-option v-for="item in paymentTypes" :key="item.paymentType" :label="item.name"
  16 + :value="item.paymentType" />
  17 + </el-select>
  18 + </el-col>
  19 + <el-col :span="6">
  20 + <el-select v-model="searchForm.state" :placeholder="$t('paymentPool.search.state')" style="width:100%">
  21 + <el-option :label="$t('paymentPool.search.allStatus')" value="" />
  22 + <el-option :label="$t('paymentPool.search.enable')" value="Y" />
  23 + <el-option :label="$t('paymentPool.search.disable')" value="N" />
  24 + </el-select>
  25 + </el-col>
  26 + <el-col :span="6">
  27 + <el-button type="primary" @click="handleSearch">
  28 + {{ $t('common.search') }}
  29 + </el-button>
  30 + </el-col>
  31 + </el-row>
  32 + </el-card>
  33 +
  34 + <!-- 列表 -->
  35 + <el-card class="list-wrapper">
  36 + <div slot="header" class="flex justify-between">
  37 + <span>{{ $t('paymentPool.list.title') }}</span>
  38 + <el-button type="primary" size="small" style="float:right" @click="handleAdd">
  39 + {{ $t('common.add') }}
  40 + </el-button>
  41 + </div>
  42 +
  43 + <el-table v-loading="loading" :data="tableData" border style="width:100%">
  44 + <el-table-column prop="paymentName" :label="$t('paymentPool.table.paymentName')" align="center" />
  45 + <el-table-column prop="paymentTypeName" :label="$t('paymentPool.table.paymentType')" align="center" />
  46 + <el-table-column :label="$t('paymentPool.table.payRange')" align="center">
  47 + <template slot-scope="scope">
  48 + <div v-if="scope.row.payType === '1001'">
  49 + {{ $t('paymentPool.table.communityFee') }}
  50 + </div>
  51 + <div v-else-if="scope.row.payType === '2002'">
  52 + {{ $t('paymentPool.table.tempCarFee') }}
  53 + </div>
  54 + <div v-else>
  55 + {{ $t('paymentPool.table.specifiedFee') }}
  56 + </div>
  57 + </template>
  58 + </el-table-column>
  59 + <el-table-column :label="$t('paymentPool.table.state')" align="center">
  60 + <template slot-scope="scope">
  61 + <el-tag :type="scope.row.state === 'Y' ? 'success' : 'danger'">
  62 + {{ scope.row.state === 'Y' ? $t('paymentPool.table.enable') : $t('paymentPool.table.disable') }}
  63 + </el-tag>
  64 + </template>
  65 + </el-table-column>
  66 + <el-table-column prop="createTime" :label="$t('paymentPool.table.createTime')" align="center" />
  67 + <el-table-column prop="remark" :label="$t('paymentPool.table.remark')" align="center" />
  68 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  69 + <template slot-scope="scope">
  70 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  71 + {{ $t('common.edit') }}
  72 + </el-button>
  73 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  74 + {{ $t('common.delete') }}
  75 + </el-button>
  76 + </template>
  77 + </el-table-column>
  78 + </el-table>
  79 +
  80 + <el-pagination :current-page="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  81 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  82 + @current-change="handleCurrentChange" />
  83 + </el-card>
  84 +
  85 + <!-- 组件 -->
  86 + <add-payment-pool ref="addPaymentPool" @success="handleSuccess" />
  87 + <edit-payment-pool ref="editPaymentPool" @success="handleSuccess" />
  88 + <delete-payment-pool ref="deletePaymentPool" @success="handleSuccess" />
  89 + </div>
  90 +</template>
  91 +
  92 +<script>
  93 +import { listPaymentPool, listPaymentAdapt } from '@/api/system/paymentPoolApi'
  94 +import AddPaymentPool from '@/components/system/addPaymentPool'
  95 +import EditPaymentPool from '@/components/system/editPaymentPool'
  96 +import DeletePaymentPool from '@/components/system/deletePaymentPool'
  97 +import { getCommunityId } from '@/api/community/communityApi'
  98 +
  99 +export default {
  100 + name: 'PaymentPoolList',
  101 + components: {
  102 + AddPaymentPool,
  103 + EditPaymentPool,
  104 + DeletePaymentPool
  105 + },
  106 + data() {
  107 + return {
  108 + loading: false,
  109 + searchForm: {
  110 + paymentName: '',
  111 + paymentType: '',
  112 + state: ''
  113 + },
  114 + tableData: [],
  115 + paymentTypes: [],
  116 + page: {
  117 + current: 1,
  118 + size: 10,
  119 + total: 0
  120 + },
  121 + communityId: ''
  122 + }
  123 + },
  124 + created() {
  125 + this.communityId = getCommunityId()
  126 + this.getList()
  127 + this.getPaymentTypes()
  128 + },
  129 + methods: {
  130 + async getList() {
  131 + try {
  132 + this.loading = true
  133 + const params = {
  134 + page: this.page.current,
  135 + row: this.page.size,
  136 + communityId: this.communityId,
  137 + ...this.searchForm
  138 + }
  139 + const { data, total } = await listPaymentPool(params)
  140 + this.tableData = data
  141 + this.page.total = total
  142 + } catch (error) {
  143 + this.$message.error(this.$t('paymentPool.fetchError'))
  144 + } finally {
  145 + this.loading = false
  146 + }
  147 + },
  148 + async getPaymentTypes() {
  149 + try {
  150 + const { data } = await listPaymentAdapt({
  151 + page: 1,
  152 + row: 100,
  153 + })
  154 + this.paymentTypes = data
  155 + } catch (error) {
  156 + console.error('获取支付类型失败:', error)
  157 + }
  158 + },
  159 + handleSearch() {
  160 + this.page.current = 1
  161 + this.getList()
  162 + },
  163 + handleAdd() {
  164 + this.$refs.addPaymentPool.open()
  165 + },
  166 + handleEdit(row) {
  167 + this.$refs.editPaymentPool.open(row)
  168 + },
  169 + handleDelete(row) {
  170 + this.$refs.deletePaymentPool.open(row)
  171 + },
  172 + handleSuccess() {
  173 + this.getList()
  174 + },
  175 + handleSizeChange(val) {
  176 + this.page.size = val
  177 + this.getList()
  178 + },
  179 + handleCurrentChange(val) {
  180 + this.page.current = val
  181 + this.getList()
  182 + }
  183 + }
  184 +}
  185 +</script>
  186 +
  187 +<style lang="scss" scoped>
  188 +.payment-pool-container {
  189 + padding: 20px;
  190 +
  191 + .search-wrapper {
  192 + margin-bottom: 20px;
  193 +
  194 + .el-row {
  195 + margin-bottom: -20px;
  196 + }
  197 +
  198 + .el-col {
  199 + margin-bottom: 20px;
  200 + }
  201 + }
  202 +
  203 + .list-wrapper {
  204 + .el-pagination {
  205 + margin-top: 20px;
  206 + text-align: right;
  207 + }
  208 + }
  209 +}
  210 +</style>
0 211 \ No newline at end of file
... ...
src/views/system/publicWeChatManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + publicWeChatManage: {
  4 + title: 'My Public WeChat',
  5 + addTitle: 'Add Public WeChat',
  6 + editTitle: 'Edit Public WeChat',
  7 + deleteTitle: 'Confirm Operation',
  8 + deleteConfirm: 'Are you sure to delete this public WeChat?',
  9 + table: {
  10 + name: 'Name',
  11 + appSecret: 'App Secret',
  12 + remarks: 'Description',
  13 + operation: 'Operation'
  14 + },
  15 + form: {
  16 + name: 'Name',
  17 + appSecret: 'App Secret',
  18 + remarks: 'Description'
  19 + },
  20 + placeholder: {
  21 + name: 'Required, please fill in the name',
  22 + appId: 'Required, please fill in APPID',
  23 + appSecret: 'Required, please fill in App Secret',
  24 + remarks: 'Optional, please fill in description'
  25 + },
  26 + validate: {
  27 + nameRequired: 'Name is required',
  28 + appIdRequired: 'APPID is required',
  29 + appSecretRequired: 'App Secret is required'
  30 + },
  31 + message: {
  32 + addSuccess: 'Added successfully',
  33 + editSuccess: 'Modified successfully',
  34 + deleteSuccess: 'Deleted successfully',
  35 + fetchError: 'Failed to fetch data'
  36 + }
  37 + }
  38 + },
  39 + zh: {
  40 + publicWeChatManage: {
  41 + title: '我的公众号',
  42 + addTitle: '添加公众号',
  43 + editTitle: '修改公众号',
  44 + deleteTitle: '请确认您的操作',
  45 + deleteConfirm: '确定删除该公众号吗?',
  46 + table: {
  47 + name: '名称',
  48 + appSecret: '应用密钥',
  49 + remarks: '描述',
  50 + operation: '操作'
  51 + },
  52 + form: {
  53 + name: '名称',
  54 + appSecret: '应用密钥',
  55 + remarks: '描述'
  56 + },
  57 + placeholder: {
  58 + name: '必填,请填写名称',
  59 + appId: '必填,请填写APPID',
  60 + appSecret: '必填,请填写应用密钥',
  61 + remarks: '选填,请填写描述信息'
  62 + },
  63 + validate: {
  64 + nameRequired: '名称不能为空',
  65 + appIdRequired: 'APPID不能为空',
  66 + appSecretRequired: '应用密钥不能为空'
  67 + },
  68 + message: {
  69 + addSuccess: '添加成功',
  70 + editSuccess: '修改成功',
  71 + deleteSuccess: '删除成功',
  72 + fetchError: '获取数据失败'
  73 + }
  74 + }
  75 + }
  76 +}
0 77 \ No newline at end of file
... ...
src/views/system/publicWeChatManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="public-wechat-manage-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between">
  5 + <span>{{ $t('publicWeChatManage.title') }}</span>
  6 + <div class="header-tools">
  7 + <el-button v-if="smallWeChatManageInfo.smallWeChats.length === 0" type="primary" size="small"
  8 + @click="_openAddSmallWeChatModal(1100)">
  9 + <i class="el-icon-plus"></i>{{ $t('common.add') }}
  10 + </el-button>
  11 + <el-button type="primary" size="small" @click="showMarkdown('/pages/property/publicWeChatManage')">
  12 + <i class="el-icon-document"></i>{{ $t('common.document') }}
  13 + </el-button>
  14 + </div>
  15 + </div>
  16 +
  17 + <el-table :data="smallWeChatManageInfo.smallWeChats" border style="width: 100%">
  18 + <el-table-column prop="name" :label="$t('publicWeChatManage.table.name')" align="center">
  19 + </el-table-column>
  20 + <el-table-column prop="appId" label="APPID" align="center">
  21 + </el-table-column>
  22 + <el-table-column :label="$t('publicWeChatManage.table.appSecret')" align="center">
  23 + <template >
  24 + ********
  25 + </template>
  26 + </el-table-column>
  27 + <el-table-column prop="remarks" :label="$t('publicWeChatManage.table.remarks')" align="center">
  28 + </el-table-column>
  29 + <el-table-column :label="$t('common.operation')" align="center" width="150">
  30 + <template slot-scope="scope">
  31 + <el-button size="mini" @click="_openEditSmallWeChatModel(scope.row)">
  32 + {{ $t('common.edit') }}
  33 + </el-button>
  34 + </template>
  35 + </el-table-column>
  36 + </el-table>
  37 + </el-card>
  38 +
  39 + <add-small-wechat ref="addSmallWeChat" @success="handleSuccess"></add-small-wechat>
  40 + <edit-small-wechat ref="editSmallWeChat" @success="handleSuccess"></edit-small-wechat>
  41 + <delete-small-wechat ref="deleteSmallWeChat" @success="handleSuccess"></delete-small-wechat>
  42 + </div>
  43 +</template>
  44 +
  45 +<script>
  46 +import { getCommunityId } from '@/api/community/communityApi'
  47 +import { listSmallWeChats } from '@/api/system/publicWeChatManageApi'
  48 +import AddSmallWechat from '@/components/system/addSmallWechat'
  49 +import EditSmallWechat from '@/components/system/editSmallWechat'
  50 +import DeleteSmallWechat from '@/components/system/deleteSmallWechat'
  51 +
  52 +export default {
  53 + name: 'PublicWeChatManageList',
  54 + components: {
  55 + AddSmallWechat,
  56 + EditSmallWechat,
  57 + DeleteSmallWechat
  58 + },
  59 + data() {
  60 + return {
  61 + smallWeChatManageInfo: {
  62 + smallWeChats: [],
  63 + total: 0,
  64 + records: 1,
  65 + conditions: {
  66 + name: '',
  67 + appId: '',
  68 + weChatType: '1100',
  69 + communityId: ''
  70 + }
  71 + }
  72 + }
  73 + },
  74 + created() {
  75 + this.smallWeChatManageInfo.conditions.communityId = getCommunityId()
  76 + this._listSmallWeChats(1, 10)
  77 + },
  78 + methods: {
  79 + async _listSmallWeChats(page, rows) {
  80 + try {
  81 + this.smallWeChatManageInfo.conditions.page = page
  82 + this.smallWeChatManageInfo.conditions.row = rows
  83 +
  84 + const { data, total } = await listSmallWeChats(this.smallWeChatManageInfo.conditions)
  85 + this.smallWeChatManageInfo.smallWeChats = data
  86 + this.smallWeChatManageInfo.total = total
  87 + } catch (error) {
  88 + this.$message.error(this.$t('publicWeChatManage.fetchError'))
  89 + }
  90 + },
  91 + _openAddSmallWeChatModal(type) {
  92 + this.$refs.addSmallWeChat.open(type)
  93 + },
  94 + _openEditSmallWeChatModel(smallWeChat) {
  95 + this.$refs.editSmallWeChat.open(smallWeChat)
  96 + },
  97 + handleSuccess() {
  98 + this._listSmallWeChats(1, 10)
  99 + },
  100 + showMarkdown(path) {
  101 + // 显示markdown文档的方法
  102 + console.log(path)
  103 + }
  104 + }
  105 +}
  106 +</script>
  107 +
  108 +<style lang="scss" scoped>
  109 +.public-wechat-manage-container {
  110 + padding: 20px;
  111 +
  112 + .header-tools {
  113 + float: right;
  114 + margin-right: 10px;
  115 + }
  116 +
  117 + .el-card {
  118 + margin-bottom: 20px;
  119 + }
  120 +}
  121 +</style>
0 122 \ No newline at end of file
... ...
src/views/system/smallWeChatManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + smallWeChatManage: {
  4 + title: 'My Mini Programs',
  5 + name: 'Name',
  6 + appSecret: 'App Secret',
  7 + remarks: 'Description',
  8 + addTitle: 'Add Mini Program',
  9 + editTitle: 'Edit Mini Program',
  10 + deleteTitle: 'Confirm Operation',
  11 + deleteConfirm: 'Are you sure to delete this mini program?',
  12 + namePlaceholder: 'Required, please enter name',
  13 + appIdPlaceholder: 'Required, please enter APPID',
  14 + appSecretPlaceholder: 'Required, please enter app secret',
  15 + remarksPlaceholder: 'Optional, please enter description',
  16 + nameRequired: 'Name is required',
  17 + nameMaxLength: 'Name cannot exceed 100 characters',
  18 + appIdRequired: 'APPID is required',
  19 + appIdMaxLength: 'APPID cannot exceed 100 characters',
  20 + appSecretRequired: 'App secret is required',
  21 + appSecretMaxLength: 'App secret cannot exceed 200 characters',
  22 + wechatIdRequired: 'WeChat ID is required',
  23 + addSuccess: 'Add mini program successfully',
  24 + addFailed: 'Failed to add mini program',
  25 + editSuccess: 'Edit mini program successfully',
  26 + editFailed: 'Failed to edit mini program',
  27 + deleteSuccess: 'Delete mini program successfully',
  28 + deleteFailed: 'Failed to delete mini program',
  29 + fetchError: 'Failed to fetch mini program list'
  30 + }
  31 + },
  32 + zh: {
  33 + smallWeChatManage: {
  34 + title: '我的小程序',
  35 + name: '名称',
  36 + appSecret: '应用密钥',
  37 + remarks: '描述',
  38 + addTitle: '添加小程序',
  39 + editTitle: '修改小程序',
  40 + deleteTitle: '请确认您的操作',
  41 + deleteConfirm: '确定删除小程序管理吗?',
  42 + namePlaceholder: '必填,请填写名称',
  43 + appIdPlaceholder: '必填,请填写APPID',
  44 + appSecretPlaceholder: '必填,请填写应用密钥',
  45 + remarksPlaceholder: '选填,请填写描述信息',
  46 + nameRequired: '名称不能为空',
  47 + nameMaxLength: '名称不能超过100位',
  48 + appIdRequired: 'APPID不能为空',
  49 + appIdMaxLength: 'APPID不能超过100位',
  50 + appSecretRequired: '应用密钥不能为空',
  51 + appSecretMaxLength: '应用密钥不能超过200个字符',
  52 + wechatIdRequired: '编码不能为空',
  53 + addSuccess: '添加成功',
  54 + addFailed: '添加失败',
  55 + editSuccess: '修改成功',
  56 + editFailed: '修改失败',
  57 + deleteSuccess: '删除成功',
  58 + deleteFailed: '删除失败',
  59 + fetchError: '获取小程序列表失败'
  60 + }
  61 + }
  62 +}
0 63 \ No newline at end of file
... ...
src/views/system/smallWeChatManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="small-wechat-manage-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span>{{ $t('smallWeChatManage.title') }}</span>
  6 + <el-button v-if="smallWeChatManageInfo.smallWeChats.length === 0" type="primary" size="small"
  7 + class="float-right" @click="_openAddSmallWeChatModal(1000)">
  8 + <i class="el-icon-plus"></i>
  9 + {{ $t('common.add') }}
  10 + </el-button>
  11 + </div>
  12 +
  13 + <el-table :data="smallWeChatManageInfo.smallWeChats" border style="width: 100%" v-loading="loading">
  14 + <el-table-column prop="name" :label="$t('smallWeChatManage.name')" align="center" />
  15 + <el-table-column prop="appId" label="APPID" align="center" />
  16 + <el-table-column :label="$t('smallWeChatManage.appSecret')" align="center">
  17 + <template>
  18 + ********
  19 + </template>
  20 + </el-table-column>
  21 + <el-table-column prop="remarks" :label="$t('smallWeChatManage.remarks')" align="center" />
  22 + <el-table-column :label="$t('common.operation')" align="center" width="150">
  23 + <template slot-scope="scope">
  24 + <el-button type="text" size="small" @click="_openEditSmallWeChatModel(scope.row)">
  25 + {{ $t('common.edit') }}
  26 + </el-button>
  27 + </template>
  28 + </el-table-column>
  29 + </el-table>
  30 +
  31 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.current"
  32 + :page-sizes="[10, 20, 30, 50]" :page-size="page.size" layout="total, sizes, prev, pager, next, jumper"
  33 + :total="page.total" class="pagination">
  34 + </el-pagination>
  35 + </el-card>
  36 +
  37 + <add-small-wechat ref="addSmallWeChat" @success="handleSuccess" />
  38 + <edit-small-wechat ref="editSmallWeChat" @success="handleSuccess" />
  39 + <delete-small-wechat ref="deleteSmallWeChat" @success="handleSuccess" />
  40 + </div>
  41 +</template>
  42 +
  43 +<script>
  44 +import { getCommunityId } from '@/api/community/communityApi'
  45 +import { listSmallWeChats } from '@/api/system/smallWeChatManageApi'
  46 +import AddSmallWechat from '@/components/system/addSmallWechat'
  47 +import EditSmallWechat from '@/components/system/editSmallWechat'
  48 +import DeleteSmallWechat from '@/components/system/deleteSmallWechat'
  49 +
  50 +export default {
  51 + name: 'SmallWeChatManageList',
  52 + components: {
  53 + AddSmallWechat,
  54 + EditSmallWechat,
  55 + DeleteSmallWechat
  56 + },
  57 + data() {
  58 + return {
  59 + loading: false,
  60 + smallWeChatManageInfo: {
  61 + smallWeChats: [],
  62 + conditions: {
  63 + name: '',
  64 + appId: '',
  65 + weChatType: '1000'
  66 + }
  67 + },
  68 + page: {
  69 + current: 1,
  70 + size: 10,
  71 + total: 0
  72 + },
  73 + communityId: ''
  74 + }
  75 + },
  76 + created() {
  77 + this.communityId = getCommunityId()
  78 + this._listSmallWeChats()
  79 + },
  80 + methods: {
  81 + async _listSmallWeChats() {
  82 + try {
  83 + this.loading = true
  84 + const params = {
  85 + page: this.page.current,
  86 + row: this.page.size,
  87 + communityId: this.communityId,
  88 + ...this.smallWeChatManageInfo.conditions
  89 + }
  90 + const { smallWeChats, total } = await listSmallWeChats(params)
  91 + this.smallWeChatManageInfo.smallWeChats = smallWeChats
  92 + this.page.total = total
  93 + } catch (error) {
  94 + this.$message.error(this.$t('smallWeChatManage.fetchError'))
  95 + } finally {
  96 + this.loading = false
  97 + }
  98 + },
  99 + _openAddSmallWeChatModal(type) {
  100 + this.$refs.addSmallWeChat.open(type)
  101 + },
  102 + _openEditSmallWeChatModel(smallWeChat) {
  103 + this.$refs.editSmallWeChat.open(smallWeChat)
  104 + },
  105 + _openDeleteSmallWeChatModel(smallWeChat) {
  106 + this.$refs.deleteSmallWeChat.open(smallWeChat)
  107 + },
  108 + handleSuccess() {
  109 + this._listSmallWeChats()
  110 + },
  111 + handleSizeChange(val) {
  112 + this.page.size = val
  113 + this._listSmallWeChats()
  114 + },
  115 + handleCurrentChange(val) {
  116 + this.page.current = val
  117 + this._listSmallWeChats()
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style lang="scss" scoped>
  124 +.small-wechat-manage-container {
  125 + padding: 20px;
  126 +
  127 + .box-card {
  128 + margin-bottom: 20px;
  129 + }
  130 +
  131 + .pagination {
  132 + margin-top: 20px;
  133 + text-align: right;
  134 + }
  135 +
  136 + .float-right {
  137 + float: right;
  138 + }
  139 +}
  140 +</style>
0 141 \ No newline at end of file
... ...