Commit 71def04c09c0ae1bd2a6cdaeceb09a9e7a1c9e78

Authored by wuxw
1 parent 95629508

优化优惠

Showing 46 changed files with 5228 additions and 42 deletions
src/api/report/commonReportApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取报表自定义列表
  5 +export function listReportCustom(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/reportCustom.listReportCustom',
  9 + method: 'get',
  10 + params
  11 + }).then(response => {
  12 + const res = response.data
  13 + resolve(res)
  14 + }).catch(error => {
  15 + reject(error)
  16 + })
  17 + })
  18 +}
  19 +
  20 +// 获取报表自定义组件关系
  21 +export function listReportCustomComponentRel(params) {
  22 + return new Promise((resolve, reject) => {
  23 + request({
  24 + url: '/reportCustomComponentRel.listReportCustomComponentRel',
  25 + method: 'get',
  26 + params
  27 + }).then(response => {
  28 + const res = response.data
  29 + resolve(res)
  30 + }).catch(error => {
  31 + reject(error)
  32 + })
  33 + })
  34 +}
  35 +
  36 +// 获取报表自定义组件条件
  37 +export function listReportCustomComponentCondition(params) {
  38 + return new Promise((resolve, reject) => {
  39 + request({
  40 + url: '/reportCustomComponentCondition.listReportCustomComponentCondition',
  41 + method: 'get',
  42 + params
  43 + }).then(response => {
  44 + const res = response.data
  45 + resolve(res)
  46 + }).catch(error => {
  47 + reject(error)
  48 + })
  49 + })
  50 +}
  51 +
  52 +// 获取报表自定义组件数据
  53 +export function listReportCustomComponentData(params) {
  54 + return new Promise((resolve, reject) => {
  55 + request({
  56 + url: '/reportCustomComponent.listReportCustomComponentData',
  57 + method: 'get',
  58 + params: {
  59 + ...params,
  60 + communityId: getCommunityId()
  61 + }
  62 + }).then(response => {
  63 + const res = response.data
  64 + resolve(res)
  65 + }).catch(error => {
  66 + reject(error)
  67 + })
  68 + })
  69 +}
  70 +
  71 +// 获取报表自定义组件页脚数据
  72 +export function listReportCustomComponentDataFooter(params) {
  73 + return new Promise((resolve, reject) => {
  74 + request({
  75 + url: '/reportCustomComponent.listReportCustomComponentDataFooter',
  76 + method: 'get',
  77 + params: {
  78 + ...params,
  79 + communityId: getCommunityId()
  80 + }
  81 + }).then(response => {
  82 + const res = response.data
  83 + resolve(res)
  84 + }).catch(error => {
  85 + reject(error)
  86 + })
  87 + })
  88 +}
  89 +
  90 +// 导出报表数据
  91 +export function exportData(params) {
  92 + return new Promise((resolve, reject) => {
  93 + request({
  94 + url: '/export.exportData',
  95 + method: 'get',
  96 + params: {
  97 + ...params,
  98 + communityId: getCommunityId()
  99 + }
  100 + }).then(response => {
  101 + const res = response.data
  102 + resolve(res)
  103 + }).catch(error => {
  104 + reject(error)
  105 + })
  106 + })
  107 +}
0 \ No newline at end of file 108 \ No newline at end of file
src/api/report/reportHuaningApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询未收情况表数据
  5 +export function queryHuaningOweFee(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/reportFeeMonthStatistics/queryHuaningOweFee',
  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 queryHuaningOweFeeDetail(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/reportFeeMonthStatistics/queryHuaningOweFeeDetail',
  28 + method: 'get',
  29 + params: {
  30 + ...params,
  31 + communityId: getCommunityId()
  32 + }
  33 + }).then(response => {
  34 + const res = response.data
  35 + resolve(res)
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 查询当月收费情况表数据
  43 +export function queryHuaningPayFee(params) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/reportFeeMonthStatistics/queryHuaningPayFee',
  47 + method: 'get',
  48 + params: {
  49 + ...params,
  50 + communityId: getCommunityId()
  51 + }
  52 + }).then(response => {
  53 + const res = response.data
  54 + resolve(res)
  55 + }).catch(error => {
  56 + reject(error)
  57 + })
  58 + })
  59 +}
  60 +
  61 +// 查询费用明细
  62 +export function queryFeeDetail(params) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/fee.queryFeeDetail',
  66 + method: 'get',
  67 + params: {
  68 + ...params,
  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 listFloors(params) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/floor.queryFloors',
  85 + method: 'get',
  86 + params: {
  87 + ...params,
  88 + communityId: getCommunityId()
  89 + }
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
0 \ No newline at end of file 98 \ No newline at end of file
src/api/report/reportPayFeeDepositApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询押金报表
  5 +export function queryPayFeeDeposit(params) {
  6 + return new Promise((resolve, reject) => {
  7 + params.communityId = getCommunityId()
  8 + request({
  9 + url: '/reportFeeMonthStatistics/queryPayFeeDeposit',
  10 + method: 'get',
  11 + params
  12 + }).then(response => {
  13 + const res = response.data
  14 + resolve(res)
  15 + }).catch(error => {
  16 + reject(error)
  17 + })
  18 + })
  19 +}
  20 +
  21 +// 导出押金报表数据
  22 +export function exportData(params) {
  23 + return new Promise((resolve, reject) => {
  24 + params.communityId = getCommunityId()
  25 + request({
  26 + url: '/export.exportData',
  27 + method: 'get',
  28 + params
  29 + }).then(response => {
  30 + const res = response.data
  31 + resolve(res)
  32 + }).catch(error => {
  33 + reject(error)
  34 + })
  35 + })
  36 +}
  37 +
  38 +// 查询单元列表
  39 +export function queryUnits(params) {
  40 + return new Promise((resolve, reject) => {
  41 + params.communityId = getCommunityId()
  42 + request({
  43 + url: '/unit.queryUnits',
  44 + method: 'get',
  45 + params
  46 + }).then(response => {
  47 + const res = response.data
  48 + resolve(res)
  49 + }).catch(error => {
  50 + reject(error)
  51 + })
  52 + })
  53 +}
0 \ No newline at end of file 54 \ No newline at end of file
src/api/scm/couponMarketApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取供应商列表
  4 +export function listSupplier(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/supplier.listSupplier',
  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 listSupplierCoupon(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/supplierCoupon.listSupplierCoupon',
  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 +}
0 \ No newline at end of file 34 \ No newline at end of file
src/api/scm/couponPropertyPoolManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取优惠券池列表
  4 +export function listCouponPropertyPool(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/couponProperty.listCouponPropertyPool',
  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 saveCouponPropertyPool(data) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/couponProperty.saveCouponPropertyPool',
  24 + method: 'post',
  25 + data
  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 updateCouponPropertyPool(data) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/couponProperty.updateCouponPropertyPool',
  40 + method: 'post',
  41 + data
  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 deleteCouponPropertyPool(data) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/couponProperty.deleteCouponPropertyPool',
  56 + method: 'post',
  57 + data
  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 giftCouponProperty(data) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/couponProperty.giftCouponProperty',
  72 + method: 'post',
  73 + data
  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 listCouponKey(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/couponKey.listCouponKey',
  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 +}
0 \ No newline at end of file 98 \ No newline at end of file
src/api/scm/couponRuleApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取优惠券规则列表
  5 +export function listCouponRule(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/couponRule.listCouponRule',
  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 saveCouponRule(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/couponRule.saveCouponRule',
  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 updateCouponRule(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/couponRule.updateCouponRule',
  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 deleteCouponRule(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/couponRule.deleteCouponRule',
  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 listCouponRuleCpps(params) {
  82 + return new Promise((resolve, reject) => {
  83 + request({
  84 + url: '/couponRule.listCouponRuleCpps',
  85 + method: 'get',
  86 + params: {
  87 + ...params,
  88 + communityId: getCommunityId()
  89 + }
  90 + }).then(response => {
  91 + const res = response.data
  92 + resolve(res)
  93 + }).catch(error => {
  94 + reject(error)
  95 + })
  96 + })
  97 +}
  98 +
  99 +// 添加优惠券规则关联的优惠券
  100 +export function saveCouponRuleCpps(data) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/couponRule.saveCouponRuleCpps',
  104 + method: 'post',
  105 + data: {
  106 + ...data,
  107 + communityId: getCommunityId()
  108 + }
  109 + }).then(response => {
  110 + const res = response.data
  111 + resolve(res)
  112 + }).catch(error => {
  113 + reject(error)
  114 + })
  115 + })
  116 +}
  117 +
  118 +// 更新优惠券规则关联的优惠券
  119 +export function updateCouponRuleCpps(data) {
  120 + return new Promise((resolve, reject) => {
  121 + request({
  122 + url: '/couponRule.updateCouponRuleCpps',
  123 + method: 'post',
  124 + data: {
  125 + ...data,
  126 + communityId: getCommunityId()
  127 + }
  128 + }).then(response => {
  129 + const res = response.data
  130 + resolve(res)
  131 + }).catch(error => {
  132 + reject(error)
  133 + })
  134 + })
  135 +}
  136 +
  137 +// 删除优惠券规则关联的优惠券
  138 +export function deleteCouponRuleCpps(data) {
  139 + return new Promise((resolve, reject) => {
  140 + request({
  141 + url: '/couponRule.deleteCouponRuleCpps',
  142 + method: 'post',
  143 + data: {
  144 + ...data,
  145 + communityId: getCommunityId()
  146 + }
  147 + }).then(response => {
  148 + const res = response.data
  149 + resolve(res)
  150 + }).catch(error => {
  151 + reject(error)
  152 + })
  153 + })
  154 +}
  155 +
  156 +// 获取优惠券规则关联的缴费赠送列表
  157 +export function listCouponRuleFee(params) {
  158 + return new Promise((resolve, reject) => {
  159 + request({
  160 + url: '/couponRule.listCouponRuleFee',
  161 + method: 'get',
  162 + params: {
  163 + ...params,
  164 + communityId: getCommunityId()
  165 + }
  166 + }).then(response => {
  167 + const res = response.data
  168 + resolve(res)
  169 + }).catch(error => {
  170 + reject(error)
  171 + })
  172 + })
  173 +}
  174 +
  175 +// 添加优惠券规则关联的缴费赠送
  176 +export function saveCouponRuleFee(data) {
  177 + return new Promise((resolve, reject) => {
  178 + request({
  179 + url: '/couponRule.saveCouponRuleFee',
  180 + method: 'post',
  181 + data: {
  182 + ...data,
  183 + communityId: getCommunityId()
  184 + }
  185 + }).then(response => {
  186 + const res = response.data
  187 + resolve(res)
  188 + }).catch(error => {
  189 + reject(error)
  190 + })
  191 + })
  192 +}
  193 +
  194 +// 删除优惠券规则关联的缴费赠送
  195 +export function deleteCouponRuleFee(data) {
  196 + return new Promise((resolve, reject) => {
  197 + request({
  198 + url: '/couponRule.deleteCouponRuleFee',
  199 + method: 'post',
  200 + data: {
  201 + ...data,
  202 + communityId: getCommunityId()
  203 + }
  204 + }).then(response => {
  205 + const res = response.data
  206 + resolve(res)
  207 + }).catch(error => {
  208 + reject(error)
  209 + })
  210 + })
  211 +}
  212 +
  213 +// 获取优惠券属性池列表
  214 +export function listCouponPropertyPool(params) {
  215 + return new Promise((resolve, reject) => {
  216 + request({
  217 + url: '/couponProperty.listCouponPropertyPool',
  218 + method: 'get',
  219 + params: {
  220 + ...params,
  221 + communityId: getCommunityId()
  222 + }
  223 + }).then(response => {
  224 + const res = response.data
  225 + resolve(res)
  226 + }).catch(error => {
  227 + reject(error)
  228 + })
  229 + })
  230 +}
  231 +
  232 +// 获取费用配置列表
  233 +export function listFeeConfigs(params) {
  234 + return new Promise((resolve, reject) => {
  235 + request({
  236 + url: '/feeConfig.listFeeConfigs',
  237 + method: 'get',
  238 + params: {
  239 + ...params,
  240 + communityId: getCommunityId()
  241 + }
  242 + }).then(response => {
  243 + const res = response.data
  244 + resolve(res)
  245 + }).catch(error => {
  246 + reject(error)
  247 + })
  248 + })
  249 +}
0 \ No newline at end of file 250 \ No newline at end of file
src/components/report/ReportHuaningOweFee.vue 0 → 100644
  1 +<template>
  2 + <div class="report-owe-fee-container">
  3 + <el-table :data="reportHuaningOweFeeInfo.fees" border style="width: 100%" class="margin-top">
  4 + <el-table-column prop="floorNum" :label="$t('reportHuaningOweFee.table.floorNum')" align="center" />
  5 + <el-table-column prop="oweAmount"
  6 + :label="$t('reportHuaningOweFee.table.totalOweAmount', { date: reportHuaningOweFeeInfo.dateStr })"
  7 + align="center" />
  8 + <el-table-column prop="curOweAmount" :label="_getCurYear() + $t('reportHuaningOweFee.table.oweAmount')"
  9 + align="center" />
  10 + <el-table-column prop="preOweAmount" :label="_getPreCurYear()" align="center" />
  11 + </el-table>
  12 +
  13 + <el-pagination :current-page.sync="pagination.current" :page-size="pagination.size" :total="pagination.total"
  14 + layout="total, prev, pager, next, jumper" @current-change="handlePageChange" class="margin-top" />
  15 + </div>
  16 +</template>
  17 +
  18 +<script>
  19 +import { queryHuaningOweFee } from '@/api/report/reportHuaningApi'
  20 +import { getCommunityId } from '@/api/community/communityApi'
  21 +import {getDateYYYYMMDD} from '@/utils/dateUtil'
  22 +
  23 +export default {
  24 + name: 'ReportHuaningOweFee',
  25 + data() {
  26 + return {
  27 + reportHuaningOweFeeInfo: {
  28 + fees: [],
  29 + dateStr:getDateYYYYMMDD(),
  30 + conditions: {}
  31 + },
  32 + pagination: {
  33 + current: 1,
  34 + size: 10,
  35 + total: 0
  36 + }
  37 + }
  38 + },
  39 + methods: {
  40 + async initData(conditions) {
  41 + this.reportHuaningOweFeeInfo.conditions = { ...conditions }
  42 + this.pagination.current = 1
  43 + await this._listReportHuaningOweFee()
  44 + },
  45 + async _listReportHuaningOweFee() {
  46 + try {
  47 + const params = {
  48 + ...this.reportHuaningOweFeeInfo.conditions,
  49 + page: this.pagination.current,
  50 + row: this.pagination.size,
  51 + communityId: getCommunityId(),
  52 + objType: '3333'
  53 + }
  54 +
  55 + const { data, total } = await queryHuaningOweFee(params)
  56 +
  57 + this.reportHuaningOweFeeInfo.fees = data
  58 + this.pagination.total = total
  59 + this.reportHuaningOweFeeInfo.listColumns = []
  60 +
  61 + if (data.length > 0 && data[0].reportFeeYearCollectionDetailDtos) {
  62 + data[0].reportFeeYearCollectionDetailDtos.forEach(item => {
  63 + this.reportHuaningOweFeeInfo.listColumns.push(`${item.collectionYear}${this.$t('common.year')}`)
  64 + })
  65 + }
  66 + } catch (error) {
  67 + console.error('获取欠费数据失败:', error)
  68 + }
  69 + },
  70 + handlePageChange(currentPage) {
  71 + this.pagination.current = currentPage
  72 + this._listReportHuaningOweFee()
  73 + },
  74 + _getCurYear() {
  75 + const date = new Date()
  76 + const year = date.getFullYear()
  77 + const month = date.getMonth() + 1
  78 + return `${year}${this.$t('common.year')}1-${month}${this.$t('common.month')}`
  79 + },
  80 + _getPreCurYear() {
  81 + const date = new Date()
  82 + const year = date.getFullYear()
  83 + return `${year}${this.$t('reportHuaningOweFee.table.preYearOweAmount')}`
  84 + },
  85 + _showFeeDetail(fee, item) {
  86 + this.$refs.viewFeeDetail.open({
  87 + roomName: fee.objName,
  88 + feeId: fee.feeId,
  89 + configId: fee.configId,
  90 + payerObjId: fee.objId,
  91 + curYear: item.collectionYear
  92 + })
  93 + }
  94 + }
  95 +}
  96 +</script>
  97 +
  98 +<style lang="scss" scoped>
  99 +.report-owe-fee-container {
  100 + .margin-top {
  101 + margin-top: 20px;
  102 + }
  103 +}
  104 +</style>
0 \ No newline at end of file 105 \ No newline at end of file
src/components/report/ReportHuaningOweFeeDetail.vue 0 → 100644
  1 +<template>
  2 + <div class="report-owe-fee-detail-container">
  3 + <el-table :data="reportHuaningOweFeeDetailInfo.fees" border style="width: 100%" class="margin-top">
  4 + <el-table-column prop="roomName" :label="$t('reportHuaningOweFeeDetail.table.roomNum')" align="center" />
  5 + <el-table-column prop="builtUpArea" :label="$t('reportHuaningOweFeeDetail.table.area')" align="center" />
  6 + <el-table-column prop="feeName" :label="$t('reportHuaningOweFeeDetail.table.fee')" align="center" />
  7 + <el-table-column prop="startTime" :label="$t('reportHuaningOweFeeDetail.table.startTime')" align="center" />
  8 + <el-table-column prop="endTime" :label="$t('reportHuaningOweFeeDetail.table.endTime')" align="center" />
  9 + <el-table-column prop="oweAmount" :label="$t('reportHuaningOweFeeDetail.table.totalOweAmount')" align="center" />
  10 + <el-table-column prop="curOweAmount"
  11 + :label="`${reportHuaningOweFeeDetailInfo.conditions.year}${$t('common.year')}1-${reportHuaningOweFeeDetailInfo.conditions.month}${$t('common.month')}${$t('reportHuaningOweFeeDetail.table.oweAmount')}`"
  12 + align="center" />
  13 + <el-table-column prop="preOweAmount"
  14 + :label="`${reportHuaningOweFeeDetailInfo.conditions.year}${$t('common.year')}${$t('reportHuaningOweFeeDetail.table.preYearOweAmount')}`"
  15 + align="center" />
  16 + </el-table>
  17 +
  18 + <el-pagination :current-page.sync="pagination.current" :page-size="pagination.size" :total="pagination.total"
  19 + layout="total, prev, pager, next, jumper" @current-change="handlePageChange" class="margin-top" />
  20 + </div>
  21 +</template>
  22 +
  23 +<script>
  24 +import { queryHuaningOweFeeDetail } from '@/api/report/reportHuaningApi'
  25 +import { getCommunityId } from '@/api/community/communityApi'
  26 +import {getDateYYYYMMDD} from '@/utils/dateUtil'
  27 +
  28 +export default {
  29 + name: 'ReportHuaningOweFeeDetail',
  30 + data() {
  31 + return {
  32 + reportHuaningOweFeeDetailInfo: {
  33 + fees: [],
  34 + conditions: {
  35 + year: new Date().getFullYear(),
  36 + month: new Date().getMonth() + 1
  37 + },
  38 + dateStr: getDateYYYYMMDD()
  39 + },
  40 + pagination: {
  41 + current: 1,
  42 + size: 10,
  43 + total: 0
  44 + }
  45 + }
  46 + },
  47 + methods: {
  48 + async initData(conditions) {
  49 + this.reportHuaningOweFeeDetailInfo.conditions = { ...conditions }
  50 + this.pagination.current = 1
  51 + await this._listReportHuaningOweFeeDetail()
  52 + },
  53 + async _listReportHuaningOweFeeDetail() {
  54 + try {
  55 + const params = {
  56 + ...this.reportHuaningOweFeeDetailInfo.conditions,
  57 + page: this.pagination.current,
  58 + row: this.pagination.size,
  59 + communityId: getCommunityId()
  60 + }
  61 +
  62 + const { data, total } = await queryHuaningOweFeeDetail(params)
  63 +
  64 + this.reportHuaningOweFeeDetailInfo.fees = data
  65 + this.pagination.total = total
  66 + } catch (error) {
  67 + console.error('获取欠费明细数据失败:', error)
  68 + }
  69 + },
  70 + handlePageChange(currentPage) {
  71 + this.pagination.current = currentPage
  72 + this._listReportHuaningOweFeeDetail()
  73 + }
  74 + }
  75 +}
  76 +</script>
  77 +
  78 +<style lang="scss" scoped>
  79 +.report-owe-fee-detail-container {
  80 + .margin-top {
  81 + margin-top: 20px;
  82 + }
  83 +}
  84 +</style>
0 \ No newline at end of file 85 \ No newline at end of file
src/components/report/ReportHuaningPayFee.vue 0 → 100644
  1 +<template>
  2 + <div class="report-pay-fee-container">
  3 + <el-table :data="reportHuaningPayFeeInfo.fees" border style="width: 100%" class="margin-top">
  4 + <el-table-column prop="floorNum" :label="$t('reportHuaningPayFee.table.floorNum')" align="center" />
  5 + <el-table-column prop="receivableAmount" :label="$t('reportHuaningPayFee.table.monthlyReceivable')"
  6 + align="center" />
  7 + <el-table-column prop="receivedAmount"
  8 + :label="`${reportHuaningPayFeeInfo.conditions.month}${$t('reportHuaningPayFee.table.monthReceived')}`"
  9 + align="center" />
  10 + <el-table-column prop="receivedAmount1" :label="`${reportHuaningPayFeeInfo.conditions.month}${$t('reportHuaningPayFee.table.monthReceivedPart1', {
  11 + year: reportHuaningPayFeeInfo.conditions.year,
  12 + month: reportHuaningPayFeeInfo.conditions.month - 1
  13 + })}`" align="center" />
  14 + <el-table-column prop="receivedAmount2" :label="`${reportHuaningPayFeeInfo.conditions.month}${$t('reportHuaningPayFee.table.monthReceivedPart2', {
  15 + year: reportHuaningPayFeeInfo.conditions.year,
  16 + month: reportHuaningPayFeeInfo.conditions.month
  17 + })}`" align="center" />
  18 + <el-table-column prop="receivedAmount3" :label="`${reportHuaningPayFeeInfo.conditions.month}${$t('reportHuaningPayFee.table.monthReceivedPart3', {
  19 + nextMonth: _getNextMonth()
  20 + })}`" align="center" />
  21 + <el-table-column prop="receivedAmount4" :label="`${reportHuaningPayFeeInfo.conditions.month}${$t('reportHuaningPayFee.table.monthReceivedPart4', {
  22 + year: reportHuaningPayFeeInfo.conditions.year
  23 + })}`" align="center" />
  24 + </el-table>
  25 +
  26 + <el-pagination :current-page.sync="pagination.current" :page-size="pagination.size" :total="pagination.total"
  27 + layout="total, prev, pager, next, jumper" @current-change="handlePageChange" class="margin-top" />
  28 + </div>
  29 +</template>
  30 +
  31 +<script>
  32 +import { queryHuaningPayFee } from '@/api/report/reportHuaningApi'
  33 +import { getCommunityId } from '@/api/community/communityApi'
  34 +import {getDateYYYYMMDD} from '@/utils/dateUtil'
  35 +
  36 +export default {
  37 + name: 'ReportHuaningPayFee',
  38 + data() {
  39 + return {
  40 + reportHuaningPayFeeInfo: {
  41 + fees: [],
  42 + conditions: {
  43 + year: new Date().getFullYear(),
  44 + month: new Date().getMonth() + 1
  45 + },
  46 + dateStr:getDateYYYYMMDD()
  47 + },
  48 + pagination: {
  49 + current: 1,
  50 + size: 10,
  51 + total: 0
  52 + }
  53 + }
  54 + },
  55 + methods: {
  56 + async initData(conditions) {
  57 + this.reportHuaningPayFeeInfo.conditions = { ...conditions }
  58 + this.pagination.current = 1
  59 + await this._listReportHuaningPayFee()
  60 + },
  61 + async _listReportHuaningPayFee() {
  62 + try {
  63 + const params = {
  64 + ...this.reportHuaningPayFeeInfo.conditions,
  65 + page: this.pagination.current,
  66 + row: this.pagination.size,
  67 + communityId: getCommunityId()
  68 + }
  69 +
  70 + const { data, total } = await queryHuaningPayFee(params)
  71 +
  72 + this.reportHuaningPayFeeInfo.fees = data
  73 + this.pagination.total = total
  74 + } catch (error) {
  75 + console.error('获取缴费数据失败:', error)
  76 + }
  77 + },
  78 + handlePageChange(currentPage) {
  79 + this.pagination.current = currentPage
  80 + this._listReportHuaningPayFee()
  81 + },
  82 + _getNextMonth() {
  83 + const date = new Date()
  84 + date.setMonth(date.getMonth() + 1)
  85 + return `${date.getFullYear()}${this.$t('common.year')}${date.getMonth() + 1}${this.$t('common.month')}`
  86 + }
  87 + }
  88 +}
  89 +</script>
  90 +
  91 +<style lang="scss" scoped>
  92 +.report-pay-fee-container {
  93 + .margin-top {
  94 + margin-top: 20px;
  95 + }
  96 +}
  97 +</style>
0 \ No newline at end of file 98 \ No newline at end of file
src/components/report/commonReportTable.vue 0 → 100644
  1 +<template>
  2 + <div class="common-report-table">
  3 + <div v-for="(item, index) in commonReportTableInfo.components" :key="index">
  4 + <el-card v-if="item.conditions && item.conditions.length > 0" class="query-card">
  5 + <div slot="header" class="clearfix">
  6 + <span>{{ $t('commonReportTable.queryConditions') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col v-for="(conditionItem, conditionIndex) in item.conditions" :key="conditionIndex" :span="6">
  10 + <el-input v-model.trim="conditionItem.value" :type="conditionItem.type"
  11 + :placeholder="conditionItem.holdpace" clearable />
  12 + </el-col>
  13 + <el-col :span="6">
  14 + <el-button type="primary" @click="_queryReportTableMethod(item)">
  15 + <i class="el-icon-search"></i>
  16 + {{ $t('commonReportTable.query') }}
  17 + </el-button>
  18 + <el-button @click="_resetReportTableMethod(item)">
  19 + <i class="el-icon-refresh"></i>
  20 + {{ $t('commonReportTable.reset') }}
  21 + </el-button>
  22 + </el-col>
  23 + </el-row>
  24 + </el-card>
  25 +
  26 + <el-card class="table-card">
  27 + <div slot="header" class="clearfix">
  28 + <span>{{ item.componentName }}</span>
  29 + <div style="float: right;">
  30 + <el-button type="primary" size="small" @click="_exportReportTableMethod(item)">
  31 + <i class="el-icon-download"></i>
  32 + {{ $t('commonReportTable.export') }}
  33 + </el-button>
  34 + <el-button type="primary" size="small" @click="_printReportTableMethod(item)">
  35 + <i class="el-icon-printer"></i>
  36 + {{ $t('commonReportTable.print') }}
  37 + </el-button>
  38 + </div>
  39 + </div>
  40 +
  41 + <el-table :data="item.data" border style="width: 100%" v-loading="loading">
  42 + <el-table-column v-for="(itemTh, indexTh) in item.th" :key="indexTh" :label="itemTh" align="center">
  43 + <template slot-scope="scope">
  44 + <div class="text-auto">
  45 + {{ scope.row[itemTh] }}
  46 + </div>
  47 + </template>
  48 + </el-table-column>
  49 + </el-table>
  50 +
  51 + <div v-if="item.footer" class="footer-wrapper">
  52 + <el-row :gutter="20">
  53 + <el-col v-for="(tmpItemTh, key) in item.footer" :key="key" :span="4">
  54 + <div class="footer-item">
  55 + {{ key }}: {{ tmpItemTh }}
  56 + </div>
  57 + </el-col>
  58 + </el-row>
  59 + </div>
  60 +
  61 + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  62 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  63 + @current-change="handleCurrentChange" />
  64 + </el-card>
  65 + </div>
  66 + </div>
  67 +</template>
  68 +
  69 +<script>
  70 +import {
  71 + listReportCustomComponentRel,
  72 + listReportCustomComponentCondition,
  73 + listReportCustomComponentData,
  74 + listReportCustomComponentDataFooter,
  75 + exportData
  76 +} from '@/api/report/commonReportApi'
  77 +import { getCommunityId } from '@/api/community/communityApi'
  78 +
  79 +export default {
  80 + name: 'CommonReportTable',
  81 + data() {
  82 + return {
  83 + commonReportTableInfo: {
  84 + components: [],
  85 + customId: ''
  86 + },
  87 + pagination: {
  88 + current: 1,
  89 + size: 10,
  90 + total: 0
  91 + },
  92 + loading: false,
  93 + communityId: ''
  94 + }
  95 + },
  96 + created() {
  97 + this.communityId = getCommunityId()
  98 + },
  99 + methods: {
  100 + handleSwitch(value) {
  101 + this.commonReportTableInfo.customId = value.customId
  102 + this._listReportCustomTableComponent()
  103 + },
  104 + handleSizeChange(val) {
  105 + this.pagination.size = val
  106 + this._queryReportTableMethod(this.commonReportTableInfo.components[0])
  107 + },
  108 + handleCurrentChange(val) {
  109 + this.pagination.current = val
  110 + this._queryReportTableMethod(this.commonReportTableInfo.components[0])
  111 + },
  112 + async _queryReportTableMethod(item) {
  113 + const condition = {}
  114 + item.conditions.forEach(_item => {
  115 + condition[_item.param] = _item.value
  116 + })
  117 + await this._listReportCustomTableDatas(this.pagination.current, this.pagination.size, item, condition)
  118 + await this._listReportCustomTableFooter(this.pagination.current, this.pagination.size, item, condition)
  119 + },
  120 + _resetReportTableMethod(item) {
  121 + const condition = {}
  122 + item.conditions.forEach(_item => {
  123 + _item.value = ''
  124 + condition[_item.param] = _item.value
  125 + })
  126 + this._listReportCustomTableDatas(1, this.pagination.size, item, condition)
  127 + this._listReportCustomTableFooter(1, this.pagination.size, item, condition)
  128 + },
  129 + async _listReportCustomTableComponent() {
  130 + try {
  131 + this.loading = true
  132 + const params = {
  133 + page: 1,
  134 + row: this.pagination.size,
  135 + customId: this.commonReportTableInfo.customId,
  136 + componentType: '1001'
  137 + }
  138 + const { data } = await listReportCustomComponentRel(params)
  139 + this.commonReportTableInfo.components = data
  140 + for (const item of this.commonReportTableInfo.components) {
  141 + await this._listReportCustomTableConditions(item)
  142 + await this._listReportCustomTableDatas(1, this.pagination.size, item)
  143 + await this._listReportCustomTableFooter(1, this.pagination.size, item)
  144 + }
  145 + } catch (error) {
  146 + console.error('Failed to load report components:', error)
  147 + } finally {
  148 + this.loading = false
  149 + }
  150 + },
  151 + async _listReportCustomTableConditions(component) {
  152 + try {
  153 + const params = {
  154 + page: 1,
  155 + row: this.pagination.size,
  156 + componentId: component.componentId
  157 + }
  158 + const { data } = await listReportCustomComponentCondition(params)
  159 + component.conditions = data
  160 + } catch (error) {
  161 + console.error('Failed to load conditions:', error)
  162 + }
  163 + },
  164 + async _listReportCustomTableDatas(page, row, component, conditions) {
  165 + try {
  166 + this.loading = true
  167 + const params = {
  168 + page,
  169 + row,
  170 + componentId: component.componentId,
  171 + communityId: this.communityId,
  172 + ...conditions
  173 + }
  174 + const { data, total } = await listReportCustomComponentData(params)
  175 + component.th = data.th
  176 + component.data = data.td
  177 + this.pagination.total = total
  178 + } catch (error) {
  179 + console.error('Failed to load table data:', error)
  180 + } finally {
  181 + this.loading = false
  182 + }
  183 + },
  184 + async _listReportCustomTableFooter(page, row, component, conditions) {
  185 + try {
  186 + const params = {
  187 + page,
  188 + row,
  189 + componentId: component.componentId,
  190 + communityId: this.communityId,
  191 + ...conditions
  192 + }
  193 + const { data } = await listReportCustomComponentDataFooter(params)
  194 + component.footer = data
  195 + } catch (error) {
  196 + console.error('Failed to load footer data:', error)
  197 + }
  198 + },
  199 + async _exportReportTableMethod(item) {
  200 + try {
  201 + const condition = {}
  202 + item.conditions.forEach(_item => {
  203 + condition[_item.param] = _item.value
  204 + })
  205 + const params = {
  206 + page: 1,
  207 + row: 10000,
  208 + componentId: item.componentId,
  209 + communityId: this.communityId,
  210 + pagePath: 'exportCustomReportTableData',
  211 + ...condition
  212 + }
  213 + const { code, msg } = await exportData(params)
  214 + this.$message.success(msg)
  215 + if (code === 0) {
  216 + this.$router.push('/pages/property/downloadTempFile?tab=downloadCenter')
  217 + }
  218 + } catch (error) {
  219 + console.error('Export failed:', error)
  220 + }
  221 + },
  222 + _printReportTableMethod(data) {
  223 + this.$store.commit('SET_PRINT_DATA', data)
  224 + window.open('/print.html#/pages/property/printCommonReportTable')
  225 + }
  226 + }
  227 +}
  228 +</script>
  229 +
  230 +<style lang="scss" scoped>
  231 +.common-report-table {
  232 + .query-card {
  233 + margin-bottom: 20px;
  234 + }
  235 +
  236 + .table-card {
  237 + margin-bottom: 20px;
  238 + }
  239 +
  240 + .text-auto {
  241 + max-width: 200px;
  242 + white-space: nowrap;
  243 + overflow: hidden;
  244 + text-overflow: ellipsis;
  245 + }
  246 +
  247 + .footer-wrapper {
  248 + margin-top: 20px;
  249 + padding: 10px;
  250 + background-color: #f5f7fa;
  251 + border-radius: 4px;
  252 +
  253 + .footer-item {
  254 + padding: 5px 0;
  255 + }
  256 + }
  257 +
  258 + .el-pagination {
  259 + margin-top: 20px;
  260 + text-align: right;
  261 + }
  262 +}
  263 +</style>
0 \ No newline at end of file 264 \ No newline at end of file
src/components/report/searchFloor.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('searchFloor.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + @close="handleClose">
  7 + <el-row :gutter="20">
  8 + <el-col :span="24">
  9 + <el-card>
  10 + <el-row :gutter="20">
  11 + <el-col :span="6">
  12 + <el-input
  13 + v-model="searchForm.floorId"
  14 + :placeholder="$t('searchFloor.floorId')"
  15 + clearable>
  16 + </el-input>
  17 + </el-col>
  18 + <el-col :span="6">
  19 + <el-input
  20 + v-model="searchForm.floorName"
  21 + :placeholder="$t('searchFloor.floorName')"
  22 + clearable>
  23 + </el-input>
  24 + </el-col>
  25 + <el-col :span="6">
  26 + <el-input
  27 + v-model="searchForm.floorNum"
  28 + :placeholder="$t('searchFloor.floorNum')"
  29 + clearable>
  30 + </el-input>
  31 + </el-col>
  32 + <el-col :span="6">
  33 + <el-button type="primary" @click="searchFloors">
  34 + <i class="el-icon-search"></i>
  35 + {{ $t('searchFloor.search') }}
  36 + </el-button>
  37 + <el-button @click="resetFloors" style="margin-left: 10px;">
  38 + <i class="el-icon-refresh"></i>
  39 + {{ $t('searchFloor.reset') }}
  40 + </el-button>
  41 + </el-col>
  42 + </el-row>
  43 +
  44 + <el-table
  45 + :data="floors"
  46 + border
  47 + style="width: 100%; margin-top: 20px;"
  48 + v-loading="loading">
  49 + <el-table-column
  50 + prop="floorId"
  51 + :label="$t('searchFloor.table.floorId')"
  52 + align="center">
  53 + </el-table-column>
  54 + <el-table-column
  55 + prop="floorName"
  56 + :label="$t('searchFloor.table.floorName')"
  57 + align="center">
  58 + </el-table-column>
  59 + <el-table-column
  60 + prop="floorNum"
  61 + :label="$t('searchFloor.table.floorNum')"
  62 + align="center">
  63 + </el-table-column>
  64 + <el-table-column
  65 + prop="userName"
  66 + :label="$t('searchFloor.table.userName')"
  67 + align="center">
  68 + </el-table-column>
  69 + <el-table-column
  70 + :label="$t('searchFloor.table.operation')"
  71 + align="center"
  72 + width="120">
  73 + <template slot-scope="scope">
  74 + <el-button
  75 + size="mini"
  76 + type="primary"
  77 + @click="chooseFloor(scope.row)">
  78 + {{ $t('searchFloor.table.choose') }}
  79 + </el-button>
  80 + </template>
  81 + </el-table-column>
  82 + </el-table>
  83 +
  84 + <el-pagination
  85 + @size-change="handleSizeChange"
  86 + @current-change="handleCurrentChange"
  87 + :current-page="page.current"
  88 + :page-sizes="[10, 20, 30, 50]"
  89 + :page-size="page.size"
  90 + layout="total, sizes, prev, pager, next, jumper"
  91 + :total="total"
  92 + style="margin-top: 20px;">
  93 + </el-pagination>
  94 + </el-card>
  95 + </el-col>
  96 + </el-row>
  97 + </el-dialog>
  98 +</template>
  99 +
  100 +<script>
  101 +import { getCommunityId } from '@/api/community/communityApi'
  102 +import { queryFloors } from '@/api/property/floorApi'
  103 +
  104 +export default {
  105 + name: 'SearchFloor',
  106 + data() {
  107 + return {
  108 + visible: false,
  109 + loading: false,
  110 + communityId: '',
  111 + searchForm: {
  112 + floorId: '',
  113 + floorName: '',
  114 + floorNum: ''
  115 + },
  116 + floors: [],
  117 + page: {
  118 + current: 1,
  119 + size: 10,
  120 + total: 0
  121 + }
  122 + }
  123 + },
  124 + created() {
  125 + this.communityId = getCommunityId()
  126 + },
  127 + methods: {
  128 + open() {
  129 + this.visible = true
  130 + this.refreshSearchFloorData()
  131 + this.loadAllFloorInfo()
  132 + },
  133 + async loadAllFloorInfo() {
  134 + this.loading = true
  135 + try {
  136 + const params = {
  137 + page: this.page.current,
  138 + row: this.page.size,
  139 + communityId: this.communityId,
  140 + floorId: this.searchForm.floorId,
  141 + floorName: this.searchForm.floorName,
  142 + floorNum: this.searchForm.floorNum
  143 + }
  144 + const res = await queryFloors(params)
  145 + this.floors = res.data
  146 + this.page.total = res.total
  147 + } catch (error) {
  148 + console.error('获取楼栋列表失败:', error)
  149 + } finally {
  150 + this.loading = false
  151 + }
  152 + },
  153 + chooseFloor(floor) {
  154 + this.$emit('chooseFloor', floor)
  155 + this.visible = false
  156 + },
  157 + searchFloors() {
  158 + this.page.current = 1
  159 + this.loadAllFloorInfo()
  160 + },
  161 + resetFloors() {
  162 + this.searchForm = {
  163 + floorId: '',
  164 + floorName: '',
  165 + floorNum: ''
  166 + }
  167 + this.loadAllFloorInfo()
  168 + },
  169 + handleSizeChange(val) {
  170 + this.page.size = val
  171 + this.loadAllFloorInfo()
  172 + },
  173 + handleCurrentChange(val) {
  174 + this.page.current = val
  175 + this.loadAllFloorInfo()
  176 + },
  177 + refreshSearchFloorData() {
  178 + this.searchForm = {
  179 + floorId: '',
  180 + floorName: '',
  181 + floorNum: ''
  182 + }
  183 + },
  184 + handleClose() {
  185 + this.refreshSearchFloorData()
  186 + }
  187 + }
  188 +}
  189 +</script>
  190 +
  191 +<style lang="scss" scoped>
  192 +.el-dialog__body {
  193 + padding: 20px;
  194 +}
  195 +</style>
0 \ No newline at end of file 196 \ No newline at end of file
src/components/report/viewFeeDetail.vue
1 <template> 1 <template>
2 - <el-dialog :title="`${viewFeeDetailInfo.curYear}${$t('viewFeeDetail.yearFeeHistory')}(${viewFeeDetailInfo.roomName})`"  
3 - :visible.sync="dialogVisible" width="80%" top="5vh">  
4 - <el-table :data="viewFeeDetailInfo.feeDetails" border style="width: 100%" height="500">  
5 - <el-table-column prop="cycles" :label="$t('viewFeeDetail.cycle')" align="center">  
6 - </el-table-column>  
7 - <el-table-column prop="receivableAmount" :label="$t('viewFeeDetail.receivableAmount')" align="center">  
8 - </el-table-column>  
9 - <el-table-column prop="receivedAmount" :label="$t('viewFeeDetail.receivedAmount')" align="center">  
10 - </el-table-column>  
11 - <el-table-column prop="createTime" :label="$t('viewFeeDetail.paymentTime')" align="center">  
12 - </el-table-column>  
13 - <el-table-column prop="startTime" :label="$t('viewFeeDetail.startTime')" align="center"> 2 + <el-dialog :title="`${viewFeeDetailInfo.curYear}${$t('viewFeeDetail.title')}(${viewFeeDetailInfo.roomName})`"
  3 + :visible.sync="dialogVisible" width="80%" @close="handleClose">
  4 + <el-table :data="viewFeeDetailInfo.feeDetails" border style="width: 100%">
  5 + <el-table-column prop="cycles" :label="$t('viewFeeDetail.table.cycle')" align="center" />
  6 + <el-table-column prop="receivableAmount" :label="$t('viewFeeDetail.table.receivableAmount')" align="center" />
  7 + <el-table-column prop="receivedAmount" :label="$t('viewFeeDetail.table.receivedAmount')" align="center" />
  8 + <el-table-column prop="createTime" :label="$t('viewFeeDetail.table.payTime')" align="center" />
  9 + <el-table-column prop="startTime" :label="$t('viewFeeDetail.table.startTime')" align="center">
14 <template slot-scope="scope"> 10 <template slot-scope="scope">
15 - {{ $moment(scope.row.startTime).format('YYYY-MM-DD') }} 11 + {{ $dayjs(scope.row.startTime).format('YYYY-MM-DD') }}
16 </template> 12 </template>
17 </el-table-column> 13 </el-table-column>
18 - <el-table-column prop="endTime" :label="$t('viewFeeDetail.endTime')" align="center"> 14 + <el-table-column prop="endTime" :label="$t('viewFeeDetail.table.endTime')" align="center">
19 <template slot-scope="scope"> 15 <template slot-scope="scope">
20 - {{ $moment(scope.row.endTime).format('YYYY-MM-DD') }} 16 + {{ $dayjs(scope.row.endTime).format('YYYY-MM-DD') }}
21 </template> 17 </template>
22 </el-table-column> 18 </el-table-column>
23 - <el-table-column prop="stateName" :label="$t('viewFeeDetail.status')" align="center">  
24 - </el-table-column>  
25 - <el-table-column prop="remark" :label="$t('viewFeeDetail.remark')" align="center">  
26 - </el-table-column> 19 + <el-table-column prop="stateName" :label="$t('viewFeeDetail.table.status')" align="center" />
  20 + <el-table-column prop="remark" :label="$t('viewFeeDetail.table.remark')" align="center" />
27 </el-table> 21 </el-table>
28 22
29 - <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"  
30 - :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"  
31 - @current-change="handleCurrentChange">  
32 - </el-pagination> 23 + <el-pagination :current-page.sync="pagination.current" :page-size="pagination.size" :total="pagination.total"
  24 + layout="total, prev, pager, next, jumper" @current-change="handlePageChange" class="margin-top" />
33 </el-dialog> 25 </el-dialog>
34 </template> 26 </template>
35 27
36 <script> 28 <script>
37 -import { queryFeeDetail } from '@/api/report/reportProficientApi' 29 +import { queryFeeDetail } from '@/api/report/reportHuaningApi'
  30 +import { getCommunityId } from '@/api/community/communityApi'
38 31
39 export default { 32 export default {
40 name: 'ViewFeeDetail', 33 name: 'ViewFeeDetail',
@@ -43,11 +36,13 @@ export default { @@ -43,11 +36,13 @@ export default {
43 dialogVisible: false, 36 dialogVisible: false,
44 viewFeeDetailInfo: { 37 viewFeeDetailInfo: {
45 feeDetails: [], 38 feeDetails: [],
46 - curYear: '',  
47 - roomName: '', 39 + total: 0,
  40 + records: 1,
48 feeId: '', 41 feeId: '',
49 configId: '', 42 configId: '',
50 - payerObjId: '' 43 + payerObjId: '',
  44 + curYear: '',
  45 + roomName: ''
51 }, 46 },
52 pagination: { 47 pagination: {
53 current: 1, 48 current: 1,
@@ -65,29 +60,31 @@ export default { @@ -65,29 +60,31 @@ export default {
65 this.dialogVisible = true 60 this.dialogVisible = true
66 this.listFeeDetail() 61 this.listFeeDetail()
67 }, 62 },
  63 + handleClose() {
  64 + this.dialogVisible = false
  65 + this.pagination.current = 1
  66 + },
68 async listFeeDetail() { 67 async listFeeDetail() {
69 try { 68 try {
70 const params = { 69 const params = {
71 page: this.pagination.current, 70 page: this.pagination.current,
72 row: this.pagination.size, 71 row: this.pagination.size,
  72 + communityId: getCommunityId(),
73 curYear: this.viewFeeDetailInfo.curYear, 73 curYear: this.viewFeeDetailInfo.curYear,
74 configId: this.viewFeeDetailInfo.configId, 74 configId: this.viewFeeDetailInfo.configId,
75 payerObjId: this.viewFeeDetailInfo.payerObjId 75 payerObjId: this.viewFeeDetailInfo.payerObjId
76 } 76 }
77 - const { data, records } = await queryFeeDetail(params) 77 +
  78 + const { data, total } = await queryFeeDetail(params)
78 79
79 this.viewFeeDetailInfo.feeDetails = data 80 this.viewFeeDetailInfo.feeDetails = data
80 - this.pagination.total = records 81 + this.pagination.total = total
81 } catch (error) { 82 } catch (error) {
82 - console.error('获取费用详情失败:', error) 83 + console.error('获取费用明细失败:', error)
83 } 84 }
84 }, 85 },
85 - handleSizeChange(val) {  
86 - this.pagination.size = val  
87 - this.listFeeDetail()  
88 - },  
89 - handleCurrentChange(val) {  
90 - this.pagination.current = val 86 + handlePageChange(currentPage) {
  87 + this.pagination.current = currentPage
91 this.listFeeDetail() 88 this.listFeeDetail()
92 } 89 }
93 } 90 }
@@ -95,7 +92,7 @@ export default { @@ -95,7 +92,7 @@ export default {
95 </script> 92 </script>
96 93
97 <style lang="scss" scoped> 94 <style lang="scss" scoped>
98 -::v-deep .el-dialog__body {  
99 - padding: 20px; 95 +.margin-top {
  96 + margin-top: 20px;
100 } 97 }
101 </style> 98 </style>
102 \ No newline at end of file 99 \ No newline at end of file
src/components/scm/AddCouponRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRule.addRule')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  8 + <el-form-item :label="$t('couponRule.ruleName')" prop="ruleName">
  9 + <el-input v-model="form.ruleName" :placeholder="$t('couponRule.ruleNamePlaceholder')" />
  10 + </el-form-item>
  11 +
  12 + <el-form-item :label="$t('couponRule.remark')" prop="remark">
  13 + <el-input
  14 + type="textarea"
  15 + :rows="3"
  16 + v-model="form.remark"
  17 + :placeholder="$t('couponRule.remarkPlaceholder')" />
  18 + </el-form-item>
  19 + </el-form>
  20 +
  21 + <span slot="footer" class="dialog-footer">
  22 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  23 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  24 + </span>
  25 + </el-dialog>
  26 +</template>
  27 +
  28 +<script>
  29 +import { saveCouponRule } from '@/api/scm/couponRuleApi'
  30 +import { getCommunityId } from '@/api/community/communityApi'
  31 +
  32 +export default {
  33 + name: 'AddCouponRule',
  34 + data() {
  35 + return {
  36 + visible: false,
  37 + form: {
  38 + ruleName: '',
  39 + remark: '',
  40 + communityId: ''
  41 + },
  42 + rules: {
  43 + ruleName: [
  44 + { required: true, message: this.$t('couponRule.ruleNameRequired'), trigger: 'blur' },
  45 + { max: 64, message: this.$t('couponRule.ruleNameMaxLength'), trigger: 'blur' }
  46 + ],
  47 + remark: [
  48 + { max: 512, message: this.$t('couponRule.remarkMaxLength'), trigger: 'blur' }
  49 + ]
  50 + }
  51 + }
  52 + },
  53 + methods: {
  54 + open() {
  55 + this.visible = true
  56 + this.form.communityId = getCommunityId()
  57 + this.$nextTick(() => {
  58 + this.$refs.form.resetFields()
  59 + })
  60 + },
  61 + handleClose() {
  62 + this.$refs.form.resetFields()
  63 + },
  64 + handleSubmit() {
  65 + this.$refs.form.validate(async valid => {
  66 + if (valid) {
  67 + try {
  68 + await saveCouponRule(this.form)
  69 + this.$message.success(this.$t('common.addSuccess'))
  70 + this.visible = false
  71 + this.$emit('success')
  72 + } catch (error) {
  73 + console.error('Failed to add coupon rule:', error)
  74 + }
  75 + }
  76 + })
  77 + }
  78 + }
  79 +}
  80 +</script>
  81 +
  82 +<style lang="scss" scoped>
  83 +.el-dialog {
  84 + .el-form {
  85 + padding: 0 20px;
  86 +
  87 + .el-input, .el-textarea {
  88 + width: 100%;
  89 + }
  90 + }
  91 +}
  92 +</style>
0 \ No newline at end of file 93 \ No newline at end of file
src/components/scm/AddCouponRuleCpps.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRuleCpps.addCoupon')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form
  8 + ref="form"
  9 + :model="form"
  10 + :rules="rules"
  11 + label-width="120px">
  12 + <el-form-item
  13 + :label="$t('couponRuleCpps.coupon')"
  14 + prop="cppId">
  15 + <el-select
  16 + v-model="form.cppId"
  17 + :placeholder="$t('couponRuleCpps.couponPlaceholder')"
  18 + style="width: 100%">
  19 + <el-option
  20 + v-for="item in couponOptions"
  21 + :key="item.cppId"
  22 + :label="item.couponName"
  23 + :value="item.cppId">
  24 + </el-option>
  25 + </el-select>
  26 + </el-form-item>
  27 +
  28 + <el-form-item
  29 + :label="$t('couponRuleCpps.quantity')"
  30 + prop="quantity">
  31 + <el-input
  32 + v-model="form.quantity"
  33 + :placeholder="$t('couponRuleCpps.quantityPlaceholder')" />
  34 + </el-form-item>
  35 +
  36 + <el-form-item
  37 + :label="$t('couponRuleCpps.frequency')"
  38 + prop="giftFrequency">
  39 + <el-select
  40 + v-model="form.giftFrequency"
  41 + :placeholder="$t('couponRuleCpps.frequencyPlaceholder')"
  42 + style="width: 100%">
  43 + <el-option
  44 + v-for="item in frequencyOptions"
  45 + :key="item.value"
  46 + :label="item.label"
  47 + :value="item.value">
  48 + </el-option>
  49 + </el-select>
  50 + </el-form-item>
  51 + </el-form>
  52 +
  53 + <span slot="footer" class="dialog-footer">
  54 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  55 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  56 + </span>
  57 + </el-dialog>
  58 +</template>
  59 +
  60 +<script>
  61 +import { saveCouponRuleCpps, listCouponPropertyPool } from '@/api/scm/couponRuleApi'
  62 +import { getCommunityId } from '@/api/community/communityApi'
  63 +
  64 +export default {
  65 + name: 'AddCouponRuleCpps',
  66 + props: {
  67 + ruleId: {
  68 + type: String,
  69 + required: true
  70 + }
  71 + },
  72 + data() {
  73 + return {
  74 + visible: false,
  75 + form: {
  76 + cppId: '',
  77 + quantity: '',
  78 + giftFrequency: '100301',
  79 + ruleId: '',
  80 + communityId: ''
  81 + },
  82 + rules: {
  83 + cppId: [
  84 + { required: true, message: this.$t('couponRuleCpps.couponRequired'), trigger: 'change' }
  85 + ],
  86 + quantity: [
  87 + { required: true, message: this.$t('couponRuleCpps.quantityRequired'), trigger: 'blur' },
  88 + { pattern: /^[1-9]\d*$/, message: this.$t('couponRuleCpps.quantityPattern'), trigger: 'blur' }
  89 + ],
  90 + giftFrequency: [
  91 + { required: true, message: this.$t('couponRuleCpps.frequencyRequired'), trigger: 'change' }
  92 + ]
  93 + },
  94 + couponOptions: [],
  95 + frequencyOptions: [
  96 + { value: '100301', label: this.$t('couponRuleCpps.once') },
  97 + { value: '100302', label: this.$t('couponRuleCpps.monthly') }
  98 + ]
  99 + }
  100 + },
  101 + methods: {
  102 + open() {
  103 + this.form.ruleId = this.ruleId
  104 + this.form.communityId = getCommunityId()
  105 + this.getCouponOptions()
  106 + this.visible = true
  107 + this.$nextTick(() => {
  108 + this.$refs.form.resetFields()
  109 + })
  110 + },
  111 + async getCouponOptions() {
  112 + try {
  113 + const params = {
  114 + page: 1,
  115 + row: 100,
  116 + communityId: getCommunityId()
  117 + }
  118 + const { data } = await listCouponPropertyPool(params)
  119 + this.couponOptions = data
  120 + } catch (error) {
  121 + console.error('Failed to get coupon options:', error)
  122 + }
  123 + },
  124 + handleClose() {
  125 + this.$refs.form.resetFields()
  126 + },
  127 + handleSubmit() {
  128 + this.$refs.form.validate(async valid => {
  129 + if (valid) {
  130 + try {
  131 + await saveCouponRuleCpps(this.form)
  132 + this.$message.success(this.$t('common.addSuccess'))
  133 + this.visible = false
  134 + this.$emit('success')
  135 + } catch (error) {
  136 + console.error('Failed to add coupon rule cpps:', error)
  137 + }
  138 + }
  139 + })
  140 + }
  141 + }
  142 +}
  143 +</script>
  144 +
  145 +<style lang="scss" scoped>
  146 +.el-dialog {
  147 + .el-form {
  148 + padding: 0 20px;
  149 +
  150 + .el-input, .el-select {
  151 + width: 100%;
  152 + }
  153 + }
  154 +}
  155 +</style>
0 \ No newline at end of file 156 \ No newline at end of file
src/components/scm/AddCouponRuleFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRuleFee.addFee')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form
  8 + ref="form"
  9 + :model="form"
  10 + :rules="rules"
  11 + label-width="120px">
  12 + <el-form-item
  13 + :label="$t('couponRuleFee.fee')"
  14 + prop="feeConfigId">
  15 + <el-select
  16 + v-model="form.feeConfigId"
  17 + :placeholder="$t('couponRuleFee.feePlaceholder')"
  18 + style="width: 100%">
  19 + <el-option
  20 + v-for="item in feeOptions"
  21 + :key="item.configId"
  22 + :label="item.feeName"
  23 + :value="item.configId">
  24 + </el-option>
  25 + </el-select>
  26 + </el-form-item>
  27 +
  28 + <el-form-item
  29 + :label="$t('couponRuleFee.payStartTime')"
  30 + prop="payStartTime">
  31 + <el-date-picker
  32 + v-model="form.payStartTime"
  33 + type="datetime"
  34 + :placeholder="$t('couponRuleFee.payStartTimePlaceholder')"
  35 + style="width: 100%">
  36 + </el-date-picker>
  37 + </el-form-item>
  38 +
  39 + <el-form-item
  40 + :label="$t('couponRuleFee.payEndTime')"
  41 + prop="payEndTime">
  42 + <el-date-picker
  43 + v-model="form.payEndTime"
  44 + type="datetime"
  45 + :placeholder="$t('couponRuleFee.payEndTimePlaceholder')"
  46 + style="width: 100%">
  47 + </el-date-picker>
  48 + </el-form-item>
  49 +
  50 + <el-form-item
  51 + :label="$t('couponRuleFee.payMonth')"
  52 + prop="payMonth">
  53 + <el-input-number
  54 + v-model="form.payMonth"
  55 + :min="1"
  56 + :max="12"
  57 + :placeholder="$t('couponRuleFee.payMonthPlaceholder')">
  58 + </el-input-number>
  59 + </el-form-item>
  60 + </el-form>
  61 +
  62 + <span slot="footer" class="dialog-footer">
  63 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  64 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  65 + </span>
  66 + </el-dialog>
  67 +</template>
  68 +
  69 +<script>
  70 +import { saveCouponRuleFee, listFeeConfigs } from '@/api/scm/couponRuleApi'
  71 +import { getCommunityId } from '@/api/community/communityApi'
  72 +
  73 +export default {
  74 + name: 'AddCouponRuleFee',
  75 + props: {
  76 + ruleId: {
  77 + type: String,
  78 + required: true
  79 + }
  80 + },
  81 + data() {
  82 + return {
  83 + visible: false,
  84 + form: {
  85 + feeConfigId: '',
  86 + payStartTime: '',
  87 + payEndTime: '',
  88 + payMonth: 1,
  89 + ruleId: '',
  90 + communityId: ''
  91 + },
  92 + rules: {
  93 + feeConfigId: [
  94 + { required: true, message: this.$t('couponRuleFee.feeRequired'), trigger: 'change' }
  95 + ],
  96 + payStartTime: [
  97 + { required: true, message: this.$t('couponRuleFee.payStartTimeRequired'), trigger: 'change' }
  98 + ],
  99 + payEndTime: [
  100 + { required: true, message: this.$t('couponRuleFee.payEndTimeRequired'), trigger: 'change' }
  101 + ],
  102 + payMonth: [
  103 + { required: true, message: this.$t('couponRuleFee.payMonthRequired'), trigger: 'blur' }
  104 + ]
  105 + },
  106 + feeOptions: []
  107 + }
  108 + },
  109 + methods: {
  110 + open() {
  111 + this.form.ruleId = this.ruleId
  112 + this.form.communityId = getCommunityId()
  113 + this.getFeeOptions()
  114 + this.visible = true
  115 + this.$nextTick(() => {
  116 + this.$refs.form.resetFields()
  117 + })
  118 + },
  119 + async getFeeOptions() {
  120 + try {
  121 + const params = {
  122 + page: 1,
  123 + row: 100,
  124 + communityId: getCommunityId()
  125 + }
  126 + const { feeConfigs } = await listFeeConfigs(params)
  127 + this.feeOptions = feeConfigs
  128 + } catch (error) {
  129 + console.error('Failed to get fee options:', error)
  130 + }
  131 + },
  132 + handleClose() {
  133 + this.$refs.form.resetFields()
  134 + },
  135 + handleSubmit() {
  136 + this.$refs.form.validate(async valid => {
  137 + if (valid) {
  138 + try {
  139 + await saveCouponRuleFee(this.form)
  140 + this.$message.success(this.$t('common.addSuccess'))
  141 + this.visible = false
  142 + this.$emit('success')
  143 + } catch (error) {
  144 + console.error('Failed to add coupon rule fee:', error)
  145 + }
  146 + }
  147 + })
  148 + }
  149 + }
  150 +}
  151 +</script>
  152 +
  153 +<style lang="scss" scoped>
  154 +.el-dialog {
  155 + .el-form {
  156 + padding: 0 20px;
  157 +
  158 + .el-select, .el-date-picker {
  159 + width: 100%;
  160 + }
  161 + }
  162 +}
  163 +</style>
0 \ No newline at end of file 164 \ No newline at end of file
src/components/scm/CouponRuleCpps.vue 0 → 100644
  1 +<template>
  2 + <div class="coupon-rule-cpps">
  3 + <el-row class="operation-row">
  4 + <el-col :span="24">
  5 + <el-button
  6 + type="primary"
  7 + size="small"
  8 + @click="handleQuery"
  9 + class="query-btn">
  10 + {{ $t('common.query') }}
  11 + </el-button>
  12 + <el-button
  13 + type="primary"
  14 + size="small"
  15 + @click="openAddModal"
  16 + class="add-btn">
  17 + <i class="el-icon-plus"></i>
  18 + {{ $t('common.add') }}
  19 + </el-button>
  20 + </el-col>
  21 + </el-row>
  22 +
  23 + <el-table
  24 + :data="tableData"
  25 + border
  26 + style="width: 100%"
  27 + v-loading="loading">
  28 + <el-table-column
  29 + prop="crcId"
  30 + :label="$t('couponRuleCpps.id')"
  31 + align="center"
  32 + width="100">
  33 + </el-table-column>
  34 + <el-table-column
  35 + prop="couponName"
  36 + :label="$t('couponRuleCpps.coupon')"
  37 + align="center">
  38 + </el-table-column>
  39 + <el-table-column
  40 + prop="quantity"
  41 + :label="$t('couponRuleCpps.quantity')"
  42 + align="center">
  43 + </el-table-column>
  44 + <el-table-column
  45 + prop="giftFrequencyName"
  46 + :label="$t('couponRuleCpps.frequency')"
  47 + align="center">
  48 + </el-table-column>
  49 + <el-table-column
  50 + :label="$t('common.operation')"
  51 + align="center"
  52 + width="200">
  53 + <template slot-scope="scope">
  54 + <el-button
  55 + size="mini"
  56 + @click="openEditModal(scope.row)">
  57 + {{ $t('common.edit') }}
  58 + </el-button>
  59 + <el-button
  60 + size="mini"
  61 + type="danger"
  62 + @click="openDeleteModal(scope.row)">
  63 + {{ $t('common.delete') }}
  64 + </el-button>
  65 + </template>
  66 + </el-table-column>
  67 + </el-table>
  68 +
  69 + <el-pagination
  70 + @size-change="handleSizeChange"
  71 + @current-change="handleCurrentChange"
  72 + :current-page="pagination.current"
  73 + :page-sizes="[10, 20, 30, 50]"
  74 + :page-size="pagination.size"
  75 + layout="total, sizes, prev, pager, next, jumper"
  76 + :total="pagination.total">
  77 + </el-pagination>
  78 +
  79 + <add-coupon-rule-cpps
  80 + ref="addCouponRuleCpps"
  81 + :rule-id="ruleId"
  82 + @success="handleSuccess" />
  83 + <edit-coupon-rule-cpps
  84 + ref="editCouponRuleCpps"
  85 + @success="handleSuccess" />
  86 + <delete-coupon-rule-cpps
  87 + ref="deleteCouponRuleCpps"
  88 + @success="handleSuccess" />
  89 + </div>
  90 +</template>
  91 +
  92 +<script>
  93 +import { listCouponRuleCpps } from '@/api/scm/couponRuleApi'
  94 +import AddCouponRuleCpps from './AddCouponRuleCpps'
  95 +import EditCouponRuleCpps from './EditCouponRuleCpps'
  96 +import DeleteCouponRuleCpps from './DeleteCouponRuleCpps'
  97 +import { getCommunityId } from '@/api/community/communityApi'
  98 +
  99 +export default {
  100 + name: 'CouponRuleCpps',
  101 + components: {
  102 + AddCouponRuleCpps,
  103 + EditCouponRuleCpps,
  104 + DeleteCouponRuleCpps
  105 + },
  106 + props: {
  107 + ruleId: {
  108 + type: String,
  109 + required: true
  110 + }
  111 + },
  112 + data() {
  113 + return {
  114 + loading: false,
  115 + tableData: [],
  116 + pagination: {
  117 + current: 1,
  118 + size: 10,
  119 + total: 0
  120 + }
  121 + }
  122 + },
  123 + watch: {
  124 + ruleId() {
  125 + this.getList()
  126 + }
  127 + },
  128 + methods: {
  129 + async getList() {
  130 + if (!this.ruleId) return
  131 +
  132 + this.loading = true
  133 + try {
  134 + const params = {
  135 + page: this.pagination.current,
  136 + row: this.pagination.size,
  137 + ruleId: this.ruleId,
  138 + communityId: getCommunityId()
  139 + }
  140 + const { data, total } = await listCouponRuleCpps(params)
  141 + this.tableData = data
  142 + this.pagination.total = total
  143 + } catch (error) {
  144 + console.error('Failed to get coupon rule cpps:', error)
  145 + } finally {
  146 + this.loading = false
  147 + }
  148 + },
  149 + handleQuery() {
  150 + this.pagination.current = 1
  151 + this.getList()
  152 + },
  153 + handleSizeChange(val) {
  154 + this.pagination.size = val
  155 + this.getList()
  156 + },
  157 + handleCurrentChange(val) {
  158 + this.pagination.current = val
  159 + this.getList()
  160 + },
  161 + openAddModal() {
  162 + this.$refs.addCouponRuleCpps.open()
  163 + },
  164 + openEditModal(row) {
  165 + this.$refs.editCouponRuleCpps.open(row)
  166 + },
  167 + openDeleteModal(row) {
  168 + this.$refs.deleteCouponRuleCpps.open(row)
  169 + },
  170 + handleSuccess() {
  171 + this.getList()
  172 + }
  173 + }
  174 +}
  175 +</script>
  176 +
  177 +<style lang="scss" scoped>
  178 +.coupon-rule-cpps {
  179 + .operation-row {
  180 + margin-bottom: 20px;
  181 +
  182 + .query-btn {
  183 + margin-right: 10px;
  184 + }
  185 + }
  186 +
  187 + .el-pagination {
  188 + margin-top: 20px;
  189 + text-align: right;
  190 + }
  191 +}
  192 +</style>
0 \ No newline at end of file 193 \ No newline at end of file
src/components/scm/CouponRuleDiv.vue 0 → 100644
  1 +<template>
  2 + <el-card class="coupon-rule-div">
  3 + <div class="operation-buttons">
  4 + <el-button type="primary" size="small" @click="openAddModal">{{ $t('common.add') }}</el-button>
  5 + <el-button type="warning" size="small" @click="openEditModal">{{ $t('common.edit') }}</el-button>
  6 + <el-button type="danger" size="small" @click="openDeleteModal">{{ $t('common.delete') }}</el-button>
  7 + </div>
  8 +
  9 + <el-divider></el-divider>
  10 +
  11 + <el-tree :data="couponRules" :props="treeProps" node-key="ruleId" highlight-current @node-click="handleNodeClick"
  12 + class="coupon-rule-tree">
  13 + <span slot-scope="{ node }" class="custom-tree-node">
  14 + <span>{{ node.label }}</span>
  15 + </span>
  16 + </el-tree>
  17 + </el-card>
  18 +</template>
  19 +
  20 +<script>
  21 +import { listCouponRule } from '@/api/scm/couponRuleApi'
  22 +import { getCommunityId } from '@/api/community/communityApi'
  23 +
  24 +export default {
  25 + name: 'CouponRuleDiv',
  26 + data() {
  27 + return {
  28 + couponRules: [],
  29 + currentRule: {},
  30 + treeProps: {
  31 + label: 'ruleName',
  32 + children: 'children'
  33 + }
  34 + }
  35 + },
  36 + created() {
  37 + this.communityId = getCommunityId()
  38 + this.getList()
  39 + },
  40 + methods: {
  41 + async getList() {
  42 + try {
  43 + const params = {
  44 + page: 1,
  45 + row: 100,
  46 + communityId: this.communityId
  47 + }
  48 + const { data } = await listCouponRule(params)
  49 + this.couponRules = data
  50 + if (this.couponRules.length > 0) {
  51 + this.handleNodeClick(this.couponRules[0])
  52 + }
  53 + } catch (error) {
  54 + console.error('Failed to get coupon rules:', error)
  55 + }
  56 + },
  57 + handleNodeClick(data) {
  58 + this.currentRule = data
  59 + this.$emit('switch', data)
  60 + },
  61 + openAddModal() {
  62 + this.$emit('open-add')
  63 + },
  64 + openEditModal() {
  65 + if (!this.currentRule.ruleId) {
  66 + this.$message.warning(this.$t('couponRule.selectRuleFirst'))
  67 + return
  68 + }
  69 + this.$emit('open-edit', this.currentRule)
  70 + },
  71 + openDeleteModal() {
  72 + if (!this.currentRule.ruleId) {
  73 + this.$message.warning(this.$t('couponRule.selectRuleFirst'))
  74 + return
  75 + }
  76 + this.$emit('open-delete', this.currentRule)
  77 + },
  78 + refreshList() {
  79 + this.getList()
  80 + }
  81 + }
  82 +}
  83 +</script>
  84 +
  85 +<style lang="scss" scoped>
  86 +.coupon-rule-div {
  87 + height: 100%;
  88 +
  89 + .operation-buttons {
  90 + margin-bottom: 10px;
  91 +
  92 + .el-button {
  93 + margin-right: 10px;
  94 + }
  95 + }
  96 +
  97 + .coupon-rule-tree {
  98 + height: calc(100% - 60px);
  99 + overflow-y: auto;
  100 +
  101 + .custom-tree-node {
  102 + flex: 1;
  103 + display: flex;
  104 + align-items: center;
  105 + justify-content: space-between;
  106 + font-size: 14px;
  107 + padding-right: 8px;
  108 + }
  109 + }
  110 +}
  111 +</style>
0 \ No newline at end of file 112 \ No newline at end of file
src/components/scm/CouponRuleFees.vue 0 → 100644
  1 +<template>
  2 + <div class="coupon-rule-fees">
  3 + <el-row class="operation-row">
  4 + <el-col :span="24">
  5 + <el-button type="primary" size="small" @click="handleQuery" class="query-btn">
  6 + {{ $t('common.query') }}
  7 + </el-button>
  8 + <el-button type="primary" size="small" @click="openAddModal" class="add-btn">
  9 + <i class="el-icon-plus"></i>
  10 + {{ $t('common.add') }}
  11 + </el-button>
  12 + </el-col>
  13 + </el-row>
  14 +
  15 + <el-table :data="tableData" border style="width: 100%" v-loading="loading">
  16 + <el-table-column prop="crfId" :label="$t('couponRuleFee.id')" align="center" width="100">
  17 + </el-table-column>
  18 + <el-table-column prop="feeConfigName" :label="$t('couponRuleFee.fee')" align="center">
  19 + </el-table-column>
  20 + <el-table-column :label="$t('couponRuleFee.payTime')" align="center">
  21 + <template slot-scope="scope">
  22 + {{ scope.row.payStartTime }} ~ {{ scope.row.payEndTime }}
  23 + </template>
  24 + </el-table-column>
  25 + <el-table-column prop="payMonth" :label="$t('couponRuleFee.payMonth')" align="center">
  26 + </el-table-column>
  27 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  28 + <template slot-scope="scope">
  29 + <el-button size="mini" @click="openEditModal(scope.row)">
  30 + {{ $t('common.edit') }}
  31 + </el-button>
  32 + <el-button size="mini" type="danger" @click="openDeleteModal(scope.row)">
  33 + {{ $t('common.delete') }}
  34 + </el-button>
  35 + </template>
  36 + </el-table-column>
  37 + </el-table>
  38 +
  39 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  40 + :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  41 + layout="total, sizes, prev, pager, next, jumper" :total="pagination.total">
  42 + </el-pagination>
  43 +
  44 + <add-coupon-rule-fee ref="addCouponRuleFee" :rule-id="ruleId" @success="handleSuccess" />
  45 + </div>
  46 +</template>
  47 +
  48 +<script>
  49 +import { listCouponRuleFee } from '@/api/scm/couponRuleApi'
  50 +import AddCouponRuleFee from './AddCouponRuleFee'
  51 +import { getCommunityId } from '@/api/community/communityApi'
  52 +
  53 +export default {
  54 + name: 'CouponRuleFees',
  55 + components: {
  56 + AddCouponRuleFee
  57 + },
  58 + props: {
  59 + ruleId: {
  60 + type: String,
  61 + required: true
  62 + }
  63 + },
  64 + data() {
  65 + return {
  66 + loading: false,
  67 + tableData: [],
  68 + pagination: {
  69 + current: 1,
  70 + size: 10,
  71 + total: 0
  72 + }
  73 + }
  74 + },
  75 + watch: {
  76 + ruleId() {
  77 + this.getList()
  78 + }
  79 + },
  80 + methods: {
  81 + async getList() {
  82 + if (!this.ruleId) return
  83 +
  84 + this.loading = true
  85 + try {
  86 + const params = {
  87 + page: this.pagination.current,
  88 + row: this.pagination.size,
  89 + ruleId: this.ruleId,
  90 + communityId: getCommunityId()
  91 + }
  92 + const { data, total } = await listCouponRuleFee(params)
  93 + this.tableData = data
  94 + this.pagination.total = total
  95 + } catch (error) {
  96 + console.error('Failed to get coupon rule fees:', error)
  97 + } finally {
  98 + this.loading = false
  99 + }
  100 + },
  101 + handleQuery() {
  102 + this.pagination.current = 1
  103 + this.getList()
  104 + },
  105 + handleSizeChange(val) {
  106 + this.pagination.size = val
  107 + this.getList()
  108 + },
  109 + handleCurrentChange(val) {
  110 + this.pagination.current = val
  111 + this.getList()
  112 + },
  113 + openAddModal() {
  114 + this.$refs.addCouponRuleFee.open()
  115 + },
  116 + openEditModal(row) {
  117 + // TODO: Implement edit modal
  118 + this.$refs.editCouponRuleFee.open(row)
  119 +
  120 + this.$message.warning('Edit feature will be implemented soon')
  121 + },
  122 + openDeleteModal(row) {
  123 + this.$refs.deleteCouponRuleFee.open(row)
  124 +
  125 + // TODO: Implement delete modal
  126 + this.$message.warning('Delete feature will be implemented soon')
  127 + },
  128 + handleSuccess() {
  129 + this.getList()
  130 + }
  131 + }
  132 +}
  133 +</script>
  134 +
  135 +<style lang="scss" scoped>
  136 +.coupon-rule-fees {
  137 + .operation-row {
  138 + margin-bottom: 20px;
  139 +
  140 + .query-btn {
  141 + margin-right: 10px;
  142 + }
  143 + }
  144 +
  145 + .el-pagination {
  146 + margin-top: 20px;
  147 + text-align: right;
  148 + }
  149 +}
  150 +</style>
0 \ No newline at end of file 151 \ No newline at end of file
src/components/scm/DeleteCouponRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRule.deleteConfirm')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center>
  7 + <div class="text-center">
  8 + <p>{{ $t('couponRule.deleteRulePrompt') }}</p>
  9 + <p class="delete-item">{{ currentRule.ruleName }}</p>
  10 + </div>
  11 +
  12 + <span slot="footer" class="dialog-footer">
  13 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  14 + <el-button type="danger" @click="handleConfirm">{{ $t('common.confirmDelete') }}</el-button>
  15 + </span>
  16 + </el-dialog>
  17 +</template>
  18 +
  19 +<script>
  20 +import { deleteCouponRule } from '@/api/scm/couponRuleApi'
  21 +import { getCommunityId } from '@/api/community/communityApi'
  22 +
  23 +export default {
  24 + name: 'DeleteCouponRule',
  25 + data() {
  26 + return {
  27 + visible: false,
  28 + currentRule: {
  29 + ruleId: '',
  30 + ruleName: ''
  31 + }
  32 + }
  33 + },
  34 + methods: {
  35 + open(data) {
  36 + this.currentRule = {
  37 + ruleId: data.ruleId,
  38 + ruleName: data.ruleName,
  39 + communityId: getCommunityId()
  40 + }
  41 + this.visible = true
  42 + },
  43 + async handleConfirm() {
  44 + try {
  45 + await deleteCouponRule(this.currentRule)
  46 + this.$message.success(this.$t('common.deleteSuccess'))
  47 + this.visible = false
  48 + this.$emit('success')
  49 + } catch (error) {
  50 + console.error('Failed to delete coupon rule:', error)
  51 + }
  52 + }
  53 + }
  54 +}
  55 +</script>
  56 +
  57 +<style lang="scss" scoped>
  58 +.text-center {
  59 + text-align: center;
  60 +
  61 + .delete-item {
  62 + font-weight: bold;
  63 + color: #f56c6c;
  64 + margin-top: 10px;
  65 + }
  66 +}
  67 +</style>
0 \ No newline at end of file 68 \ No newline at end of file
src/components/scm/DeleteCouponRuleCpps.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRuleCpps.deleteConfirm')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center>
  7 + <div class="text-center">
  8 + <p>{{ $t('couponRuleCpps.deletePrompt') }}</p>
  9 + <p class="delete-item">{{ currentItem.couponName }}</p>
  10 + </div>
  11 +
  12 + <span slot="footer" class="dialog-footer">
  13 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  14 + <el-button type="danger" @click="handleConfirm">{{ $t('common.confirmDelete') }}</el-button>
  15 + </span>
  16 + </el-dialog>
  17 +</template>
  18 +
  19 +<script>
  20 +import { deleteCouponRuleCpps } from '@/api/scm/couponRuleApi'
  21 +import { getCommunityId } from '@/api/community/communityApi'
  22 +
  23 +export default {
  24 + name: 'DeleteCouponRuleCpps',
  25 + data() {
  26 + return {
  27 + visible: false,
  28 + currentItem: {
  29 + crcId: '',
  30 + couponName: ''
  31 + }
  32 + }
  33 + },
  34 + methods: {
  35 + open(row) {
  36 + this.currentItem = {
  37 + crcId: row.crcId,
  38 + couponName: row.couponName,
  39 + communityId: getCommunityId()
  40 + }
  41 + this.visible = true
  42 + },
  43 + async handleConfirm() {
  44 + try {
  45 + await deleteCouponRuleCpps({
  46 + crcId: this.currentItem.crcId,
  47 + communityId: this.currentItem.communityId
  48 + })
  49 + this.$message.success(this.$t('common.deleteSuccess'))
  50 + this.visible = false
  51 + this.$emit('success')
  52 + } catch (error) {
  53 + console.error('Failed to delete coupon rule cpps:', error)
  54 + }
  55 + }
  56 + }
  57 +}
  58 +</script>
  59 +
  60 +<style lang="scss" scoped>
  61 +.text-center {
  62 + text-align: center;
  63 +
  64 + .delete-item {
  65 + font-weight: bold;
  66 + color: #f56c6c;
  67 + margin-top: 10px;
  68 + }
  69 +}
  70 +</style>
0 \ No newline at end of file 71 \ No newline at end of file
src/components/scm/DeleteCouponRuleFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRuleFee.deleteConfirm')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center
  7 + @close="handleClose">
  8 + <div class="text-center">
  9 + <p>{{ $t('couponRuleFee.deletePrompt') }}</p>
  10 + <p class="delete-item">{{ currentItem.feeConfigName }}</p>
  11 + <p class="delete-info">
  12 + {{ currentItem.payStartTime }} ~ {{ currentItem.payEndTime }}
  13 + </p>
  14 + </div>
  15 +
  16 + <span slot="footer" class="dialog-footer">
  17 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  18 + <el-button
  19 + type="danger"
  20 + @click="handleConfirm"
  21 + :loading="loading">
  22 + {{ $t('common.confirmDelete') }}
  23 + </el-button>
  24 + </span>
  25 + </el-dialog>
  26 +</template>
  27 +
  28 +<script>
  29 +import { deleteCouponRuleFee } from '@/api/scm/couponRuleApi'
  30 +import { getCommunityId } from '@/api/community/communityApi'
  31 +
  32 +export default {
  33 + name: 'DeleteCouponRuleFee',
  34 + data() {
  35 + return {
  36 + visible: false,
  37 + loading: false,
  38 + currentItem: {
  39 + crfId: '',
  40 + feeConfigName: '',
  41 + payStartTime: '',
  42 + payEndTime: '',
  43 + communityId: ''
  44 + }
  45 + }
  46 + },
  47 + methods: {
  48 + open(row) {
  49 + this.currentItem = {
  50 + crfId: row.crfId,
  51 + feeConfigName: row.feeConfigName,
  52 + payStartTime: row.payStartTime,
  53 + payEndTime: row.payEndTime,
  54 + communityId: getCommunityId()
  55 + }
  56 + this.visible = true
  57 + },
  58 + handleClose() {
  59 + this.loading = false
  60 + },
  61 + async handleConfirm() {
  62 + this.loading = true
  63 + try {
  64 + await deleteCouponRuleFee({
  65 + crfId: this.currentItem.crfId,
  66 + communityId: this.currentItem.communityId
  67 + })
  68 + this.$message.success(this.$t('common.deleteSuccess'))
  69 + this.visible = false
  70 + this.$emit('success')
  71 + } catch (error) {
  72 + this.$message.error(this.$t('common.deleteFailed'))
  73 + console.error('Failed to delete coupon rule fee:', error)
  74 + } finally {
  75 + this.loading = false
  76 + }
  77 + }
  78 + }
  79 +}
  80 +</script>
  81 +
  82 +<style lang="scss" scoped>
  83 +.text-center {
  84 + text-align: center;
  85 +
  86 + .delete-item {
  87 + font-weight: bold;
  88 + color: #f56c6c;
  89 + margin: 10px 0;
  90 + }
  91 +
  92 + .delete-info {
  93 + color: #909399;
  94 + font-size: 12px;
  95 + }
  96 +}
  97 +</style>
0 \ No newline at end of file 98 \ No newline at end of file
src/components/scm/EditCouponRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRule.editRule')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  8 + <el-form-item :label="$t('couponRule.ruleName')" prop="ruleName">
  9 + <el-input v-model="form.ruleName" :placeholder="$t('couponRule.ruleNamePlaceholder')" />
  10 + </el-form-item>
  11 +
  12 + <el-form-item :label="$t('couponRule.remark')" prop="remark">
  13 + <el-input
  14 + type="textarea"
  15 + :rows="3"
  16 + v-model="form.remark"
  17 + :placeholder="$t('couponRule.remarkPlaceholder')" />
  18 + </el-form-item>
  19 + </el-form>
  20 +
  21 + <span slot="footer" class="dialog-footer">
  22 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  23 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  24 + </span>
  25 + </el-dialog>
  26 +</template>
  27 +
  28 +<script>
  29 +import { updateCouponRule } from '@/api/scm/couponRuleApi'
  30 +import { getCommunityId } from '@/api/community/communityApi'
  31 +
  32 +export default {
  33 + name: 'EditCouponRule',
  34 + data() {
  35 + return {
  36 + visible: false,
  37 + form: {
  38 + ruleId: '',
  39 + ruleName: '',
  40 + remark: '',
  41 + communityId: ''
  42 + },
  43 + rules: {
  44 + ruleName: [
  45 + { required: true, message: this.$t('couponRule.ruleNameRequired'), trigger: 'blur' },
  46 + { max: 64, message: this.$t('couponRule.ruleNameMaxLength'), trigger: 'blur' }
  47 + ],
  48 + remark: [
  49 + { max: 512, message: this.$t('couponRule.remarkMaxLength'), trigger: 'blur' }
  50 + ],
  51 + ruleId: [
  52 + { required: true, message: this.$t('couponRule.ruleIdRequired'), trigger: 'blur' }
  53 + ]
  54 + }
  55 + }
  56 + },
  57 + methods: {
  58 + open(data) {
  59 + this.form = {
  60 + ruleId: data.ruleId,
  61 + ruleName: data.ruleName,
  62 + remark: data.remark,
  63 + communityId: getCommunityId()
  64 + }
  65 + this.visible = true
  66 + },
  67 + handleClose() {
  68 + this.$refs.form.resetFields()
  69 + },
  70 + handleSubmit() {
  71 + this.$refs.form.validate(async valid => {
  72 + if (valid) {
  73 + try {
  74 + await updateCouponRule(this.form)
  75 + this.$message.success(this.$t('common.editSuccess'))
  76 + this.visible = false
  77 + this.$emit('success')
  78 + } catch (error) {
  79 + console.error('Failed to edit coupon rule:', error)
  80 + }
  81 + }
  82 + })
  83 + }
  84 + }
  85 +}
  86 +</script>
  87 +
  88 +<style lang="scss" scoped>
  89 +.el-dialog {
  90 + .el-form {
  91 + padding: 0 20px;
  92 +
  93 + .el-input, .el-textarea {
  94 + width: 100%;
  95 + }
  96 + }
  97 +}
  98 +</style>
0 \ No newline at end of file 99 \ No newline at end of file
src/components/scm/EditCouponRuleCpps.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponRuleCpps.editCoupon')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form
  8 + ref="form"
  9 + :model="form"
  10 + :rules="rules"
  11 + label-width="120px">
  12 + <el-form-item
  13 + :label="$t('couponRuleCpps.coupon')"
  14 + prop="cppId">
  15 + <el-select
  16 + v-model="form.cppId"
  17 + :placeholder="$t('couponRuleCpps.couponPlaceholder')"
  18 + style="width: 100%">
  19 + <el-option
  20 + v-for="item in couponOptions"
  21 + :key="item.cppId"
  22 + :label="item.couponName"
  23 + :value="item.cppId">
  24 + </el-option>
  25 + </el-select>
  26 + </el-form-item>
  27 +
  28 + <el-form-item
  29 + :label="$t('couponRuleCpps.quantity')"
  30 + prop="quantity">
  31 + <el-input
  32 + v-model="form.quantity"
  33 + :placeholder="$t('couponRuleCpps.quantityPlaceholder')" />
  34 + </el-form-item>
  35 +
  36 + <el-form-item
  37 + :label="$t('couponRuleCpps.frequency')"
  38 + prop="giftFrequency">
  39 + <el-select
  40 + v-model="form.giftFrequency"
  41 + :placeholder="$t('couponRuleCpps.frequencyPlaceholder')"
  42 + style="width: 100%">
  43 + <el-option
  44 + v-for="item in frequencyOptions"
  45 + :key="item.value"
  46 + :label="item.label"
  47 + :value="item.value">
  48 + </el-option>
  49 + </el-select>
  50 + </el-form-item>
  51 + </el-form>
  52 +
  53 + <span slot="footer" class="dialog-footer">
  54 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  55 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  56 + </span>
  57 + </el-dialog>
  58 +</template>
  59 +
  60 +<script>
  61 +import { updateCouponRuleCpps, listCouponPropertyPool } from '@/api/scm/couponRuleApi'
  62 +import { getCommunityId } from '@/api/community/communityApi'
  63 +
  64 +export default {
  65 + name: 'EditCouponRuleCpps',
  66 + data() {
  67 + return {
  68 + visible: false,
  69 + form: {
  70 + crcId: '',
  71 + cppId: '',
  72 + quantity: '',
  73 + giftFrequency: '',
  74 + communityId: ''
  75 + },
  76 + rules: {
  77 + crcId: [
  78 + { required: true, message: this.$t('couponRuleCpps.idRequired'), trigger: 'blur' }
  79 + ],
  80 + cppId: [
  81 + { required: true, message: this.$t('couponRuleCpps.couponRequired'), trigger: 'change' }
  82 + ],
  83 + quantity: [
  84 + { required: true, message: this.$t('couponRuleCpps.quantityRequired'), trigger: 'blur' },
  85 + { pattern: /^[1-9]\d*$/, message: this.$t('couponRuleCpps.quantityPattern'), trigger: 'blur' }
  86 + ],
  87 + giftFrequency: [
  88 + { required: true, message: this.$t('couponRuleCpps.frequencyRequired'), trigger: 'change' }
  89 + ]
  90 + },
  91 + couponOptions: [],
  92 + frequencyOptions: [
  93 + { value: '100301', label: this.$t('couponRuleCpps.once') },
  94 + { value: '100302', label: this.$t('couponRuleCpps.monthly') }
  95 + ]
  96 + }
  97 + },
  98 + methods: {
  99 + open(row) {
  100 + this.form = {
  101 + crcId: row.crcId,
  102 + cppId: row.cppId,
  103 + quantity: row.quantity,
  104 + giftFrequency: row.giftFrequency,
  105 + communityId: getCommunityId()
  106 + }
  107 + this.getCouponOptions()
  108 + this.visible = true
  109 + },
  110 + async getCouponOptions() {
  111 + try {
  112 + const params = {
  113 + page: 1,
  114 + row: 100,
  115 + communityId: getCommunityId()
  116 + }
  117 + const { data } = await listCouponPropertyPool(params)
  118 + this.couponOptions = data
  119 + } catch (error) {
  120 + console.error('Failed to get coupon options:', error)
  121 + }
  122 + },
  123 + handleClose() {
  124 + this.$refs.form.resetFields()
  125 + },
  126 + handleSubmit() {
  127 + this.$refs.form.validate(async valid => {
  128 + if (valid) {
  129 + try {
  130 + await updateCouponRuleCpps(this.form)
  131 + this.$message.success(this.$t('common.editSuccess'))
  132 + this.visible = false
  133 + this.$emit('success')
  134 + } catch (error) {
  135 + console.error('Failed to edit coupon rule cpps:', error)
  136 + }
  137 + }
  138 + })
  139 + }
  140 + }
  141 +}
  142 +</script>
  143 +
  144 +<style lang="scss" scoped>
  145 +.el-dialog {
  146 + .el-form {
  147 + padding: 0 20px;
  148 +
  149 + .el-input, .el-select {
  150 + width: 100%;
  151 + }
  152 + }
  153 +}
  154 +</style>
0 \ No newline at end of file 155 \ No newline at end of file
src/components/scm/addCouponPropertyPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponPropertyPoolManage.add.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + >
  14 + <el-form-item
  15 + :label="$t('couponPropertyPoolManage.add.couponName')"
  16 + prop="couponName"
  17 + >
  18 + <el-input
  19 + v-model="formData.couponName"
  20 + :placeholder="$t('couponPropertyPoolManage.add.couponNamePlaceholder')"
  21 + />
  22 + </el-form-item>
  23 +
  24 + <el-form-item
  25 + :label="$t('couponPropertyPoolManage.add.toType')"
  26 + prop="toType"
  27 + >
  28 + <el-select
  29 + v-model="formData.toType"
  30 + :placeholder="$t('couponPropertyPoolManage.add.toTypePlaceholder')"
  31 + style="width:100%"
  32 + @change="handleToTypeChange"
  33 + >
  34 + <el-option
  35 + v-for="item in toTypeOptions"
  36 + :key="item.value"
  37 + :label="item.label"
  38 + :value="item.value"
  39 + />
  40 + </el-select>
  41 + </el-form-item>
  42 +
  43 + <el-form-item
  44 + v-for="(item, index) in formData.toTypes"
  45 + :key="index"
  46 + :label="item.name"
  47 + >
  48 + <el-input
  49 + v-model="item.columnValue"
  50 + :placeholder="item.remark"
  51 + />
  52 + </el-form-item>
  53 +
  54 + <el-form-item
  55 + :label="$t('couponPropertyPoolManage.add.stock')"
  56 + prop="stock"
  57 + >
  58 + <el-input
  59 + v-model="formData.stock"
  60 + :placeholder="$t('couponPropertyPoolManage.add.stockPlaceholder')"
  61 + />
  62 + </el-form-item>
  63 +
  64 + <el-form-item
  65 + :label="$t('couponPropertyPoolManage.add.validityDay')"
  66 + prop="validityDay"
  67 + >
  68 + <el-input
  69 + v-model="formData.validityDay"
  70 + :placeholder="$t('couponPropertyPoolManage.add.validityDayPlaceholder')"
  71 + />
  72 + </el-form-item>
  73 +
  74 + <el-form-item
  75 + :label="$t('couponPropertyPoolManage.add.remark')"
  76 + prop="remark"
  77 + >
  78 + <el-input
  79 + v-model="formData.remark"
  80 + type="textarea"
  81 + :placeholder="$t('couponPropertyPoolManage.add.remarkPlaceholder')"
  82 + :rows="3"
  83 + />
  84 + </el-form-item>
  85 + </el-form>
  86 +
  87 + <span slot="footer" class="dialog-footer">
  88 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  89 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  90 + </span>
  91 + </el-dialog>
  92 +</template>
  93 +
  94 +<script>
  95 +import { saveCouponPropertyPool, listCouponKey } from '@/api/scm/couponPropertyPoolManageApi'
  96 +import { getCommunityId } from '@/api/community/communityApi'
  97 +
  98 +export default {
  99 + name: 'AddCouponPropertyPool',
  100 + data() {
  101 + return {
  102 + visible: false,
  103 + formData: {
  104 + couponName: '',
  105 + fromType: '2002',
  106 + toType: '',
  107 + stock: '',
  108 + validityDay: '',
  109 + remark: '',
  110 + toTypes: [],
  111 + communityId: getCommunityId()
  112 + },
  113 + rules: {
  114 + couponName: [
  115 + { required: true, message: this.$t('couponPropertyPoolManage.validate.couponNameRequired'), trigger: 'blur' },
  116 + { max: 64, message: this.$t('couponPropertyPoolManage.validate.couponNameMaxLength'), trigger: 'blur' }
  117 + ],
  118 + toType: [
  119 + { required: true, message: this.$t('couponPropertyPoolManage.validate.toTypeRequired'), trigger: 'change' }
  120 + ],
  121 + stock: [
  122 + { required: true, message: this.$t('couponPropertyPoolManage.validate.stockRequired'), trigger: 'blur' }
  123 + ],
  124 + validityDay: [
  125 + { required: true, message: this.$t('couponPropertyPoolManage.validate.validityDayRequired'), trigger: 'blur' }
  126 + ],
  127 + remark: [
  128 + { required: true, message: this.$t('couponPropertyPoolManage.validate.remarkRequired'), trigger: 'blur' }
  129 + ]
  130 + },
  131 + toTypeOptions: [
  132 + { value: '1011', label: this.$t('couponPropertyPoolManage.toType.shopping') },
  133 + { value: '4004', label: this.$t('couponPropertyPoolManage.toType.parking') },
  134 + { value: '5005', label: this.$t('couponPropertyPoolManage.toType.charging') }
  135 + ]
  136 + }
  137 + },
  138 + methods: {
  139 + open() {
  140 + this.visible = true
  141 + },
  142 + handleClose() {
  143 + this.$refs.form.resetFields()
  144 + this.formData.toTypes = []
  145 + },
  146 + async handleToTypeChange(val) {
  147 + if (!val) return
  148 + try {
  149 + const params = {
  150 + beanName: val,
  151 + page: 1,
  152 + row: 100
  153 + }
  154 + const { data } = await listCouponKey(params)
  155 + this.formData.toTypes = data
  156 + } catch (error) {
  157 + console.error('获取优惠券属性失败:', error)
  158 + }
  159 + },
  160 + handleSubmit() {
  161 + this.$refs.form.validate(async valid => {
  162 + if (valid) {
  163 + try {
  164 + await saveCouponPropertyPool(this.formData)
  165 + this.$message.success(this.$t('couponPropertyPoolManage.add.success'))
  166 + this.visible = false
  167 + this.$emit('success')
  168 + } catch (error) {
  169 + this.$message.error(error.message || this.$t('couponPropertyPoolManage.add.error'))
  170 + }
  171 + }
  172 + })
  173 + }
  174 + }
  175 +}
  176 +</script>
0 \ No newline at end of file 177 \ No newline at end of file
src/components/scm/deleteCouponPropertyPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponPropertyPoolManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div style="text-align:center;margin-bottom:20px">
  9 + <p>{{ $t('couponPropertyPoolManage.delete.confirmText') }}</p>
  10 + <p style="font-weight:bold">{{ formData.couponName }}</p>
  11 + </div>
  12 +
  13 + <span slot="footer" class="dialog-footer">
  14 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  15 + <el-button type="danger" @click="handleConfirm">{{ $t('common.confirm') }}</el-button>
  16 + </span>
  17 + </el-dialog>
  18 +</template>
  19 +
  20 +<script>
  21 +import { deleteCouponPropertyPool } from '@/api/scm/couponPropertyPoolManageApi'
  22 +import { getCommunityId } from '@/api/community/communityApi'
  23 +
  24 +export default {
  25 + name: 'DeleteCouponPropertyPool',
  26 + data() {
  27 + return {
  28 + visible: false,
  29 + formData: {
  30 + cppId: '',
  31 + couponName: '',
  32 + communityId: getCommunityId()
  33 + }
  34 + }
  35 + },
  36 + methods: {
  37 + open(row) {
  38 + this.formData = {
  39 + ...this.formData,
  40 + cppId: row.cppId,
  41 + couponName: row.couponName
  42 + }
  43 + this.visible = true
  44 + },
  45 + handleClose() {
  46 + this.formData.cppId = ''
  47 + this.formData.couponName = ''
  48 + },
  49 + async handleConfirm() {
  50 + try {
  51 + await deleteCouponPropertyPool(this.formData)
  52 + this.$message.success(this.$t('couponPropertyPoolManage.delete.success'))
  53 + this.visible = false
  54 + this.$emit('success')
  55 + } catch (error) {
  56 + this.$message.error(error.message || this.$t('couponPropertyPoolManage.delete.error'))
  57 + }
  58 + }
  59 + }
  60 +}
  61 +</script>
0 \ No newline at end of file 62 \ No newline at end of file
src/components/scm/editCouponPropertyPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponPropertyPoolManage.edit.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + >
  14 + <el-form-item
  15 + :label="$t('couponPropertyPoolManage.edit.couponName')"
  16 + prop="couponName"
  17 + >
  18 + <el-input
  19 + v-model="formData.couponName"
  20 + :placeholder="$t('couponPropertyPoolManage.edit.couponNamePlaceholder')"
  21 + />
  22 + </el-form-item>
  23 +
  24 + <el-form-item
  25 + :label="$t('couponPropertyPoolManage.edit.toType')"
  26 + prop="toType"
  27 + >
  28 + <el-select
  29 + v-model="formData.toType"
  30 + :placeholder="$t('couponPropertyPoolManage.edit.toTypePlaceholder')"
  31 + style="width:100%"
  32 + @change="handleToTypeChange"
  33 + >
  34 + <el-option
  35 + v-for="item in toTypeOptions"
  36 + :key="item.value"
  37 + :label="item.label"
  38 + :value="item.value"
  39 + />
  40 + </el-select>
  41 + </el-form-item>
  42 +
  43 + <el-form-item
  44 + v-for="(item, index) in formData.toTypes"
  45 + :key="index"
  46 + :label="item.name"
  47 + >
  48 + <el-input
  49 + v-model="item.columnValue"
  50 + :placeholder="item.remark"
  51 + />
  52 + </el-form-item>
  53 +
  54 + <el-form-item
  55 + :label="$t('couponPropertyPoolManage.edit.stock')"
  56 + prop="stock"
  57 + >
  58 + <el-input
  59 + v-model="formData.stock"
  60 + :placeholder="$t('couponPropertyPoolManage.edit.stockPlaceholder')"
  61 + />
  62 + </el-form-item>
  63 +
  64 + <el-form-item
  65 + :label="$t('couponPropertyPoolManage.edit.validityDay')"
  66 + prop="validityDay"
  67 + >
  68 + <el-input
  69 + v-model="formData.validityDay"
  70 + :placeholder="$t('couponPropertyPoolManage.edit.validityDayPlaceholder')"
  71 + />
  72 + </el-form-item>
  73 +
  74 + <el-form-item
  75 + :label="$t('couponPropertyPoolManage.edit.remark')"
  76 + prop="remark"
  77 + >
  78 + <el-input
  79 + v-model="formData.remark"
  80 + type="textarea"
  81 + :placeholder="$t('couponPropertyPoolManage.edit.remarkPlaceholder')"
  82 + :rows="3"
  83 + />
  84 + </el-form-item>
  85 + </el-form>
  86 +
  87 + <span slot="footer" class="dialog-footer">
  88 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  89 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  90 + </span>
  91 + </el-dialog>
  92 +</template>
  93 +
  94 +<script>
  95 +import { updateCouponPropertyPool, listCouponKey } from '@/api/scm/couponPropertyPoolManageApi'
  96 +import { getCommunityId } from '@/api/community/communityApi'
  97 +
  98 +export default {
  99 + name: 'EditCouponPropertyPool',
  100 + data() {
  101 + return {
  102 + visible: false,
  103 + formData: {
  104 + cppId: '',
  105 + couponName: '',
  106 + fromType: '2002',
  107 + toType: '',
  108 + stock: '',
  109 + validityDay: '',
  110 + remark: '',
  111 + toTypes: [],
  112 + communityId: getCommunityId()
  113 + },
  114 + rules: {
  115 + couponName: [
  116 + { required: true, message: this.$t('couponPropertyPoolManage.validate.couponNameRequired'), trigger: 'blur' },
  117 + { max: 64, message: this.$t('couponPropertyPoolManage.validate.couponNameMaxLength'), trigger: 'blur' }
  118 + ],
  119 + toType: [
  120 + { required: true, message: this.$t('couponPropertyPoolManage.validate.toTypeRequired'), trigger: 'change' }
  121 + ],
  122 + stock: [
  123 + { required: true, message: this.$t('couponPropertyPoolManage.validate.stockRequired'), trigger: 'blur' }
  124 + ],
  125 + validityDay: [
  126 + { required: true, message: this.$t('couponPropertyPoolManage.validate.validityDayRequired'), trigger: 'blur' }
  127 + ],
  128 + remark: [
  129 + { required: true, message: this.$t('couponPropertyPoolManage.validate.remarkRequired'), trigger: 'blur' }
  130 + ],
  131 + cppId: [
  132 + { required: true, message: this.$t('couponPropertyPoolManage.validate.cppIdRequired'), trigger: 'blur' }
  133 + ]
  134 + },
  135 + toTypeOptions: [
  136 + { value: '1011', label: this.$t('couponPropertyPoolManage.toType.shopping') },
  137 + { value: '2002', label: this.$t('couponPropertyPoolManage.toType.payment') },
  138 + { value: '3003', label: this.$t('couponPropertyPoolManage.toType.repair') },
  139 + { value: '4004', label: this.$t('couponPropertyPoolManage.toType.parking') },
  140 + { value: '5005', label: this.$t('couponPropertyPoolManage.toType.charging') }
  141 + ]
  142 + }
  143 + },
  144 + methods: {
  145 + open(row) {
  146 + this.formData = {
  147 + ...this.formData,
  148 + ...row,
  149 + toType: row.toType || ''
  150 + }
  151 + this.formData.toTypes = row.configs || []
  152 + this.visible = true
  153 + },
  154 + handleClose() {
  155 + this.$refs.form.resetFields()
  156 + this.formData.toTypes = []
  157 + },
  158 + async handleToTypeChange(val) {
  159 + if (!val) return
  160 + try {
  161 + const params = {
  162 + beanName: val,
  163 + page: 1,
  164 + row: 100
  165 + }
  166 + const { data } = await listCouponKey(params)
  167 + this.formData.toTypes = data
  168 + } catch (error) {
  169 + console.error('获取优惠券属性失败:', error)
  170 + }
  171 + },
  172 + handleSubmit() {
  173 + this.$refs.form.validate(async valid => {
  174 + if (valid) {
  175 + try {
  176 + await updateCouponPropertyPool(this.formData)
  177 + this.$message.success(this.$t('couponPropertyPoolManage.edit.success'))
  178 + this.visible = false
  179 + this.$emit('success')
  180 + } catch (error) {
  181 + this.$message.error(error.message || this.$t('couponPropertyPoolManage.edit.error'))
  182 + }
  183 + }
  184 + })
  185 + }
  186 + }
  187 +}
  188 +</script>
0 \ No newline at end of file 189 \ No newline at end of file
src/components/scm/giftCouponPropertyPool.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('couponPropertyPoolManage.gift.title')"
  4 + :visible.sync="visible"
  5 + width="40%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + >
  14 + <el-form-item
  15 + :label="$t('couponPropertyPoolManage.gift.couponName')"
  16 + >
  17 + <el-input
  18 + v-model="formData.couponName"
  19 + disabled
  20 + />
  21 + </el-form-item>
  22 +
  23 + <el-form-item
  24 + :label="$t('couponPropertyPoolManage.gift.giftCount')"
  25 + prop="giftCount"
  26 + >
  27 + <el-input
  28 + v-model="formData.giftCount"
  29 + type="number"
  30 + :placeholder="$t('couponPropertyPoolManage.gift.giftCountPlaceholder')"
  31 + />
  32 + </el-form-item>
  33 +
  34 + <el-form-item
  35 + :label="$t('couponPropertyPoolManage.gift.tel')"
  36 + prop="tel"
  37 + >
  38 + <el-input
  39 + v-model="formData.tel"
  40 + :placeholder="$t('couponPropertyPoolManage.gift.telPlaceholder')"
  41 + />
  42 + </el-form-item>
  43 + </el-form>
  44 +
  45 + <span slot="footer" class="dialog-footer">
  46 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  47 + <el-button type="primary" @click="handleSubmit">{{ $t('couponPropertyPoolManage.gift.submit') }}</el-button>
  48 + </span>
  49 + </el-dialog>
  50 +</template>
  51 +
  52 +<script>
  53 +import { giftCouponProperty } from '@/api/scm/couponPropertyPoolManageApi'
  54 +import { getCommunityId } from '@/api/community/communityApi'
  55 +
  56 +export default {
  57 + name: 'GiftCouponPropertyPool',
  58 + data() {
  59 + return {
  60 + visible: false,
  61 + formData: {
  62 + cppId: '',
  63 + couponName: '',
  64 + giftCount: '',
  65 + tel: '',
  66 + communityId: getCommunityId()
  67 + },
  68 + rules: {
  69 + cppId: [
  70 + { required: true, message: this.$t('couponPropertyPoolManage.validate.cppIdRequired'), trigger: 'blur' }
  71 + ],
  72 + giftCount: [
  73 + { required: true, message: this.$t('couponPropertyPoolManage.validate.giftCountRequired'), trigger: 'blur' }
  74 + ],
  75 + tel: [
  76 + { required: true, message: this.$t('couponPropertyPoolManage.validate.telRequired'), trigger: 'blur' }
  77 + ]
  78 + }
  79 + }
  80 + },
  81 + methods: {
  82 + open(row) {
  83 + this.formData = {
  84 + ...this.formData,
  85 + cppId: row.cppId,
  86 + couponName: row.couponName
  87 + }
  88 + this.visible = true
  89 + },
  90 + handleClose() {
  91 + this.$refs.form.resetFields()
  92 + },
  93 + handleSubmit() {
  94 + this.$refs.form.validate(async valid => {
  95 + if (valid) {
  96 + try {
  97 + await giftCouponProperty(this.formData)
  98 + this.$message.success(this.$t('couponPropertyPoolManage.gift.success'))
  99 + this.visible = false
  100 + this.$emit('success')
  101 + } catch (error) {
  102 + this.$message.error(error.message || this.$t('couponPropertyPoolManage.gift.error'))
  103 + }
  104 + }
  105 + })
  106 + }
  107 + }
  108 +}
  109 +</script>
0 \ No newline at end of file 110 \ No newline at end of file
src/i18n/commonLang.js
@@ -48,6 +48,8 @@ export const messages = { @@ -48,6 +48,8 @@ export const messages = {
48 selectFile:'Select File', 48 selectFile:'Select File',
49 change:'Change', 49 change:'Change',
50 print:'Print', 50 print:'Print',
  51 + year:'Year',
  52 + month:'Month',
51 } 53 }
52 }, 54 },
53 zh: { 55 zh: {
@@ -99,6 +101,8 @@ export const messages = { @@ -99,6 +101,8 @@ export const messages = {
99 selectFile:'选择文件', 101 selectFile:'选择文件',
100 change:'变更', 102 change:'变更',
101 print:'打印', 103 print:'打印',
  104 + year:'年',
  105 + month:'月',
102 } 106 }
103 } 107 }
104 } 108 }
105 \ No newline at end of file 109 \ No newline at end of file
src/i18n/index.js
@@ -141,6 +141,7 @@ import { messages as reportI18n } from &#39;./reportI18n&#39; @@ -141,6 +141,7 @@ import { messages as reportI18n } from &#39;./reportI18n&#39;
141 import { messages as devI18n } from './devI18n' 141 import { messages as devI18n } from './devI18n'
142 import { messages as resourceI18n } from './resourceI18n' 142 import { messages as resourceI18n } from './resourceI18n'
143 import { messages as carI18n } from './carI18n' 143 import { messages as carI18n } from './carI18n'
  144 +import { messages as scmI18n } from './scmI18n'
144 145
145 Vue.use(VueI18n) 146 Vue.use(VueI18n)
146 147
@@ -280,6 +281,7 @@ const messages = { @@ -280,6 +281,7 @@ const messages = {
280 ...devI18n.en, 281 ...devI18n.en,
281 ...resourceI18n.en, 282 ...resourceI18n.en,
282 ...carI18n.en, 283 ...carI18n.en,
  284 + ...scmI18n.en,
283 }, 285 },
284 zh: { 286 zh: {
285 ...loginMessages.zh, 287 ...loginMessages.zh,
@@ -413,6 +415,7 @@ const messages = { @@ -413,6 +415,7 @@ const messages = {
413 ...devI18n.zh, 415 ...devI18n.zh,
414 ...resourceI18n.zh, 416 ...resourceI18n.zh,
415 ...carI18n.zh, 417 ...carI18n.zh,
  418 + ...scmI18n.zh,
416 } 419 }
417 } 420 }
418 421
src/i18n/reportI18n.js
@@ -16,6 +16,9 @@ import { messages as reportRepairMessages } from &#39;../views/report/reportRepairLa @@ -16,6 +16,9 @@ import { messages as reportRepairMessages } from &#39;../views/report/reportRepairLa
16 import { messages as reportNoFeeRoomMessages } from '../views/report/reportNoFeeRoomLang' 16 import { messages as reportNoFeeRoomMessages } from '../views/report/reportNoFeeRoomLang'
17 import { messages as reportQuestionAnswerDetailMessages } from '../views/report/reportQuestionAnswerDetailLang' 17 import { messages as reportQuestionAnswerDetailMessages } from '../views/report/reportQuestionAnswerDetailLang'
18 import { messages as reportOwnerPayFeeMessages } from '../views/report/reportOwnerPayFeeLang' 18 import { messages as reportOwnerPayFeeMessages } from '../views/report/reportOwnerPayFeeLang'
  19 +import { messages as reportHuaningMessages } from '../views/report/reportHuaningLang'
  20 +import { messages as reportPayFeeDepositMessages } from '../views/report/reportPayFeeDepositLang'
  21 +import { messages as commonReportMessages } from '../views/report/commonReportLang'
19 22
20 export const messages = { 23 export const messages = {
21 en: { 24 en: {
@@ -36,6 +39,9 @@ export const messages = { @@ -36,6 +39,9 @@ export const messages = {
36 ...reportNoFeeRoomMessages.en, 39 ...reportNoFeeRoomMessages.en,
37 ...reportQuestionAnswerDetailMessages.en, 40 ...reportQuestionAnswerDetailMessages.en,
38 ...reportOwnerPayFeeMessages.en, 41 ...reportOwnerPayFeeMessages.en,
  42 + ...reportHuaningMessages.en,
  43 + ...reportPayFeeDepositMessages.en,
  44 + ...commonReportMessages.en,
39 }, 45 },
40 zh: { 46 zh: {
41 ...reportCustomComponentRelManageMessages.zh, 47 ...reportCustomComponentRelManageMessages.zh,
@@ -54,5 +60,8 @@ export const messages = { @@ -54,5 +60,8 @@ export const messages = {
54 ...reportNoFeeRoomMessages.zh, 60 ...reportNoFeeRoomMessages.zh,
55 ...reportQuestionAnswerDetailMessages.zh, 61 ...reportQuestionAnswerDetailMessages.zh,
56 ...reportOwnerPayFeeMessages.zh, 62 ...reportOwnerPayFeeMessages.zh,
  63 + ...reportHuaningMessages.zh,
  64 + ...reportPayFeeDepositMessages.zh,
  65 + ...commonReportMessages.zh,
57 } 66 }
58 } 67 }
59 \ No newline at end of file 68 \ No newline at end of file
src/i18n/scmI18n.js 0 → 100644
  1 +import { messages as couponMarketMessages } from '../views/scm/couponMarketLang'
  2 +import { messages as couponPropertyPoolManageMessages } from '../views/scm/couponPropertyPoolManageLang'
  3 +import { messages as couponRuleMessages } from '../views/scm/couponRuleLang'
  4 +
  5 +export const messages = {
  6 + en: {
  7 +
  8 + ...couponMarketMessages.en,
  9 + ...couponPropertyPoolManageMessages.en,
  10 + ...couponRuleMessages.en,
  11 + },
  12 + zh: {
  13 + ...couponMarketMessages.zh,
  14 + ...couponPropertyPoolManageMessages.zh,
  15 + ...couponRuleMessages.zh,
  16 + }
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
src/router/index.js
@@ -11,6 +11,7 @@ import reportRouter from &#39;./reportRouter&#39; @@ -11,6 +11,7 @@ import reportRouter from &#39;./reportRouter&#39;
11 import devRouter from './devRouter' 11 import devRouter from './devRouter'
12 import resourceRouter from './resourceRouter' 12 import resourceRouter from './resourceRouter'
13 import carRouter from './carRouter' 13 import carRouter from './carRouter'
  14 +import scmRouter from './scmRouter'
14 15
15 Vue.use(VueRouter) 16 Vue.use(VueRouter)
16 17
@@ -630,6 +631,7 @@ const routes = [ @@ -630,6 +631,7 @@ const routes = [
630 ...devRouter, 631 ...devRouter,
631 ...resourceRouter, 632 ...resourceRouter,
632 ...carRouter, 633 ...carRouter,
  634 + ...scmRouter,
633 // 其他子路由可以在这里添加 635 // 其他子路由可以在这里添加
634 ] 636 ]
635 }, 637 },
src/router/reportRouter.js
@@ -50,9 +50,23 @@ export default [ @@ -50,9 +50,23 @@ export default [
50 component: () => import('@/views/report/reportQuestionAnswerDetailList.vue') 50 component: () => import('@/views/report/reportQuestionAnswerDetailList.vue')
51 }, 51 },
52 { 52 {
53 - path:'/pages/property/reportOwnerPayFee',  
54 - name:'/pages/property/reportOwnerPayFee', 53 + path: '/pages/property/reportOwnerPayFee',
  54 + name: '/pages/property/reportOwnerPayFee',
55 component: () => import('@/views/report/reportOwnerPayFeeList.vue') 55 component: () => import('@/views/report/reportOwnerPayFeeList.vue')
56 - },  
57 - 56 + },
  57 + {
  58 + path: '/pages/property/reportHuaning',
  59 + name: '/pages/property/reportHuaning',
  60 + component: () => import('@/views/report/reportHuaningList.vue')
  61 + },
  62 + {
  63 + path: '/pages/property/reportPayFeeDeposit',
  64 + name: '/pages/property/reportPayFeeDeposit',
  65 + component: () => import('@/views/report/reportPayFeeDepositList.vue')
  66 + },
  67 + {
  68 + path: '/pages/property/commonReport',
  69 + name: '/pages/property/commonReport',
  70 + component: () => import('@/views/report/commonReportList.vue')
  71 + },
58 ] 72 ]
59 \ No newline at end of file 73 \ No newline at end of file
src/router/scmRouter.js 0 → 100644
  1 +export default [
  2 + {
  3 + path: '/pages/scm/couponMarket',
  4 + name: '/pages/scm/couponMarket',
  5 + component: () => import('@/views/scm/couponMarketList.vue')
  6 + },
  7 + {
  8 + path: '/pages/scm/couponPropertyPoolManage',
  9 + name: '/pages/scm/couponPropertyPoolManage',
  10 + component: () => import('@/views/scm/couponPropertyPoolManageList.vue')
  11 + },
  12 + {
  13 + path:'/pages/scm/couponRule',
  14 + name:'/pages/scm/couponRule',
  15 + component: () => import('@/views/scm/couponRuleList.vue')
  16 + },
  17 +]
0 \ No newline at end of file 18 \ No newline at end of file
src/views/report/commonReportLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + commonReportTable: {
  4 + queryConditions: 'Query Conditions',
  5 + query: 'Query',
  6 + reset: 'Reset',
  7 + export: 'Export',
  8 + print: 'Print',
  9 + noData: 'No Data'
  10 + }
  11 + },
  12 + zh: {
  13 + commonReportTable: {
  14 + queryConditions: '查询条件',
  15 + query: '查询',
  16 + reset: '重置',
  17 + export: '导出',
  18 + print: '打印',
  19 + noData: '暂无数据'
  20 + }
  21 + }
  22 +}
0 \ No newline at end of file 23 \ No newline at end of file
src/views/report/commonReportList.vue 0 → 100644
  1 +<template>
  2 + <div class="common-report-container">
  3 + <el-row :gutter="20">
  4 + <el-col :span="4">
  5 + <el-card class="tree-card">
  6 + <ul class="report-list">
  7 + <li v-for="(item, index) in commonReportInfo.reportCustoms" :key="index"
  8 + :class="{ 'selected-item': commonReportInfo.switchValue === item.customId }" @click="swatch(item)">
  9 + {{ item.title }}
  10 + </li>
  11 + </ul>
  12 + </el-card>
  13 + </el-col>
  14 + <el-col :span="20">
  15 +
  16 + <common-report-table ref="reportTable" />
  17 + </el-col>
  18 + </el-row>
  19 + </div>
  20 +</template>
  21 +
  22 +<script>
  23 +import CommonReportTable from '@/components/report/commonReportTable'
  24 +import { listReportCustom } from '@/api/report/commonReportApi'
  25 +import { getCommunityId } from '@/api/community/communityApi'
  26 +
  27 +export default {
  28 + name: 'CommonReportList',
  29 + components: {
  30 + CommonReportTable
  31 + },
  32 + data() {
  33 + return {
  34 + commonReportInfo: {
  35 + groupId: '',
  36 + switchValue: '',
  37 + reportCustoms: []
  38 + },
  39 + communityId: ''
  40 + }
  41 + },
  42 + watch: {
  43 + '$route'(to, from) {
  44 + // 对路由变化作出响应...
  45 + console.log(to, from)
  46 + if (to.query.groupId !== from.query.groupId) {
  47 + this.commonReportInfo.groupId = to.query.groupId
  48 + this._loadReportCustom()
  49 + }
  50 + }
  51 + },
  52 + created() {
  53 + this.communityId = getCommunityId()
  54 + this.commonReportInfo.groupId = this.$route.query.groupId
  55 + this._loadReportCustom()
  56 + },
  57 + methods: {
  58 + swatch(value) {
  59 + this.commonReportInfo.switchValue = value.customId
  60 + this.$refs.reportTable.handleSwitch(value)
  61 + },
  62 + async _loadReportCustom() {
  63 + try {
  64 + const params = {
  65 + page: 1,
  66 + row: 50,
  67 + groupId: this.commonReportInfo.groupId
  68 + }
  69 + const { data } = await listReportCustom(params)
  70 + this.commonReportInfo.reportCustoms = data
  71 + if (data && data.length > 0) {
  72 + this.swatch(data[0])
  73 + }
  74 + } catch (error) {
  75 + console.error('Failed to load report custom:', error)
  76 + }
  77 + }
  78 + }
  79 +}
  80 +</script>
  81 +
  82 +<style lang="scss" scoped>
  83 +.common-report-container {
  84 + padding: 20px;
  85 +
  86 + .tree-card {
  87 + height: 100%;
  88 +
  89 + .report-list {
  90 + list-style: none;
  91 + padding: 0;
  92 + margin: 0;
  93 +
  94 + li {
  95 + padding: 10px;
  96 + margin-bottom: 5px;
  97 + text-align: center;
  98 + cursor: pointer;
  99 + border-radius: 4px;
  100 + transition: all 0.3s;
  101 +
  102 + &:hover {
  103 + background-color: #f5f7fa;
  104 + }
  105 +
  106 + &.selected-item {
  107 + background-color: #409eff;
  108 + color: white;
  109 + }
  110 + }
  111 + }
  112 + }
  113 +}
  114 +</style>
0 \ No newline at end of file 115 \ No newline at end of file
src/views/report/reportHuaningLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + reportHuaning: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + feeType: 'Please select fee type',
  7 + floor: 'Please select floor'
  8 + },
  9 + tab: {
  10 + oweFee: 'Uncollected Situation Report',
  11 + oweFeeDetail: 'Uncollected Details Report',
  12 + payFee: 'Current Month Collection Report'
  13 + }
  14 + },
  15 + reportHuaningOweFee: {
  16 + table: {
  17 + floorNum: 'Building Number',
  18 + totalOweAmount: 'Total Uncollected Amount (as of {date})',
  19 + oweAmount: 'Uncollected Amount',
  20 + preYearOweAmount: 'Uncollected Amount Before'
  21 + }
  22 + },
  23 + reportHuaningPayFee: {
  24 + table: {
  25 + floorNum: 'Building Number',
  26 + monthlyReceivable: 'Monthly Receivable',
  27 + monthReceived: 'Month Received',
  28 + monthReceivedPart1: 'Month Received belongs to {year} Year 1-{month} Month Part',
  29 + monthReceivedPart2: 'Month Received belongs to {year} Year {month} Month Part',
  30 + monthReceivedPart3: 'Month Received belongs to {nextMonth} Pre-collection Part',
  31 + monthReceivedPart4: 'Month Received belongs to Before {year} Year Part'
  32 + }
  33 + },
  34 + reportHuaningOweFeeDetail: {
  35 + table: {
  36 + roomNum: 'Room Number',
  37 + area: 'Area',
  38 + fee: 'Fee',
  39 + startTime: 'Fee Start Time',
  40 + endTime: 'Fee End Time',
  41 + totalOweAmount: 'Total Uncollected Amount',
  42 + oweAmount: 'Uncollected Amount',
  43 + preYearOweAmount: 'Uncollected Amount Before'
  44 + }
  45 + },
  46 + viewFeeDetail: {
  47 + title: 'Year Payment History',
  48 + table: {
  49 + cycle: 'Cycle (Unit: Month)',
  50 + receivableAmount: 'Receivable Amount (Unit: Yuan)',
  51 + receivedAmount: 'Received Amount (Unit: Yuan)',
  52 + payTime: 'Payment Time',
  53 + startTime: 'Payment Start Time',
  54 + endTime: 'Payment End Time',
  55 + status: 'Status',
  56 + remark: 'Remark'
  57 + }
  58 + }
  59 + },
  60 + zh: {
  61 + reportHuaning: {
  62 + search: {
  63 + title: '查询条件',
  64 + feeType: '请选择收费类型',
  65 + floor: '请选择楼栋'
  66 + },
  67 + tab: {
  68 + oweFee: '未收情况表',
  69 + oweFeeDetail: '未收明细表',
  70 + payFee: '当月收费情况表'
  71 + }
  72 + },
  73 + reportHuaningOweFee: {
  74 + table: {
  75 + floorNum: '楼栋号',
  76 + totalOweAmount: '总未收金额(截止{date})',
  77 + oweAmount: '未收金额',
  78 + preYearOweAmount: '年前未收金额'
  79 + }
  80 + },
  81 + reportHuaningPayFee: {
  82 + table: {
  83 + floorNum: '楼栋号',
  84 + monthlyReceivable: '每月应收',
  85 + monthReceived: '月实收',
  86 + monthReceivedPart1: '月实收中属于{year}年1-{month}月部分',
  87 + monthReceivedPart2: '月实收中属于{year}年{month}月部分',
  88 + monthReceivedPart3: '月实收中属于{nextMonth}起预收部分',
  89 + monthReceivedPart4: '月实收中属于{year}年前部分'
  90 + }
  91 + },
  92 + reportHuaningOweFeeDetail: {
  93 + table: {
  94 + roomNum: '房号',
  95 + area: '面积',
  96 + fee: '费用',
  97 + startTime: '费用开始时间',
  98 + endTime: '费用截止时间',
  99 + totalOweAmount: '总未收金额',
  100 + oweAmount: '未收金额',
  101 + preYearOweAmount: '年前未收金额'
  102 + }
  103 + },
  104 + viewFeeDetail: {
  105 + title: '年缴费历史',
  106 + table: {
  107 + cycle: '周期(单位:月)',
  108 + receivableAmount: '应收金额(单位:元)',
  109 + receivedAmount: '实收金额(单位:元)',
  110 + payTime: '缴费时间',
  111 + startTime: '缴费起始时间',
  112 + endTime: '缴费结束时间',
  113 + status: '状态',
  114 + remark: '备注'
  115 + }
  116 + }
  117 + }
  118 +}
0 \ No newline at end of file 119 \ No newline at end of file
src/views/report/reportHuaningList.vue 0 → 100644
  1 +<template>
  2 + <div class="report-huaning-container">
  3 + <el-row>
  4 + <el-col :span="24">
  5 + <el-card>
  6 + <div slot="header" class="flex justify-between">
  7 + <h5>{{ $t('reportHuaning.search.title') }}</h5>
  8 + </div>
  9 + <div class="ibox-content">
  10 + <el-row :gutter="20">
  11 + <!-- 费用类型 -->
  12 + <el-col :span="6">
  13 + <el-select v-model="reportHuaningInfo.conditions.feeTypeCd" @change="_changeReporficientFeeTypeCd"
  14 + style="width:100%" :placeholder="$t('reportHuaning.search.feeType')">
  15 + <el-option v-for="(item, index) in reportHuaningInfo.feeTypeCds" :key="index" :label="item.name"
  16 + :value="item.statusCd">
  17 + </el-option>
  18 + </el-select>
  19 + </el-col>
  20 +
  21 + <!-- 楼栋 -->
  22 + <el-col :span="6">
  23 + <el-select v-model="reportHuaningInfo.conditions.floorNum" style="width:100%"
  24 + :placeholder="$t('reportHuaning.search.floor')">
  25 + <el-option v-for="(item, index) in reportHuaningInfo.floors" :key="index" :label="item.floorNum"
  26 + :value="item.floorNum">
  27 + </el-option>
  28 + </el-select>
  29 + </el-col>
  30 +
  31 + <el-col :span="6">
  32 + <el-button type="primary" @click="_queryMethod">
  33 + <i class="el-icon-search"></i>
  34 + <span>{{ $t('common.search') }}</span>
  35 + </el-button>
  36 + <el-button @click="_resetMethod" style="margin-left: 20px;">
  37 + <i class="el-icon-refresh"></i>
  38 + <span>{{ $t('common.reset') }}</span>
  39 + </el-button>
  40 + </el-col>
  41 + </el-row>
  42 + </div>
  43 + </el-card>
  44 + </el-col>
  45 + </el-row>
  46 +
  47 + <el-card class="margin-top">
  48 + <div class="white-bg padding-lg">
  49 + <el-tabs v-model="reportHuaningInfo._currentTab" @tab-click="changeTab(reportHuaningInfo._currentTab)">
  50 + <el-tab-pane :label="$t('reportHuaning.tab.oweFee')" name="reportHuaningOweFee">
  51 + </el-tab-pane>
  52 + <el-tab-pane :label="$t('reportHuaning.tab.oweFeeDetail')" name="reportHuaningOweFeeDetail">
  53 + </el-tab-pane>
  54 + <el-tab-pane :label="$t('reportHuaning.tab.payFee')" name="reportHuaningPayFee">
  55 + </el-tab-pane>
  56 + </el-tabs>
  57 +
  58 + <div v-if="reportHuaningInfo._currentTab === 'reportHuaningOweFee'">
  59 + <report-huaning-owe-fee ref="reportHuaningOweFee"></report-huaning-owe-fee>
  60 + </div>
  61 + <div v-if="reportHuaningInfo._currentTab === 'reportHuaningPayFee'">
  62 + <report-huaning-pay-fee ref="reportHuaningPayFee"></report-huaning-pay-fee>
  63 + </div>
  64 + <div v-if="reportHuaningInfo._currentTab === 'reportHuaningOweFeeDetail'">
  65 + <report-huaning-owe-fee-detail ref="reportHuaningOweFeeDetail"></report-huaning-owe-fee-detail>
  66 + </div>
  67 + </div>
  68 + </el-card>
  69 +
  70 + <view-fee-detail ref="viewFeeDetail"></view-fee-detail>
  71 + </div>
  72 +</template>
  73 +
  74 +<script>
  75 +import { getDict } from '@/api/community/communityApi'
  76 +import { getCommunityId } from '@/api/community/communityApi'
  77 +import { listFloors } from '@/api/report/reportHuaningApi'
  78 +import ReportHuaningOweFee from '@/components/report/ReportHuaningOweFee'
  79 +import ReportHuaningPayFee from '@/components/report/ReportHuaningPayFee'
  80 +import ReportHuaningOweFeeDetail from '@/components/report/ReportHuaningOweFeeDetail'
  81 +import ViewFeeDetail from '@/components/report/viewFeeDetail'
  82 +
  83 +export default {
  84 + name: 'ReportHuaningList',
  85 + components: {
  86 + ReportHuaningOweFee,
  87 + ReportHuaningPayFee,
  88 + ReportHuaningOweFeeDetail,
  89 + ViewFeeDetail
  90 + },
  91 + data() {
  92 + return {
  93 + reportHuaningInfo: {
  94 + receivableAmount: '0',
  95 + noEnterRoomCount: '0',
  96 + roomCount: '0',
  97 + freeRoomCount: '0',
  98 + parkingSpaceCount: '0',
  99 + freeParkingSpaceCount: '0',
  100 + shopCount: '0',
  101 + freeShopCount: '0',
  102 + _currentTab: 'reportHuaningOweFee',
  103 + feeTypeCds: [],
  104 + feeConfigDtos: [],
  105 + floors: [],
  106 + moreCondition: false,
  107 + conditions: {
  108 + configId: '',
  109 + feeTypeCd: '',
  110 + floorNum: '',
  111 + year: new Date().getFullYear(),
  112 + month: new Date().getMonth() + 1
  113 + }
  114 + },
  115 + communityId: ''
  116 + }
  117 + },
  118 + created() {
  119 + this.communityId = getCommunityId()
  120 + this._initData()
  121 + this.changeTab(this.reportHuaningInfo._currentTab)
  122 + },
  123 + methods: {
  124 + async _initData() {
  125 + try {
  126 + // 获取费用类型字典
  127 + const feeTypes = await getDict('pay_fee_config', 'fee_type_cd')
  128 + this.reportHuaningInfo.feeTypeCds = feeTypes
  129 +
  130 + // 获取楼栋数据
  131 + const params = {
  132 + communityId: this.communityId,
  133 + row: 50,
  134 + page: 1
  135 + }
  136 + const floorData = await listFloors(params)
  137 + this.reportHuaningInfo.floors = floorData.apiFloorDataVoList
  138 + } catch (error) {
  139 + console.error('初始化数据失败:', error)
  140 + }
  141 + },
  142 + changeTab(tab) {
  143 + this.reportHuaningInfo._currentTab = tab
  144 + setTimeout(() => {
  145 + this.$refs[tab].initData(this.reportHuaningInfo.conditions)
  146 + },500)
  147 + },
  148 + _changeReporficientFeeTypeCd() {
  149 + // 费用类型变更处理
  150 + },
  151 + _queryMethod() {
  152 + this.$refs[`${this.reportHuaningInfo._currentTab}Ref`].initData(this.reportHuaningInfo.conditions)
  153 + },
  154 + _resetMethod() {
  155 + this.reportHuaningInfo.conditions = {
  156 + configId: '',
  157 + feeTypeCd: '',
  158 + floorNum: '',
  159 + year: new Date().getFullYear(),
  160 + month: new Date().getMonth() + 1
  161 + }
  162 + this._queryMethod()
  163 + },
  164 + _listFloorData() {
  165 + // 已迁移到_initData方法中
  166 + },
  167 + _moreCondition() {
  168 + this.reportHuaningInfo.moreCondition = !this.reportHuaningInfo.moreCondition
  169 + }
  170 + }
  171 +}
  172 +</script>
  173 +
  174 +<style lang="scss" scoped>
  175 +.report-huaning-container {
  176 + padding: 20px;
  177 +
  178 + .margin-top {
  179 + margin-top: 20px;
  180 + }
  181 +
  182 + .white-bg {
  183 + background-color: #fff;
  184 + }
  185 +
  186 + .padding-lg {
  187 + padding: 20px;
  188 + }
  189 +
  190 + .ibox-content {
  191 + padding: 15px 20px 20px 20px;
  192 + }
  193 +}
  194 +</style>
0 \ No newline at end of file 195 \ No newline at end of file
src/views/report/reportPayFeeDepositLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + reportPayFeeDeposit: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + floorName: 'Please select building',
  7 + choose: 'Choose',
  8 + unit: 'Unit',
  9 + unitPlaceholder: 'Please select unit',
  10 + roomNum: 'Please fill in room number',
  11 + feeId: 'Please enter fee ID',
  12 + feeName: 'Fee item name',
  13 + feeNamePlaceholder: 'Please select fee item name',
  14 + search: 'Search',
  15 + reset: 'Reset',
  16 + state: 'Payment status',
  17 + statePlaceholder: 'Please select payment status',
  18 + payerObjType: 'Payment object type',
  19 + payerObjTypePlaceholder: 'Please select payment object type',
  20 + startTime: 'Please select fee creation start time',
  21 + endTime: 'Please select fee creation end time',
  22 + detailState: 'Refund status',
  23 + detailStatePlaceholder: 'Please select refund status'
  24 + },
  25 + table: {
  26 + title: 'Deposit Report',
  27 + tooltip: 'Payment records of deposit type',
  28 + export: 'Export',
  29 + feeId: 'Fee ID',
  30 + roomNum: 'Room number',
  31 + owner: 'Owner',
  32 + feeType: 'Fee type',
  33 + feeName: 'Fee item',
  34 + startTime: 'Fee start time',
  35 + endTime: 'Fee end time',
  36 + createTime: 'Creation time',
  37 + payerObjType: 'Payment object type',
  38 + payerObjId: 'Payer ID',
  39 + amount: 'Receivable amount',
  40 + state: 'Status',
  41 + detailState: 'Refund status',
  42 + operation: 'Operation',
  43 + detail: 'Detail',
  44 + unpaid: 'Unpaid',
  45 + subtotal: 'Subtotal',
  46 + total: 'Total',
  47 + paid: 'Paid',
  48 + refunded: 'Refunded',
  49 + refundInProgress: 'Refund in progress',
  50 + refundFailed: 'Refund failed',
  51 + yuan: 'Yuan'
  52 + }
  53 + },
  54 + searchFloor: {
  55 + title: 'Building Selection',
  56 + floorId: 'Please enter building ID',
  57 + floorName: 'Please enter building name',
  58 + floorNum: 'Please enter building number',
  59 + search: 'Search',
  60 + reset: 'Reset',
  61 + table: {
  62 + floorId: 'Building ID',
  63 + floorName: 'Name',
  64 + floorNum: 'Number',
  65 + userName: 'Creator',
  66 + operation: 'Operation',
  67 + choose: 'Choose'
  68 + }
  69 + }
  70 + },
  71 + zh: {
  72 + reportPayFeeDeposit: {
  73 + search: {
  74 + title: '查询条件',
  75 + floorName: '请选择楼栋',
  76 + choose: '选择',
  77 + unit: '单元',
  78 + unitPlaceholder: '请选择单元',
  79 + roomNum: '请填写房屋编号',
  80 + feeId: '请输入费用ID',
  81 + feeName: '费用项名称',
  82 + feeNamePlaceholder: '请选择费用项名称',
  83 + search: '查询',
  84 + reset: '重置',
  85 + state: '收费状态',
  86 + statePlaceholder: '请选择收费状态',
  87 + payerObjType: '收费对象类型',
  88 + payerObjTypePlaceholder: '请选择收费对象类型',
  89 + startTime: '请选择费用创建开始时间',
  90 + endTime: '请选择费用创建结束时间',
  91 + detailState: '退费状态',
  92 + detailStatePlaceholder: '请选择退费状态'
  93 + },
  94 + table: {
  95 + title: '押金报表',
  96 + tooltip: '押金类记录的收费情况',
  97 + export: '导出',
  98 + feeId: '费用ID',
  99 + roomNum: '房号',
  100 + owner: '业主',
  101 + feeType: '费用类型',
  102 + feeName: '费用项',
  103 + startTime: '费用开始时间',
  104 + endTime: '费用结束时间',
  105 + createTime: '创建时间',
  106 + payerObjType: '付费对象类型',
  107 + payerObjId: '付款方ID',
  108 + amount: '应收金额',
  109 + state: '状态',
  110 + detailState: '退费状态',
  111 + operation: '操作',
  112 + detail: '详情',
  113 + unpaid: '未缴费',
  114 + subtotal: '小计',
  115 + total: '大计',
  116 + paid: '已收费',
  117 + refunded: '已退费',
  118 + refundInProgress: '退费中',
  119 + refundFailed: '退费失败',
  120 + yuan: '元'
  121 + }
  122 + },
  123 + searchFloor: {
  124 + title: '小区楼栋',
  125 + floorId: '请输入楼栋ID',
  126 + floorName: '请输入楼栋名称',
  127 + floorNum: '请输入楼栋编号',
  128 + search: '查询',
  129 + reset: '重置',
  130 + table: {
  131 + floorId: '楼栋ID',
  132 + floorName: '名称',
  133 + floorNum: '编号',
  134 + userName: '创建人',
  135 + operation: '操作',
  136 + choose: '选择'
  137 + }
  138 + }
  139 + }
  140 +}
0 \ No newline at end of file 141 \ No newline at end of file
src/views/report/reportPayFeeDepositList.vue 0 → 100644
  1 +<template>
  2 + <div class="report-pay-fee-deposit-container animated fadeInRight">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-card">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('reportPayFeeDeposit.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="24">
  10 + <el-row :gutter="20">
  11 + <el-col :span="4">
  12 + <el-input v-model="conditions.floorName" :placeholder="$t('reportPayFeeDeposit.search.floorName')"
  13 + class="search-item">
  14 + <el-button slot="append" icon="el-icon-search" @click="openChooseFloor">
  15 + {{ $t('reportPayFeeDeposit.search.choose') }}
  16 + </el-button>
  17 + </el-input>
  18 + </el-col>
  19 + <el-col :span="4">
  20 + <el-select v-model="conditions.unitId" :placeholder="$t('reportPayFeeDeposit.search.unit')"
  21 + class="search-item" style="width:100%">
  22 + <el-option :label="$t('reportPayFeeDeposit.search.unitPlaceholder')" value=""></el-option>
  23 + <el-option v-for="(unit, index) in roomUnits" :key="index"
  24 + :label="unit.unitNum + $t('reportPayFeeDeposit.search.unit')" :value="unit.unitId">
  25 + </el-option>
  26 + </el-select>
  27 + </el-col>
  28 + <el-col :span="4">
  29 + <el-input v-model="conditions.roomNum" :placeholder="$t('reportPayFeeDeposit.search.roomNum')"
  30 + class="search-item">
  31 + </el-input>
  32 + </el-col>
  33 + <el-col :span="4">
  34 + <el-input v-model="conditions.feeId" :placeholder="$t('reportPayFeeDeposit.search.feeId')"
  35 + class="search-item">
  36 + </el-input>
  37 + </el-col>
  38 + <el-col :span="4">
  39 + <el-select v-model="conditions.configId" :placeholder="$t('reportPayFeeDeposit.search.feeName')"
  40 + class="search-item" style="width:100%">
  41 + <el-option :label="$t('reportPayFeeDeposit.search.feeNamePlaceholder')" value=""></el-option>
  42 + <el-option v-for="(item, index) in feeConfigs" :key="index" :label="item.feeName" :value="item.configId">
  43 + </el-option>
  44 + </el-select>
  45 + </el-col>
  46 + <el-col :span="4">
  47 + <el-button type="primary" @click="queryMethod">
  48 + <i class="el-icon-search"></i>
  49 + {{ $t('reportPayFeeDeposit.search.search') }}
  50 + </el-button>
  51 + <el-button @click="resetMethod" style="margin-left: 10px;">
  52 + <i class="el-icon-refresh"></i>
  53 + {{ $t('reportPayFeeDeposit.search.reset') }}
  54 + </el-button>
  55 + </el-col>
  56 + </el-row>
  57 + <el-row :gutter="20" style="margin-top: 15px;">
  58 + <el-col :span="4">
  59 + <el-select v-model="conditions.state" :placeholder="$t('reportPayFeeDeposit.search.state')"
  60 + class="search-item" style="width:100%">
  61 + <el-option :label="$t('reportPayFeeDeposit.search.statePlaceholder')" value=""></el-option>
  62 + <el-option v-for="(item, index) in states" :key="index" :label="item.name" :value="item.statusCd">
  63 + </el-option>
  64 + </el-select>
  65 + </el-col>
  66 + <el-col :span="4">
  67 + <el-select v-model="conditions.payerObjType" :placeholder="$t('reportPayFeeDeposit.search.payerObjType')"
  68 + class="search-item" style="width:100%">
  69 + <el-option :label="$t('reportPayFeeDeposit.search.payerObjTypePlaceholder')" value=""></el-option>
  70 + <el-option v-for="(item, index) in payerObjTypes" :key="index" :label="item.name" :value="item.statusCd">
  71 + </el-option>
  72 + </el-select>
  73 + </el-col>
  74 + <el-col :span="4">
  75 + <el-date-picker v-model="conditions.startTime" type="datetime"
  76 + :placeholder="$t('reportPayFeeDeposit.search.startTime')" style="width:100%">
  77 + </el-date-picker>
  78 + </el-col>
  79 + <el-col :span="4">
  80 + <el-date-picker v-model="conditions.endTime" type="datetime"
  81 + :placeholder="$t('reportPayFeeDeposit.search.endTime')" style="width:100%">
  82 + </el-date-picker>
  83 + </el-col>
  84 + <el-col :span="4">
  85 + <el-select v-model="conditions.detailState" :placeholder="$t('reportPayFeeDeposit.search.detailState')"
  86 + class="search-item" style="width:100%">
  87 + <el-option :label="$t('reportPayFeeDeposit.search.detailStatePlaceholder')" value=""></el-option>
  88 + <template v-for="(item, index) in detailStates">
  89 + <el-option :key="index" :label="item.name" :value="item.statusCd" v-if="item.statusCd != '1300'">
  90 + </el-option>
  91 + </template>
  92 + </el-select>
  93 + </el-col>
  94 + </el-row>
  95 + </el-col>
  96 + </el-row>
  97 + </el-card>
  98 +
  99 + <!-- 押金报表 -->
  100 + <el-card class="table-card">
  101 + <div slot="header" class="flex justify-between">
  102 + <div>
  103 + <span>{{ $t('reportPayFeeDeposit.table.title') }}</span>
  104 + <el-tooltip class="item" effect="dark" :content="$t('reportPayFeeDeposit.table.tooltip')" placement="top">
  105 + <i class="el-icon-info" style="margin-left: 10px; cursor: pointer;"></i>
  106 + </el-tooltip>
  107 + </div>
  108 + <el-button type="primary" size="small" style="float: right;" @click="exportFee">
  109 + <i class="el-icon-download"></i>
  110 + {{ $t('reportPayFeeDeposit.table.export') }}
  111 + </el-button>
  112 + </div>
  113 + <el-table :data="depositFees" border style="width: 100%" v-loading="loading">
  114 + <el-table-column prop="feeId" :label="$t('reportPayFeeDeposit.table.feeId')" align="center">
  115 + </el-table-column>
  116 + <el-table-column prop="objName" :label="$t('reportPayFeeDeposit.table.roomNum')" align="center">
  117 + </el-table-column>
  118 + <el-table-column prop="ownerName" :label="$t('reportPayFeeDeposit.table.owner')" align="center">
  119 + </el-table-column>
  120 + <el-table-column prop="feeTypeCdName" :label="$t('reportPayFeeDeposit.table.feeType')" align="center">
  121 + </el-table-column>
  122 + <el-table-column prop="feeName" :label="$t('reportPayFeeDeposit.table.feeName')" align="center">
  123 + </el-table-column>
  124 + <el-table-column prop="startTime" :label="$t('reportPayFeeDeposit.table.startTime')" align="center">
  125 + </el-table-column>
  126 + <el-table-column prop="deadlineTime" :label="$t('reportPayFeeDeposit.table.endTime')" align="center">
  127 + </el-table-column>
  128 + <el-table-column prop="createTime" :label="$t('reportPayFeeDeposit.table.createTime')" align="center">
  129 + </el-table-column>
  130 + <el-table-column prop="payerObjTypeName" :label="$t('reportPayFeeDeposit.table.payerObjType')" align="center">
  131 + </el-table-column>
  132 + <el-table-column prop="payerObjId" :label="$t('reportPayFeeDeposit.table.payerObjId')" align="center">
  133 + </el-table-column>
  134 + <el-table-column prop="additionalAmount" :label="$t('reportPayFeeDeposit.table.amount')" align="center">
  135 + </el-table-column>
  136 + <el-table-column prop="stateName" :label="$t('reportPayFeeDeposit.table.state')" align="center">
  137 + </el-table-column>
  138 + <el-table-column :label="$t('reportPayFeeDeposit.table.detailState')" align="center">
  139 + <template slot-scope="scope">
  140 + <span v-if="scope.row.state == '2009001'">{{ scope.row.detailStateName }}</span>
  141 + <span v-else>{{ $t('reportPayFeeDeposit.table.unpaid') }}</span>
  142 + </template>
  143 + </el-table-column>
  144 + <el-table-column :label="$t('reportPayFeeDeposit.table.operation')" align="center" width="120">
  145 + <template slot-scope="scope">
  146 + <el-button size="mini" @click="openPayFeeDetail(scope.row)">
  147 + {{ $t('reportPayFeeDeposit.table.detail') }}
  148 + </el-button>
  149 + </template>
  150 + </el-table-column>
  151 + </el-table>
  152 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.current"
  153 + :page-sizes="[10, 20, 30, 50]" :page-size="page.size" layout="total, sizes, prev, pager, next, jumper"
  154 + :total="total" style="margin-top: 20px;">
  155 + </el-pagination>
  156 + <el-row :gutter="20" style="margin-top: 20px;">
  157 + <el-col :span="2">
  158 + <div>
  159 + <b>{{ $t('reportPayFeeDeposit.table.subtotal') }}</b>
  160 + </div>
  161 + <div style="margin-top: 10px;">
  162 + <b>{{ $t('reportPayFeeDeposit.table.total') }}</b>
  163 + </div>
  164 + </el-col>
  165 + <el-col :span="3">
  166 + <div>
  167 + {{ $t('reportPayFeeDeposit.table.unpaid') }}: {{ sumTotal.unpaidfeeAmount }} {{
  168 + $t('reportPayFeeDeposit.table.yuan') }}
  169 + </div>
  170 + <div style="margin-top: 10px;">
  171 + {{ $t('reportPayFeeDeposit.table.unpaid') }}: {{ sumTotal.unpaidfeeAmounts }} {{
  172 + $t('reportPayFeeDeposit.table.yuan') }}
  173 + </div>
  174 + </el-col>
  175 + <el-col :span="3">
  176 + <div>
  177 + {{ $t('reportPayFeeDeposit.table.paid') }}: {{ sumTotal.paidfeeAmount }} {{
  178 + $t('reportPayFeeDeposit.table.yuan')
  179 + }}
  180 + </div>
  181 + <div style="margin-top: 10px;">
  182 + {{ $t('reportPayFeeDeposit.table.paid') }}: {{ sumTotal.paidfeeAmounts }} {{
  183 + $t('reportPayFeeDeposit.table.yuan') }}
  184 + </div>
  185 + </el-col>
  186 + <el-col :span="3">
  187 + <div>
  188 + {{ $t('reportPayFeeDeposit.table.refunded') }}: {{ sumTotal.refundedAmount }} {{
  189 + $t('reportPayFeeDeposit.table.yuan') }}
  190 + </div>
  191 + <div style="margin-top: 10px;">
  192 + {{ $t('reportPayFeeDeposit.table.refunded') }}: {{ sumTotal.refundedAmounts }} {{
  193 + $t('reportPayFeeDeposit.table.yuan') }}
  194 + </div>
  195 + </el-col>
  196 + <el-col :span="3">
  197 + <div>
  198 + {{ $t('reportPayFeeDeposit.table.refundInProgress') }}: {{ sumTotal.refundInProgressAmount }} {{
  199 + $t('reportPayFeeDeposit.table.yuan') }}
  200 + </div>
  201 + <div style="margin-top: 10px;">
  202 + {{ $t('reportPayFeeDeposit.table.refundInProgress') }}: {{ sumTotal.refundInProgressAmounts }} {{
  203 + $t('reportPayFeeDeposit.table.yuan') }}
  204 + </div>
  205 + </el-col>
  206 + <el-col :span="3">
  207 + <div>
  208 + {{ $t('reportPayFeeDeposit.table.refundFailed') }}: {{ sumTotal.refundFailedAmount }} {{
  209 + $t('reportPayFeeDeposit.table.yuan') }}
  210 + </div>
  211 + <div style="margin-top: 10px;">
  212 + {{ $t('reportPayFeeDeposit.table.refundFailed') }}: {{ sumTotal.refundFailedAmounts }} {{
  213 + $t('reportPayFeeDeposit.table.yuan') }}
  214 + </div>
  215 + </el-col>
  216 + </el-row>
  217 + </el-card>
  218 +
  219 + <!-- 选择楼栋组件 -->
  220 + <search-floor ref="searchFloor" @chooseFloor="handleChooseFloor"></search-floor>
  221 + </div>
  222 +</template>
  223 +
  224 +<script>
  225 +import { getCommunityId } from '@/api/community/communityApi'
  226 +import { getDict } from '@/api/community/communityApi'
  227 +import { queryPayFeeDeposit, exportData } from '@/api/report/reportPayFeeDepositApi'
  228 +import SearchFloor from '@/components/room/searchFloor'
  229 +
  230 +export default {
  231 + name: 'ReportPayFeeDepositList',
  232 + components: {
  233 + SearchFloor
  234 + },
  235 + data() {
  236 + return {
  237 + loading: false,
  238 + communityId: '',
  239 + conditions: {
  240 + floorId: '',
  241 + floorName: '',
  242 + roomNum: '',
  243 + unitId: '',
  244 + feeId: '',
  245 + state: '',
  246 + payerObjType: '',
  247 + startTime: '',
  248 + endTime: '',
  249 + configId: '',
  250 + detailState: '',
  251 + feeTypeCd: '888800010006', // 押金
  252 + communityId: '',
  253 + page: 1,
  254 + row: 10
  255 + },
  256 + depositFees: [],
  257 + feeConfigs: [],
  258 + states: [],
  259 + payerObjTypes: [],
  260 + detailStates: [],
  261 + roomUnits: [],
  262 + sumTotal: {
  263 + unpaidfeeAmount: 0,
  264 + unpaidfeeAmounts: 0,
  265 + paidfeeAmount: 0,
  266 + paidfeeAmounts: 0,
  267 + refundedAmount: 0,
  268 + refundedAmounts: 0,
  269 + refundInProgressAmount: 0,
  270 + refundInProgressAmounts: 0,
  271 + refundFailedAmount: 0,
  272 + refundFailedAmounts: 0
  273 + },
  274 + page: {
  275 + current: 1,
  276 + size: 10,
  277 + total: 0
  278 + },
  279 + total: 0
  280 + }
  281 + },
  282 + created() {
  283 + this.communityId = getCommunityId()
  284 + this.conditions.communityId = this.communityId
  285 + this.initData()
  286 + },
  287 + methods: {
  288 + async initData() {
  289 + try {
  290 + // 获取字典数据
  291 + await Promise.all([
  292 + this.getDictData('pay_fee', 'state'),
  293 + this.getDictData('pay_fee', 'payer_obj_type'),
  294 + this.getDictData('pay_fee_detail', 'state')
  295 + ])
  296 + this.listFees()
  297 + } catch (error) {
  298 + console.error('初始化数据失败:', error)
  299 + }
  300 + },
  301 + async getDictData(dictType, state) {
  302 + try {
  303 + const data = await getDict(dictType, state)
  304 + if (dictType === 'pay_fee' && state === 'state') {
  305 + this.states = data
  306 + } else if (dictType === 'pay_fee' && state === 'payer_obj_type') {
  307 + this.payerObjTypes = data
  308 + } else if (dictType === 'pay_fee_detail' && state === 'state') {
  309 + this.detailStates = data
  310 + }
  311 + } catch (error) {
  312 + console.error('获取字典数据失败:', error)
  313 + }
  314 + },
  315 + async listFees() {
  316 + this.loading = true
  317 + try {
  318 + const params = {
  319 + ...this.conditions,
  320 + page: this.page.current,
  321 + row: this.page.size
  322 + }
  323 + const res = await queryPayFeeDeposit(params)
  324 + this.depositFees = res.data
  325 + this.total = res.total
  326 + this.sumTotal = res.sumTotal
  327 + if (res.data.length > 0) {
  328 + this.feeConfigs = res.data[0].feeConfigDtos || []
  329 + }
  330 + } catch (error) {
  331 + console.error('获取押金报表失败:', error)
  332 + } finally {
  333 + this.loading = false
  334 + }
  335 + },
  336 + async loadUnits(floorId) {
  337 + try {
  338 + const res = await this.$api.unit.queryUnits({
  339 + floorId,
  340 + communityId: this.communityId
  341 + })
  342 + this.roomUnits = res.data || []
  343 + } catch (error) {
  344 + console.error('获取单元列表失败:', error)
  345 + }
  346 + },
  347 + queryMethod() {
  348 + this.page.current = 1
  349 + this.listFees()
  350 + },
  351 + resetMethod() {
  352 + this.conditions = {
  353 + floorId: '',
  354 + floorName: '',
  355 + roomNum: '',
  356 + unitId: '',
  357 + feeId: '',
  358 + state: '',
  359 + payerObjType: '',
  360 + startTime: '',
  361 + endTime: '',
  362 + configId: '',
  363 + detailState: '',
  364 + feeTypeCd: '888800010006',
  365 + communityId: this.communityId,
  366 + page: 1,
  367 + row: 10
  368 + }
  369 + this.listFees()
  370 + },
  371 + handleSizeChange(val) {
  372 + this.page.size = val
  373 + this.listFees()
  374 + },
  375 + handleCurrentChange(val) {
  376 + this.page.current = val
  377 + this.listFees()
  378 + },
  379 + openChooseFloor() {
  380 + this.$refs.searchFloor.open()
  381 + },
  382 + handleChooseFloor(floor) {
  383 + this.conditions.floorId = floor.floorId
  384 + this.conditions.floorName = floor.floorName
  385 + this.loadUnits(floor.floorId)
  386 + },
  387 + async exportFee() {
  388 + try {
  389 + this.conditions.pagePath = 'reportPayFeeDeposit'
  390 + const res = await exportData(this.conditions)
  391 + this.$message.success(res.msg)
  392 + if (res.code === 0) {
  393 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  394 + }
  395 + } catch (error) {
  396 + console.error('导出失败:', error)
  397 + }
  398 + },
  399 + openPayFeeDetail(fee) {
  400 + this.$router.push(`/pages/property/propertyFee?feeId=${fee.feeId}`)
  401 + }
  402 + }
  403 +}
  404 +</script>
  405 +
  406 +<style lang="scss" scoped>
  407 +.report-pay-fee-deposit-container {
  408 + padding: 20px;
  409 +
  410 + .search-card {
  411 + margin-bottom: 20px;
  412 +
  413 + .search-item {
  414 + margin-bottom: 15px;
  415 + }
  416 + }
  417 +
  418 + .table-card {
  419 + margin-bottom: 20px;
  420 + }
  421 +}
  422 +</style>
0 \ No newline at end of file 423 \ No newline at end of file
src/views/scm/couponMarketLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + couponMarket: {
  4 + search: {
  5 + placeholder: 'Please enter coupon name',
  6 + },
  7 + price: 'Price',
  8 + buy: 'Buy',
  9 + fetchSupplierError: 'Failed to fetch supplier list',
  10 + fetchCouponError: 'Failed to fetch coupon list'
  11 + }
  12 + },
  13 + zh: {
  14 + couponMarket: {
  15 + search: {
  16 + placeholder: '请输入优惠券名称',
  17 + },
  18 + price: '售价',
  19 + buy: '购买',
  20 + fetchSupplierError: '获取供应商列表失败',
  21 + fetchCouponError: '获取优惠券列表失败'
  22 + }
  23 + }
  24 +}
0 \ No newline at end of file 25 \ No newline at end of file
src/views/scm/couponMarketList.vue 0 → 100644
  1 +<template>
  2 + <div class="coupon-market-container">
  3 + <div class="search-wrapper">
  4 + <div>
  5 + <el-input v-model="searchForm.couponName" style="width: 50%" :placeholder="$t('couponMarket.search.placeholder')"
  6 + @keyup.enter.native="handleSearch" />
  7 + <el-button type="primary" @click="handleSearch">
  8 + {{ $t('common.search') }}
  9 + </el-button>
  10 + </div>
  11 + <el-row :gutter="20">
  12 + <el-col :span="3"></el-col>
  13 + <el-col :span="12">
  14 + <el-link v-for="(item, index) in couponMarketInfo.suppliers" :key="index" type="primary"
  15 + @click="handleQuerySupplierCoupon(item)" class="supplier-link">
  16 + {{ item.supplierName }}
  17 + </el-link>
  18 + </el-col>
  19 + </el-row>
  20 + </div>
  21 +
  22 + <divider></divider>
  23 +
  24 + <div class="coupon-list-wrapper">
  25 + <el-row :gutter="20">
  26 + <el-col v-for="(item, index) in couponMarketInfo.coupons" :key="index" :span="6" class="coupon-item">
  27 + <el-card shadow="hover">
  28 + <el-image :src="couponMarketInfo.url" class="coupon-image" fit="cover" />
  29 + <div class="coupon-title">
  30 + {{ item.name }}
  31 + </div>
  32 + <el-row class="coupon-footer">
  33 + <el-col :span="12">
  34 + <span class="price-label">{{ $t('couponMarket.price') }}:</span>
  35 + <span class="price-value">¥{{ item.valuePrice }}</span>
  36 + </el-col>
  37 + <el-col :span="12" class="text-right">
  38 + <el-link type="primary">{{ $t('couponMarket.buy') }}</el-link>
  39 + </el-col>
  40 + </el-row>
  41 + </el-card>
  42 + </el-col>
  43 + </el-row>
  44 +
  45 + <el-pagination v-if="couponMarketInfo.records > 1" :current-page.sync="page.current" :page-size="page.size"
  46 + :total="couponMarketInfo.records" layout="total, prev, pager, next" @current-change="handlePageChange"
  47 + class="pagination-wrapper" />
  48 + </div>
  49 + </div>
  50 +</template>
  51 +
  52 +<script>
  53 +import { listSupplier, listSupplierCoupon } from '@/api/scm/couponMarketApi'
  54 +import divider from '@/components/system/divider'
  55 +
  56 +export default {
  57 + name: 'CouponMarketList',
  58 + data() {
  59 + return {
  60 + searchForm: {
  61 + couponName: ''
  62 + },
  63 + couponMarketInfo: {
  64 + coupons: [],
  65 + suppliers: [],
  66 + total: 0,
  67 + records: 1,
  68 + url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.zhimg.com%2Fv2-e262fc8062b7ef085a9f4de51a31f08f_1440w.jpg%3Fsource%3D172ae18b&refer=http%3A%2F%2Fpic1.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671372327&t=5644f55f337250a4f5af2baae7f34e3e'
  69 + },
  70 + page: {
  71 + current: 1,
  72 + size: 15
  73 + }
  74 + }
  75 + },
  76 + components: {
  77 + divider
  78 + },
  79 + created() {
  80 + this.loadTopSupplier()
  81 + this.loadCoupons()
  82 + },
  83 + methods: {
  84 + async loadTopSupplier() {
  85 + try {
  86 + const params = {
  87 + page: 1,
  88 + row: 5
  89 + }
  90 + const { data } = await listSupplier(params)
  91 + this.couponMarketInfo.suppliers = data
  92 + } catch (error) {
  93 + this.$message.error(this.$t('couponMarket.fetchSupplierError'))
  94 + }
  95 + },
  96 + async loadCoupons() {
  97 + try {
  98 + const params = {
  99 + page: this.page.current,
  100 + row: this.page.size,
  101 + supplierId: this.currentSupplierId || ''
  102 + }
  103 + const { data, total, records } = await listSupplierCoupon(params)
  104 + this.couponMarketInfo.coupons = data
  105 + this.couponMarketInfo.total = total
  106 + this.couponMarketInfo.records = records
  107 + } catch (error) {
  108 + this.$message.error(this.$t('couponMarket.fetchCouponError'))
  109 + }
  110 + },
  111 + handleQuerySupplierCoupon(item) {
  112 + this.currentSupplierId = item.supplierId
  113 + this.page.current = 1
  114 + this.loadCoupons()
  115 + },
  116 + handleSearch() {
  117 + this.page.current = 1
  118 + this.loadCoupons()
  119 + },
  120 + handlePageChange(currentPage) {
  121 + this.page.current = currentPage
  122 + this.loadCoupons()
  123 + }
  124 + }
  125 +}
  126 +</script>
  127 +
  128 +<style lang="scss" scoped>
  129 +.coupon-market-container {
  130 + padding: 20px;
  131 +
  132 + .search-wrapper {
  133 + margin-bottom: 20px;
  134 + }
  135 +
  136 + .supplier-wrapper {
  137 + margin-bottom: 20px;
  138 +
  139 + .supplier-link {
  140 + margin-right: 15px;
  141 + }
  142 + }
  143 +
  144 + .coupon-list-wrapper {
  145 + .coupon-item {
  146 + margin-bottom: 20px;
  147 +
  148 + .coupon-image {
  149 + width: 100%;
  150 + height: 150px;
  151 + border-radius: 4px;
  152 + }
  153 +
  154 + .coupon-title {
  155 + padding: 10px 0;
  156 + font-weight: bold;
  157 + }
  158 +
  159 + .coupon-footer {
  160 + padding-top: 10px;
  161 +
  162 + .price-label {
  163 + color: #999;
  164 + }
  165 +
  166 + .price-value {
  167 + color: #ff0036;
  168 + font-weight: bold;
  169 + }
  170 + }
  171 + }
  172 +
  173 + .pagination-wrapper {
  174 + margin-top: 20px;
  175 + text-align: right;
  176 + }
  177 + }
  178 +}
  179 +</style>
0 \ No newline at end of file 180 \ No newline at end of file
src/views/scm/couponPropertyPoolManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + couponPropertyPoolManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + cppId: 'Coupon ID',
  7 + couponName: 'Coupon Name',
  8 + fromType: 'From Type',
  9 + toType: 'To Type'
  10 + },
  11 + list: {
  12 + title: 'Coupon List',
  13 + add: 'Create'
  14 + },
  15 + table: {
  16 + cppId: 'ID',
  17 + couponName: 'Coupon Name',
  18 + fromType: 'From Type',
  19 + toType: 'To Type',
  20 + stock: 'Quantity',
  21 + validityDay: 'Validity',
  22 + day: 'days',
  23 + createTime: 'Create Time',
  24 + gift: 'Manual Gift'
  25 + },
  26 + fromType: {
  27 + market: 'Market Purchase',
  28 + self: 'Self Made'
  29 + },
  30 + toType: {
  31 + shopping: 'Shopping',
  32 + payment: 'Payment',
  33 + repair: 'Repair',
  34 + parking: 'Parking',
  35 + charging: 'Charging'
  36 + },
  37 + add: {
  38 + title: 'Create Coupon',
  39 + couponName: 'Coupon Name',
  40 + couponNamePlaceholder: 'Required, please enter coupon name',
  41 + toType: 'Purpose',
  42 + toTypePlaceholder: 'Required, please select purpose',
  43 + stock: 'Quantity',
  44 + stockPlaceholder: 'Required, please enter quantity',
  45 + validityDay: 'Validity',
  46 + validityDayPlaceholder: 'Required, please enter validity (days)',
  47 + remark: 'Instructions',
  48 + remarkPlaceholder: 'Required, please enter instructions',
  49 + success: 'Create successfully',
  50 + error: 'Create failed'
  51 + },
  52 + edit: {
  53 + title: 'Edit Coupon',
  54 + couponName: 'Coupon Name',
  55 + couponNamePlaceholder: 'Required, please enter coupon name',
  56 + toType: 'Purpose',
  57 + toTypePlaceholder: 'Required, please select purpose',
  58 + stock: 'Quantity',
  59 + stockPlaceholder: 'Required, please enter quantity',
  60 + validityDay: 'Validity',
  61 + validityDayPlaceholder: 'Required, please enter validity (days)',
  62 + remark: 'Instructions',
  63 + remarkPlaceholder: 'Required, please enter instructions',
  64 + success: 'Edit successfully',
  65 + error: 'Edit failed'
  66 + },
  67 + gift: {
  68 + title: 'Gift Coupon',
  69 + couponName: 'Coupon Name',
  70 + giftCount: 'Quantity',
  71 + giftCountPlaceholder: 'Required, please enter quantity',
  72 + tel: 'Owner Phone',
  73 + telPlaceholder: 'Required, please enter phone number',
  74 + submit: 'Gift',
  75 + success: 'Gift successfully',
  76 + error: 'Gift failed'
  77 + },
  78 + delete: {
  79 + title: 'Delete Confirmation',
  80 + confirmText: 'Are you sure to delete this coupon?',
  81 + success: 'Delete successfully',
  82 + error: 'Delete failed'
  83 + },
  84 + validate: {
  85 + couponNameRequired: 'Coupon name is required',
  86 + couponNameMaxLength: 'Coupon name cannot exceed 64 characters',
  87 + toTypeRequired: 'Purpose is required',
  88 + stockRequired: 'Quantity is required',
  89 + validityDayRequired: 'Validity is required',
  90 + remarkRequired: 'Instructions is required',
  91 + cppIdRequired: 'Coupon ID is required',
  92 + giftCountRequired: 'Quantity is required',
  93 + telRequired: 'Phone number is required'
  94 + },
  95 + fetchError: 'Failed to get coupon list'
  96 + }
  97 + },
  98 + zh: {
  99 + couponPropertyPoolManage: {
  100 + search: {
  101 + title: '查询条件',
  102 + cppId: '优惠券编号',
  103 + couponName: '优惠券名称',
  104 + fromType: '来自方式',
  105 + toType: '用途'
  106 + },
  107 + list: {
  108 + title: '优惠券列表',
  109 + add: '制作'
  110 + },
  111 + table: {
  112 + cppId: '编号',
  113 + couponName: '优惠券名称',
  114 + fromType: '来自方式',
  115 + toType: '用途',
  116 + stock: '数量',
  117 + validityDay: '有效期',
  118 + day: '天',
  119 + createTime: '创建时间',
  120 + gift: '手工赠送'
  121 + },
  122 + fromType: {
  123 + market: '优惠券市场购买',
  124 + self: '自己制作'
  125 + },
  126 + toType: {
  127 + shopping: '购物',
  128 + payment: '缴费',
  129 + repair: '维修劵',
  130 + parking: '停车劵',
  131 + charging: '充电桩充电劵'
  132 + },
  133 + add: {
  134 + title: '制作优惠券',
  135 + couponName: '优惠券名称',
  136 + couponNamePlaceholder: '必填,请填写优惠券名称',
  137 + toType: '用途',
  138 + toTypePlaceholder: '必填,请选择用途',
  139 + stock: '数量',
  140 + stockPlaceholder: '必填,请填写数量',
  141 + validityDay: '有效期',
  142 + validityDayPlaceholder: '必填,请填写有效期(天)',
  143 + remark: '使用说明',
  144 + remarkPlaceholder: '必填,请填写使用说明',
  145 + success: '制作成功',
  146 + error: '制作失败'
  147 + },
  148 + edit: {
  149 + title: '修改优惠券',
  150 + couponName: '优惠券名称',
  151 + couponNamePlaceholder: '必填,请填写优惠券名称',
  152 + toType: '用途',
  153 + toTypePlaceholder: '必填,请选择用途',
  154 + stock: '数量',
  155 + stockPlaceholder: '必填,请填写数量',
  156 + validityDay: '有效期',
  157 + validityDayPlaceholder: '必填,请填写有效期(天)',
  158 + remark: '使用说明',
  159 + remarkPlaceholder: '必填,请填写使用说明',
  160 + success: '修改成功',
  161 + error: '修改失败'
  162 + },
  163 + gift: {
  164 + title: '赠送优惠券',
  165 + couponName: '优惠券名称',
  166 + giftCount: '数量',
  167 + giftCountPlaceholder: '必填,请填写数量',
  168 + tel: '业主手机号',
  169 + telPlaceholder: '必填,请填写手机号',
  170 + submit: '赠送',
  171 + success: '赠送成功',
  172 + error: '赠送失败'
  173 + },
  174 + delete: {
  175 + title: '删除确认',
  176 + confirmText: '确定删除优惠券?',
  177 + success: '删除成功',
  178 + error: '删除失败'
  179 + },
  180 + validate: {
  181 + couponNameRequired: '优惠券名称不能为空',
  182 + couponNameMaxLength: '优惠券名称不能超过64个字符',
  183 + toTypeRequired: '用途不能为空',
  184 + stockRequired: '数量不能为空',
  185 + validityDayRequired: '有效期不能为空',
  186 + remarkRequired: '使用说明不能为空',
  187 + cppIdRequired: '优惠券编号不能为空',
  188 + giftCountRequired: '数量不能为空',
  189 + telRequired: '手机号不能为空'
  190 + },
  191 + fetchError: '获取优惠券列表失败'
  192 + }
  193 + }
  194 +}
0 \ No newline at end of file 195 \ No newline at end of file
src/views/scm/couponPropertyPoolManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="coupon-property-pool-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('couponPropertyPoolManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.cppId" :placeholder="$t('couponPropertyPoolManage.search.cppId')" clearable />
  11 + </el-col>
  12 + <el-col :span="6">
  13 + <el-input v-model="searchForm.couponName" :placeholder="$t('couponPropertyPoolManage.search.couponName')"
  14 + clearable />
  15 + </el-col>
  16 + <el-col :span="6">
  17 + <el-select v-model="searchForm.fromType" :placeholder="$t('couponPropertyPoolManage.search.fromType')"
  18 + style="width:100%" clearable>
  19 + <el-option v-for="item in fromTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  20 + </el-select>
  21 + </el-col>
  22 + <el-col :span="6">
  23 + <el-button type="primary" @click="handleSearch">
  24 + {{ $t('common.search') }}
  25 + </el-button>
  26 + </el-col>
  27 + </el-row>
  28 + <el-row :gutter="20" style="margin-top:15px">
  29 + <el-col :span="6">
  30 + <el-select v-model="searchForm.toType" :placeholder="$t('couponPropertyPoolManage.search.toType')"
  31 + style="width:100%" clearable>
  32 + <el-option v-for="item in toTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  33 + </el-select>
  34 + </el-col>
  35 + </el-row>
  36 + </el-card>
  37 +
  38 + <!-- 列表 -->
  39 + <el-card class="list-wrapper">
  40 + <div slot="header" class="flex justify-between">
  41 + <span>{{ $t('couponPropertyPoolManage.list.title') }}</span>
  42 + <div style="float:right">
  43 + <el-button type="text" @click="handleShowDoc">
  44 + {{ $t('common.document') }}
  45 + </el-button>
  46 + <el-button type="primary" size="small" @click="handleAdd">
  47 + {{ $t('couponPropertyPoolManage.list.add') }}
  48 + </el-button>
  49 + </div>
  50 + </div>
  51 +
  52 + <el-table v-loading="loading" :data="tableData" border style="width:100%">
  53 + <el-table-column prop="cppId" :label="$t('couponPropertyPoolManage.table.cppId')" align="center" />
  54 + <el-table-column prop="couponName" :label="$t('couponPropertyPoolManage.table.couponName')" align="center" />
  55 + <el-table-column prop="fromTypeName" :label="$t('couponPropertyPoolManage.table.fromType')" align="center" />
  56 + <el-table-column prop="toTypeName" :label="$t('couponPropertyPoolManage.table.toType')" align="center" />
  57 + <el-table-column prop="stock" :label="$t('couponPropertyPoolManage.table.stock')" align="center" />
  58 + <el-table-column prop="validityDay" :label="$t('couponPropertyPoolManage.table.validityDay')" align="center">
  59 + <template slot-scope="scope">
  60 + {{ scope.row.validityDay }}{{ $t('couponPropertyPoolManage.table.day') }}
  61 + </template>
  62 + </el-table-column>
  63 + <el-table-column prop="createTime" :label="$t('couponPropertyPoolManage.table.createTime')" align="center" />
  64 + <el-table-column :label="$t('common.operation')" align="center" width="300">
  65 + <template slot-scope="scope">
  66 + <el-button v-if="scope.row.stock > 0" size="mini" type="text" @click="handleGift(scope.row)">
  67 + {{ $t('couponPropertyPoolManage.table.gift') }}
  68 + </el-button>
  69 + <el-button v-if="scope.row.fromType === '2002'" size="mini" type="text" @click="handleEdit(scope.row)">
  70 + {{ $t('common.edit') }}
  71 + </el-button>
  72 + <el-button v-if="scope.row.fromType === '2002'" size="mini" type="text" @click="handleDelete(scope.row)">
  73 + {{ $t('common.delete') }}
  74 + </el-button>
  75 + </template>
  76 + </el-table-column>
  77 + </el-table>
  78 +
  79 + <el-pagination :current-page="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  80 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  81 + @current-change="handleCurrentChange" />
  82 + </el-card>
  83 +
  84 + <!-- 组件 -->
  85 + <add-coupon-property-pool ref="addCouponPropertyPool" @success="handleSuccess" />
  86 + <edit-coupon-property-pool ref="editCouponPropertyPool" @success="handleSuccess" />
  87 + <gift-coupon-property-pool ref="giftCouponPropertyPool" @success="handleSuccess" />
  88 + <delete-coupon-property-pool ref="deleteCouponPropertyPool" @success="handleSuccess" />
  89 + </div>
  90 +</template>
  91 +
  92 +<script>
  93 +import { listCouponPropertyPool } from '@/api/scm/couponPropertyPoolManageApi'
  94 +import AddCouponPropertyPool from '@/components/scm/addCouponPropertyPool'
  95 +import EditCouponPropertyPool from '@/components/scm/editCouponPropertyPool'
  96 +import GiftCouponPropertyPool from '@/components/scm/giftCouponPropertyPool'
  97 +import DeleteCouponPropertyPool from '@/components/scm/deleteCouponPropertyPool'
  98 +import { getCommunityId } from '@/api/community/communityApi'
  99 +
  100 +export default {
  101 + name: 'CouponPropertyPoolManageList',
  102 + components: {
  103 + AddCouponPropertyPool,
  104 + EditCouponPropertyPool,
  105 + GiftCouponPropertyPool,
  106 + DeleteCouponPropertyPool
  107 + },
  108 + data() {
  109 + return {
  110 + loading: false,
  111 + searchForm: {
  112 + cppId: '',
  113 + couponName: '',
  114 + fromType: '',
  115 + toType: '',
  116 + communityId: getCommunityId()
  117 + },
  118 + tableData: [],
  119 + page: {
  120 + current: 1,
  121 + size: 10,
  122 + total: 0
  123 + },
  124 + fromTypeOptions: [
  125 + { value: '1001', label: this.$t('couponPropertyPoolManage.fromType.market') },
  126 + { value: '2002', label: this.$t('couponPropertyPoolManage.fromType.self') }
  127 + ],
  128 + toTypeOptions: [
  129 + { value: '1001', label: this.$t('couponPropertyPoolManage.toType.shopping') },
  130 + { value: '3003', label: this.$t('couponPropertyPoolManage.toType.repair') },
  131 + { value: '4004', label: this.$t('couponPropertyPoolManage.toType.parking') }
  132 + ]
  133 + }
  134 + },
  135 + created() {
  136 + this.getList()
  137 + },
  138 + methods: {
  139 + async getList() {
  140 + try {
  141 + this.loading = true
  142 + const params = {
  143 + ...this.searchForm,
  144 + page: this.page.current,
  145 + row: this.page.size
  146 + }
  147 + const { data, total } = await listCouponPropertyPool(params)
  148 + this.tableData = data
  149 + this.page.total = total
  150 + } catch (error) {
  151 + this.$message.error(this.$t('couponPropertyPoolManage.fetchError'))
  152 + } finally {
  153 + this.loading = false
  154 + }
  155 + },
  156 + handleSearch() {
  157 + this.page.current = 1
  158 + this.getList()
  159 + },
  160 + handleAdd() {
  161 + this.$refs.addCouponPropertyPool.open()
  162 + },
  163 + handleEdit(row) {
  164 + this.$refs.editCouponPropertyPool.open(row)
  165 + },
  166 + handleGift(row) {
  167 + this.$refs.giftCouponPropertyPool.open(row)
  168 + },
  169 + handleDelete(row) {
  170 + this.$refs.deleteCouponPropertyPool.open(row)
  171 + },
  172 + handleShowDoc() {
  173 + // 显示文档逻辑
  174 + },
  175 + handleSuccess() {
  176 + this.getList()
  177 + },
  178 + handleSizeChange(val) {
  179 + this.page.size = val
  180 + this.getList()
  181 + },
  182 + handleCurrentChange(val) {
  183 + this.page.current = val
  184 + this.getList()
  185 + }
  186 + }
  187 +}
  188 +</script>
  189 +
  190 +<style lang="scss" scoped>
  191 +.coupon-property-pool-manage-container {
  192 + padding: 20px;
  193 +
  194 + .search-wrapper {
  195 + margin-bottom: 20px;
  196 + }
  197 +
  198 + .list-wrapper {
  199 + margin-bottom: 20px;
  200 + }
  201 +
  202 + .el-pagination {
  203 + margin-top: 20px;
  204 + text-align: right;
  205 + }
  206 +}
  207 +</style>
0 \ No newline at end of file 208 \ No newline at end of file
src/views/scm/couponRuleLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + couponRule: {
  4 + title: 'Coupon Rules',
  5 + ruleName: 'Rule Name',
  6 + ruleNamePlaceholder: 'Please enter rule name',
  7 + ruleNameRequired: 'Rule name is required',
  8 + ruleNameMaxLength: 'Rule name cannot exceed 64 characters',
  9 + remark: 'Remark',
  10 + remarkPlaceholder: 'Please enter remark',
  11 + remarkMaxLength: 'Remark cannot exceed 512 characters',
  12 + ruleIdRequired: 'Rule ID is required',
  13 + addRule: 'Add Rule',
  14 + editRule: 'Edit Rule',
  15 + deleteConfirm: 'Delete Confirmation',
  16 + deleteRulePrompt: 'Are you sure to delete this coupon rule?',
  17 + selectRuleFirst: 'Please select a rule first',
  18 + coupon: 'Coupon',
  19 + fee: 'Fee'
  20 + },
  21 + couponRuleCpps: {
  22 + id: 'ID',
  23 + coupon: 'Coupon',
  24 + couponPlaceholder: 'Please select coupon',
  25 + couponRequired: 'Coupon is required',
  26 + quantity: 'Quantity',
  27 + quantityPlaceholder: 'Please enter quantity',
  28 + quantityRequired: 'Quantity is required',
  29 + quantityPattern: 'Quantity must be a positive integer',
  30 + frequency: 'Frequency',
  31 + frequencyPlaceholder: 'Please select frequency',
  32 + frequencyRequired: 'Frequency is required',
  33 + once: 'Once',
  34 + monthly: 'Monthly',
  35 + addCoupon: 'Add Coupon',
  36 + editCoupon: 'Edit Coupon',
  37 + deleteConfirm: 'Delete Confirmation',
  38 + deletePrompt: 'Are you sure to delete this coupon?',
  39 + idRequired: 'ID is required'
  40 + },
  41 + couponRuleFee: {
  42 + id: 'ID',
  43 + fee: 'Fee',
  44 + feePlaceholder: 'Please select fee',
  45 + feeRequired: 'Fee is required',
  46 + payTime: 'Payment Time',
  47 + payMonth: 'Payment Month',
  48 + payMonthPlaceholder: 'Please enter payment month',
  49 + payMonthRequired: 'Payment month is required',
  50 + payStartTime: 'Start Time',
  51 + payStartTimePlaceholder: 'Please select start time',
  52 + payStartTimeRequired: 'Start time is required',
  53 + payEndTime: 'End Time',
  54 + payEndTimePlaceholder: 'Please select end time',
  55 + payEndTimeRequired: 'End time is required',
  56 + addFee: 'Add Fee',
  57 + deleteConfirm: 'Delete Confirmation',
  58 + deletePrompt: 'Are you sure to delete this fee rule?'
  59 + }
  60 + },
  61 + zh: {
  62 + couponRule: {
  63 + title: '优惠券规则',
  64 + ruleName: '规则名称',
  65 + ruleNamePlaceholder: '请输入规则名称',
  66 + ruleNameRequired: '规则名称不能为空',
  67 + ruleNameMaxLength: '规则名称不能超过64个字符',
  68 + remark: '备注',
  69 + remarkPlaceholder: '请输入备注',
  70 + remarkMaxLength: '备注不能超过512个字符',
  71 + ruleIdRequired: '规则ID不能为空',
  72 + addRule: '添加规则',
  73 + editRule: '编辑规则',
  74 + deleteConfirm: '删除确认',
  75 + deleteRulePrompt: '确定要删除此优惠券规则吗?',
  76 + selectRuleFirst: '请先选择规则',
  77 + coupon: '优惠券',
  78 + fee: '缴费赠送'
  79 + },
  80 + couponRuleCpps: {
  81 + id: '编号',
  82 + coupon: '优惠券',
  83 + couponPlaceholder: '请选择优惠券',
  84 + couponRequired: '优惠券不能为空',
  85 + quantity: '数量',
  86 + quantityPlaceholder: '请输入数量',
  87 + quantityRequired: '数量不能为空',
  88 + quantityPattern: '数量必须为正整数',
  89 + frequency: '频率',
  90 + frequencyPlaceholder: '请选择频率',
  91 + frequencyRequired: '频率不能为空',
  92 + once: '赠送一次',
  93 + monthly: '每月赠送',
  94 + addCoupon: '添加优惠券',
  95 + editCoupon: '编辑优惠券',
  96 + deleteConfirm: '删除确认',
  97 + deletePrompt: '确定要删除此优惠券吗?',
  98 + idRequired: 'ID不能为空'
  99 + },
  100 + couponRuleFee: {
  101 + id: '编号',
  102 + fee: '费用',
  103 + feePlaceholder: '请选择费用',
  104 + feeRequired: '费用不能为空',
  105 + payTime: '缴费时间',
  106 + payMonth: '缴费月',
  107 + payMonthPlaceholder: '请输入缴费月',
  108 + payMonthRequired: '缴费月不能为空',
  109 + payStartTime: '开始时间',
  110 + payStartTimePlaceholder: '请选择开始时间',
  111 + payStartTimeRequired: '开始时间不能为空',
  112 + payEndTime: '结束时间',
  113 + payEndTimePlaceholder: '请选择结束时间',
  114 + payEndTimeRequired: '结束时间不能为空',
  115 + addFee: '添加缴费赠送',
  116 + deleteConfirm: '删除确认',
  117 + deletePrompt: '确定要删除此缴费规则吗?'
  118 + }
  119 + }
  120 +}
0 \ No newline at end of file 121 \ No newline at end of file
src/views/scm/couponRuleList.vue 0 → 100644
  1 +<template>
  2 + <div class="coupon-rule-container">
  3 + <el-row class="coupon-rule-wrapper">
  4 + <el-col :span="4" class="left-panel">
  5 + <coupon-rule-div ref="couponRuleDiv" @switch="handleSwitchCouponRule" />
  6 + </el-col>
  7 + <el-col :span="20" class="right-panel">
  8 + <el-card class="box-card">
  9 + <div slot="header" class="clearfix">
  10 + <h5>{{ currentCouponRule.ruleName }}</h5>
  11 + <div class="role-context">{{ currentCouponRule.remark }}</div>
  12 + </div>
  13 + <el-divider></el-divider>
  14 + <el-tabs v-model="activeTab" @tab-click="handleTabClick">
  15 + <el-tab-pane :label="$t('couponRule.coupon')" name="couponRuleCpps">
  16 + <coupon-rule-cpps v-if="activeTab === 'couponRuleCpps'" :rule-id="currentCouponRule.ruleId" />
  17 + </el-tab-pane>
  18 + <el-tab-pane :label="$t('couponRule.fee')" name="couponRuleFee">
  19 + <coupon-rule-fees v-if="activeTab === 'couponRuleFee'" :rule-id="currentCouponRule.ruleId" />
  20 + </el-tab-pane>
  21 + </el-tabs>
  22 + </el-card>
  23 + </el-col>
  24 + </el-row>
  25 +
  26 + <add-coupon-rule ref="addCouponRule" @success="handleSuccess" />
  27 + <edit-coupon-rule ref="editCouponRule" @success="handleSuccess" />
  28 + <delete-coupon-rule ref="deleteCouponRule" @success="handleSuccess" />
  29 + </div>
  30 +</template>
  31 +
  32 +<script>
  33 +import CouponRuleDiv from '@/components/scm/CouponRuleDiv'
  34 +import CouponRuleCpps from '@/components/scm/CouponRuleCpps'
  35 +import CouponRuleFees from '@/components/scm/CouponRuleFees'
  36 +import AddCouponRule from '@/components/scm/AddCouponRule'
  37 +import EditCouponRule from '@/components/scm/EditCouponRule'
  38 +import DeleteCouponRule from '@/components/scm/DeleteCouponRule'
  39 +
  40 +export default {
  41 + name: 'CouponRuleList',
  42 + components: {
  43 + CouponRuleDiv,
  44 + CouponRuleCpps,
  45 + CouponRuleFees,
  46 + AddCouponRule,
  47 + EditCouponRule,
  48 + DeleteCouponRule
  49 + },
  50 + data() {
  51 + return {
  52 + activeTab: 'couponRuleCpps',
  53 + currentCouponRule: {
  54 + ruleId: '',
  55 + ruleName: '',
  56 + remark: ''
  57 + }
  58 + }
  59 + },
  60 + methods: {
  61 + handleSwitchCouponRule(rule) {
  62 + this.currentCouponRule = rule
  63 + },
  64 + handleTabClick(tab) {
  65 + this.activeTab = tab.name
  66 + },
  67 + handleSuccess() {
  68 + this.$refs.couponRuleDiv.refreshList()
  69 + },
  70 + openAddModal() {
  71 + this.$refs.addCouponRule.open()
  72 + },
  73 + openEditModal() {
  74 + if (!this.currentCouponRule.ruleId) {
  75 + this.$message.warning(this.$t('couponRule.selectRuleFirst'))
  76 + return
  77 + }
  78 + this.$refs.editCouponRule.open(this.currentCouponRule)
  79 + },
  80 + openDeleteModal() {
  81 + if (!this.currentCouponRule.ruleId) {
  82 + this.$message.warning(this.$t('couponRule.selectRuleFirst'))
  83 + return
  84 + }
  85 + this.$refs.deleteCouponRule.open(this.currentCouponRule)
  86 + }
  87 + }
  88 +}
  89 +</script>
  90 +
  91 +<style lang="scss" scoped>
  92 +.coupon-rule-container {
  93 + padding: 20px;
  94 + height: 100%;
  95 +
  96 + .coupon-rule-wrapper {
  97 + height: 100%;
  98 +
  99 + .left-panel {
  100 + padding-right: 10px;
  101 + height: 100%;
  102 + }
  103 +
  104 + .right-panel {
  105 + height: 100%;
  106 +
  107 + .box-card {
  108 + height: 100%;
  109 +
  110 + .clearfix {
  111 + h5 {
  112 + margin: 0;
  113 + font-size: 16px;
  114 + font-weight: bold;
  115 + }
  116 +
  117 + .role-context {
  118 + margin-top: 5px;
  119 + color: #999;
  120 + font-size: 12px;
  121 + }
  122 + }
  123 + }
  124 + }
  125 + }
  126 +}
  127 +</style>
0 \ No newline at end of file 128 \ No newline at end of file