Commit 6ed9faf14d7219f2f823b87a775dfe04f2f1da3f

Authored by wuxw
1 parent f52d2b06

开发完成优惠下的积分功能

src/api/scm/communityIntegralApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询小区积分信息
  5 +export function queryCommunityIntegral(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/mall.getMallOpenApi',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: getCommunityId(),
  13 + mallApiCode: 'queryCommunityIntegralBmoImpl'
  14 + }
  15 + }).then(response => {
  16 + const res = response.data
  17 + resolve(res)
  18 + }).catch(error => {
  19 + reject(error)
  20 + })
  21 + })
  22 +}
  23 +
  24 +// 查询小区积分明细
  25 +export function queryCommunityIntegralDetail(params) {
  26 + return new Promise((resolve, reject) => {
  27 + request({
  28 + url: '/mall.getMallOpenApi',
  29 + method: 'get',
  30 + params: {
  31 + ...params,
  32 + communityId: getCommunityId(),
  33 + mallApiCode: 'queryCommunityIntegralDetailBmoImpl'
  34 + }
  35 + }).then(response => {
  36 + const res = response.data
  37 + resolve(res)
  38 + }).catch(error => {
  39 + reject(error)
  40 + })
  41 + })
  42 +}
  43 +
  44 +// 查询积分提现申请
  45 +export function queryCommunityIntegralApply(params) {
  46 + return new Promise((resolve, reject) => {
  47 + request({
  48 + url: '/mall.getMallOpenApi',
  49 + method: 'get',
  50 + params: {
  51 + ...params,
  52 + communityId: getCommunityId(),
  53 + mallApiCode: 'queryCommunityIntegralApplyBmoImpl'
  54 + }
  55 + }).then(response => {
  56 + const res = response.data
  57 + resolve(res)
  58 + }).catch(error => {
  59 + reject(error)
  60 + })
  61 + })
  62 +}
  63 +
  64 +// 申请积分提现
  65 +export function applyIntegralWithdrawal(data) {
  66 + return new Promise((resolve, reject) => {
  67 + request({
  68 + url: '/mall.postMallOpenApi',
  69 + method: 'post',
  70 + data: {
  71 + ...data,
  72 + communityId: getCommunityId(),
  73 + mallApiCode: 'applyIntegralWithdrawalBmoImpl'
  74 + }
  75 + }).then(response => {
  76 + const res = response.data
  77 + resolve(res)
  78 + }).catch(error => {
  79 + reject(error)
  80 + })
  81 + })
  82 +}
  83 +
  84 +// 删除积分提现申请
  85 +export function deleteIntegralWithdrawal(data) {
  86 + return new Promise((resolve, reject) => {
  87 + request({
  88 + url: '/mall.postMallOpenApi',
  89 + method: 'post',
  90 + data: {
  91 + ...data,
  92 + communityId: getCommunityId(),
  93 + mallApiCode: 'deleteIntegralWithdrawalBmoImpl'
  94 + }
  95 + }).then(response => {
  96 + const res = response.data
  97 + resolve(res)
  98 + }).catch(error => {
  99 + reject(error)
  100 + })
  101 + })
  102 +}
0 \ No newline at end of file 103 \ No newline at end of file
src/api/scm/goldApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取金币账户信息
  5 +export function getPropertyGoldInfo(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/mall.getMallOpenApi',
  9 + method: 'get',
  10 + params: {
  11 + ...params,
  12 + communityId: params.communityId || getCommunityId(),
  13 + mallApiCode: 'queryPropertyGoldBmoImpl'
  14 + }
  15 + }).then(response => {
  16 + const res = response.data
  17 + resolve(res)
  18 + }).catch(error => {
  19 + reject(error)
  20 + })
  21 + })
  22 +}
  23 +
  24 +// 获取金币交易明细
  25 +export function getPropertyGoldDetail(params) {
  26 + return new Promise((resolve, reject) => {
  27 + request({
  28 + url: '/mall.getMallOpenApi',
  29 + method: 'get',
  30 + params: {
  31 + ...params,
  32 + communityId: params.communityId || getCommunityId(),
  33 + mallApiCode: 'queryPropertyGoldDetailBmoImpl'
  34 + }
  35 + }).then(response => {
  36 + const res = response.data
  37 + resolve(res)
  38 + }).catch(error => {
  39 + reject(error)
  40 + })
  41 + })
  42 +}
  43 +
  44 +// 获取金币提现申请列表
  45 +export function getPropertyGoldApplys(params) {
  46 + return new Promise((resolve, reject) => {
  47 + request({
  48 + url: '/mall.getMallOpenApi',
  49 + method: 'get',
  50 + params: {
  51 + ...params,
  52 + communityId: params.communityId || getCommunityId(),
  53 + mallApiCode: 'queryPropertyGoldApplysBmoImpl'
  54 + }
  55 + }).then(response => {
  56 + const res = response.data
  57 + resolve(res)
  58 + }).catch(error => {
  59 + reject(error)
  60 + })
  61 + })
  62 +}
  63 +
  64 +// 申请金币提现
  65 +export function applyGoldWithHold(data) {
  66 + return new Promise((resolve, reject) => {
  67 + request({
  68 + url: '/mall.postMallOpenApi',
  69 + method: 'post',
  70 + data: {
  71 + ...data,
  72 + communityId: data.communityId || getCommunityId(),
  73 + mallApiCode: 'applyGoldWithHoldBmoImpl'
  74 + }
  75 + }).then(response => {
  76 + const res = response.data
  77 + resolve(res)
  78 + }).catch(error => {
  79 + reject(error)
  80 + })
  81 + })
  82 +}
  83 +
  84 +// 删除金币提现申请
  85 +export function deleteGoldWithHold(data) {
  86 + return new Promise((resolve, reject) => {
  87 + request({
  88 + url: '/mall.postMallOpenApi',
  89 + method: 'post',
  90 + data: {
  91 + ...data,
  92 + communityId: data.communityId || getCommunityId(),
  93 + mallApiCode: 'deleteGoldWithHoldBmoImpl'
  94 + }
  95 + }).then(response => {
  96 + const res = response.data
  97 + resolve(res)
  98 + }).catch(error => {
  99 + reject(error)
  100 + })
  101 + })
  102 +}
0 \ No newline at end of file 103 \ No newline at end of file
src/api/scm/reserveCatalogManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取预约目录列表
  5 +export function listReserveCatalog(params) {
  6 + return new Promise((resolve, reject) => {
  7 + request({
  8 + url: '/reserve.listReserveCatalog',
  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 saveReserveCatalog(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/reserve.saveReserveCatalog',
  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 updateReserveCatalog(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/reserve.updateReserveCatalog',
  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 deleteReserveCatalog(data) {
  63 + return new Promise((resolve, reject) => {
  64 + request({
  65 + url: '/reserve.deleteReserveCatalog',
  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 +}
0 \ No newline at end of file 79 \ No newline at end of file
src/components/scm/addReserveCatalog.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('reserveCatalogManage.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('reserveCatalogManage.add.name')"
  16 + prop="name"
  17 + >
  18 + <el-input
  19 + v-model="formData.name"
  20 + :placeholder="$t('reserveCatalogManage.add.namePlaceholder')"
  21 + />
  22 + </el-form-item>
  23 + <el-form-item
  24 + :label="$t('reserveCatalogManage.add.sort')"
  25 + prop="sort"
  26 + >
  27 + <el-input
  28 + v-model="formData.sort"
  29 + :placeholder="$t('reserveCatalogManage.add.sortPlaceholder')"
  30 + />
  31 + </el-form-item>
  32 + <el-form-item
  33 + :label="$t('reserveCatalogManage.add.type')"
  34 + prop="type"
  35 + >
  36 + <el-select
  37 + v-model="formData.type"
  38 + :placeholder="$t('reserveCatalogManage.add.typePlaceholder')"
  39 + style="width:100%"
  40 + >
  41 + <el-option
  42 + :label="$t('reserveCatalogManage.add.typeOption1')"
  43 + value="1001"
  44 + />
  45 + <el-option
  46 + :label="$t('reserveCatalogManage.add.typeOption2')"
  47 + value="2002"
  48 + />
  49 + </el-select>
  50 + </el-form-item>
  51 + <el-form-item
  52 + :label="$t('reserveCatalogManage.add.state')"
  53 + prop="state"
  54 + >
  55 + <el-select
  56 + v-model="formData.state"
  57 + :placeholder="$t('reserveCatalogManage.add.statePlaceholder')"
  58 + style="width:100%"
  59 + >
  60 + <el-option
  61 + :label="$t('reserveCatalogManage.add.stateOption1')"
  62 + value="1001"
  63 + />
  64 + <el-option
  65 + :label="$t('reserveCatalogManage.add.stateOption2')"
  66 + value="2002"
  67 + />
  68 + </el-select>
  69 + </el-form-item>
  70 + </el-form>
  71 + <span slot="footer" class="dialog-footer">
  72 + <el-button @click="visible = false">
  73 + {{ $t('common.cancel') }}
  74 + </el-button>
  75 + <el-button type="primary" @click="handleSubmit">
  76 + {{ $t('common.confirm') }}
  77 + </el-button>
  78 + </span>
  79 + </el-dialog>
  80 +</template>
  81 +
  82 +<script>
  83 +import { saveReserveCatalog } from '@/api/scm/reserveCatalogManageApi'
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +
  86 +export default {
  87 + name: 'AddReserveCatalog',
  88 + data() {
  89 + return {
  90 + visible: false,
  91 + formData: {
  92 + name: '',
  93 + sort: '',
  94 + type: '',
  95 + state: '',
  96 + communityId: ''
  97 + },
  98 + rules: {
  99 + name: [
  100 + { required: true, message: this.$t('reserveCatalogManage.validate.nameRequired'), trigger: 'blur' },
  101 + { max: 128, message: this.$t('reserveCatalogManage.validate.nameMaxLength'), trigger: 'blur' }
  102 + ],
  103 + sort: [
  104 + { required: true, message: this.$t('reserveCatalogManage.validate.sortRequired'), trigger: 'blur' },
  105 + { max: 12, message: this.$t('reserveCatalogManage.validate.sortMaxLength'), trigger: 'blur' }
  106 + ],
  107 + type: [
  108 + { required: true, message: this.$t('reserveCatalogManage.validate.typeRequired'), trigger: 'change' }
  109 + ],
  110 + state: [
  111 + { required: true, message: this.$t('reserveCatalogManage.validate.stateRequired'), trigger: 'change' }
  112 + ]
  113 + }
  114 + }
  115 + },
  116 + methods: {
  117 + open() {
  118 + this.formData.communityId = getCommunityId()
  119 + this.visible = true
  120 + this.$nextTick(() => {
  121 + this.$refs.form.resetFields()
  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 saveReserveCatalog(this.formData)
  132 + this.$message.success(this.$t('reserveCatalogManage.add.success'))
  133 + this.visible = false
  134 + this.$emit('success')
  135 + } catch (error) {
  136 + this.$message.error(this.$t('reserveCatalogManage.add.error'))
  137 + }
  138 + }
  139 + })
  140 + }
  141 + }
  142 +}
  143 +</script>
0 \ No newline at end of file 144 \ No newline at end of file
src/components/scm/applyWithholdGold.vue 0 → 100644
  1 +<template>
  2 + <div class="apply-withhold-gold-container">
  3 + <el-table v-loading="loading" :data="applys" border style="width: 100%">
  4 + <el-table-column prop="gwId" :label="$t('applyWithholdGold.id')" align="center" />
  5 + <el-table-column prop="goldId" :label="$t('applyWithholdGold.goldId')" align="center" />
  6 + <el-table-column prop="goldName" :label="$t('applyWithholdGold.accountName')" align="center" />
  7 + <el-table-column prop="communityId" :label="$t('applyWithholdGold.communityId')" align="center" />
  8 + <el-table-column prop="amount" :label="$t('applyWithholdGold.withdrawAmount')" align="center" />
  9 + <el-table-column prop="applyUserName" :label="$t('applyWithholdGold.applicant')" align="center" />
  10 + <el-table-column prop="applyUserTel" :label="$t('applyWithholdGold.applicantPhone')" align="center" />
  11 + <el-table-column prop="bankNum" :label="$t('applyWithholdGold.bankAccount')" align="center" />
  12 + <el-table-column prop="bankNumName" :label="$t('applyWithholdGold.accountName')" align="center" />
  13 + <el-table-column prop="bankName" :label="$t('applyWithholdGold.bankName')" align="center" />
  14 + <el-table-column prop="remark" :label="$t('applyWithholdGold.applicationNote')" align="center" />
  15 + <el-table-column prop="stateName" :label="$t('applyWithholdGold.status')" align="center" />
  16 + <el-table-column prop="stateMsg" :label="$t('applyWithholdGold.reviewNote')" align="center" />
  17 + <el-table-column :label="$t('common.operation')" align="center">
  18 + <template slot-scope="scope">
  19 + <el-button size="mini" type="danger" @click="openDeleteDialog(scope.row)">
  20 + {{ $t('common.delete') }}
  21 + </el-button>
  22 + </template>
  23 + </el-table-column>
  24 + </el-table>
  25 +
  26 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  27 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  28 + @current-change="handleCurrentChange" />
  29 +
  30 + <delete-apply-withhold-gold ref="deleteDialog" @success="handleSuccess" />
  31 + </div>
  32 +</template>
  33 +
  34 +<script>
  35 +import { getCommunityId } from '@/api/community/communityApi'
  36 +import { getPropertyGoldApplys } from '@/api/scm/goldApi'
  37 +import DeleteApplyWithholdGold from '@/components/scm/deleteApplyWithholdGold'
  38 +
  39 +export default {
  40 + name: 'ApplyWithholdGold',
  41 + components: {
  42 + DeleteApplyWithholdGold
  43 + },
  44 + data() {
  45 + return {
  46 + goldId: '',
  47 + goldName: '',
  48 + loading: false,
  49 + applys: [],
  50 + page: {
  51 + current: 1,
  52 + size: 10,
  53 + total: 0
  54 + }
  55 + }
  56 + },
  57 + methods: {
  58 + open(gold) {
  59 + this.goldId = gold.goldId
  60 + this.goldName = gold.goldName
  61 + this.loadData()
  62 + },
  63 + async loadData() {
  64 + if (!this.goldId) return
  65 +
  66 + try {
  67 + this.loading = true
  68 + const params = {
  69 + communityId: getCommunityId(),
  70 + goldId: this.goldId,
  71 + page: this.page.current,
  72 + row: this.page.size
  73 + }
  74 + const { data, total } = await getPropertyGoldApplys(params)
  75 + this.applys = data
  76 + this.page.total = total
  77 + } catch (error) {
  78 + console.error('Failed to load apply withhold gold:', error)
  79 + } finally {
  80 + this.loading = false
  81 + }
  82 + },
  83 + handleSizeChange(val) {
  84 + this.page.size = val
  85 + this.loadData()
  86 + },
  87 + handleCurrentChange(val) {
  88 + this.page.current = val
  89 + this.loadData()
  90 + },
  91 + openDeleteDialog(row) {
  92 + this.$refs.deleteDialog.open(row)
  93 + },
  94 + handleSuccess() {
  95 + this.loadData()
  96 + }
  97 + }
  98 +}
  99 +</script>
  100 +
  101 +<style lang="scss" scoped>
  102 +.apply-withhold-gold-container {
  103 + padding: 20px 0;
  104 +
  105 + .el-pagination {
  106 + margin-top: 20px;
  107 + text-align: right;
  108 + }
  109 +}
  110 +</style>
0 \ No newline at end of file 111 \ No newline at end of file
src/components/scm/applyWithholdIntegral.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table v-loading="loading" :data="applys" border style="width: 100%">
  4 + <el-table-column prop="iwId" :label="$t('applyWithholdIntegral.id')" align="center" />
  5 + <el-table-column prop="integralId" :label="$t('applyWithholdIntegral.integralId')" align="center" />
  6 + <el-table-column prop="integralName" :label="$t('applyWithholdIntegral.integralName')" align="center" />
  7 + <el-table-column prop="amount" :label="$t('applyWithholdIntegral.withdrawAmount')" align="center" />
  8 + <el-table-column prop="applyUserName" :label="$t('applyWithholdIntegral.applicant')" align="center" />
  9 + <el-table-column prop="applyUserTel" :label="$t('applyWithholdIntegral.applicantPhone')" align="center" />
  10 + <el-table-column prop="bankNum" :label="$t('applyWithholdIntegral.bankAccount')" align="center" />
  11 + <el-table-column prop="bankNumName" :label="$t('applyWithholdIntegral.accountName')" align="center" />
  12 + <el-table-column prop="bankName" :label="$t('applyWithholdIntegral.bank')" align="center" />
  13 + <el-table-column prop="remark" :label="$t('applyWithholdIntegral.applicationNote')" align="center" />
  14 + <el-table-column prop="stateName" :label="$t('applyWithholdIntegral.status')" align="center" />
  15 + <el-table-column prop="stateMsg" :label="$t('applyWithholdIntegral.reviewNote')" align="center" />
  16 + <el-table-column :label="$t('common.operation')" align="center" width="150">
  17 + <template slot-scope="scope">
  18 + <el-button size="mini" type="danger" @click="openDeleteDialog(scope.row)">
  19 + {{ $t('common.delete') }}
  20 + </el-button>
  21 + </template>
  22 + </el-table-column>
  23 + </el-table>
  24 +
  25 + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  26 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  27 + @current-change="handleCurrentChange" />
  28 +
  29 + <delete-apply-withhold-integral ref="deleteDialog" @success="handleDeleteSuccess" />
  30 + </div>
  31 +</template>
  32 +
  33 +<script>
  34 +import { queryCommunityIntegralApply } from '@/api/scm/communityIntegralApi'
  35 +import { getCommunityId } from '@/api/community/communityApi'
  36 +import DeleteApplyWithholdIntegral from './deleteApplyWithholdIntegral'
  37 +
  38 +export default {
  39 + name: 'ApplyWithholdIntegral',
  40 + components: {
  41 + DeleteApplyWithholdIntegral
  42 + },
  43 +
  44 + data() {
  45 + return {
  46 + integralId: '',
  47 + integralName: '',
  48 + loading: false,
  49 + applys: [],
  50 + pagination: {
  51 + current: 1,
  52 + size: 10,
  53 + total: 0
  54 + }
  55 + }
  56 + },
  57 + methods: {
  58 + open(integral) {
  59 + this.integralId = integral.integralId
  60 + this.integralName = integral.integralName
  61 + this.loadData()
  62 + },
  63 + async loadData() {
  64 + try {
  65 + this.loading = true
  66 + const params = {
  67 + communityId: getCommunityId(),
  68 + integralId: this.integralId,
  69 + page: this.pagination.current,
  70 + row: this.pagination.size
  71 + }
  72 + const { data, total } = await queryCommunityIntegralApply(params)
  73 + this.applys = data
  74 + this.pagination.total = total
  75 + } catch (error) {
  76 + console.error('Failed to load apply withhold integral data:', error)
  77 + } finally {
  78 + this.loading = false
  79 + }
  80 + },
  81 + openDeleteDialog(row) {
  82 + this.$refs.deleteDialog.open(row)
  83 + },
  84 + handleDeleteSuccess() {
  85 + this.loadData()
  86 + },
  87 + handleSizeChange(val) {
  88 + this.pagination.size = val
  89 + this.loadData()
  90 + },
  91 + handleCurrentChange(val) {
  92 + this.pagination.current = val
  93 + this.loadData()
  94 + }
  95 + }
  96 +}
  97 +</script>
  98 +
  99 +<style scoped>
  100 +.el-pagination {
  101 + margin-top: 20px;
  102 + text-align: right;
  103 +}
  104 +</style>
0 \ No newline at end of file 105 \ No newline at end of file
src/components/scm/communityIntegralDetail.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table v-loading="loading" :data="details" border style="width: 100%">
  4 + <el-table-column prop="detailId" :label="$t('communityIntegralDetail.id')" align="center" />
  5 + <el-table-column prop="integralName" :label="$t('communityIntegralDetail.integralAccount')" align="center" />
  6 + <el-table-column prop="detailType" :label="$t('communityIntegralDetail.type')" align="center">
  7 + <template slot-scope="scope">
  8 + {{ scope.row.detailType === '1001' ? $t('communityIntegralDetail.transferIn') :
  9 + $t('communityIntegralDetail.transferOut') }}
  10 + </template>
  11 + </el-table-column>
  12 + <el-table-column prop="amount" :label="$t('communityIntegralDetail.transactionAmount')" align="center" />
  13 + <el-table-column prop="totalAmount" :label="$t('communityIntegralDetail.currentAmount')" align="center" />
  14 + <el-table-column prop="orderId" :label="$t('communityIntegralDetail.transactionNo')" align="center" />
  15 + <el-table-column prop="remark" :label="$t('communityIntegralDetail.remark')" align="center" />
  16 + <el-table-column prop="createTime" :label="$t('communityIntegralDetail.time')" align="center" />
  17 + </el-table>
  18 +
  19 + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  20 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  21 + @current-change="handleCurrentChange" />
  22 + </div>
  23 +</template>
  24 +
  25 +<script>
  26 +import { queryCommunityIntegralDetail } from '@/api/scm/communityIntegralApi'
  27 +import { getCommunityId } from '@/api/community/communityApi'
  28 +
  29 +export default {
  30 + name: 'CommunityIntegralDetail',
  31 +
  32 + data() {
  33 + return {
  34 + integralId: '',
  35 + integralName: '',
  36 + loading: false,
  37 + details: [],
  38 + pagination: {
  39 + current: 1,
  40 + size: 10,
  41 + total: 0
  42 + }
  43 + }
  44 + },
  45 + methods: {
  46 + open(integral) {
  47 + this.integralId = integral.integralId
  48 + this.integralName = integral.integralName
  49 + this.loadData()
  50 + },
  51 + async loadData() {
  52 + try {
  53 + this.loading = true
  54 + const params = {
  55 + communityId: getCommunityId(),
  56 + integralId: this.integralId,
  57 + page: this.pagination.current,
  58 + row: this.pagination.size
  59 + }
  60 + const { data, total } = await queryCommunityIntegralDetail(params)
  61 + this.details = data
  62 + this.pagination.total = total
  63 + } catch (error) {
  64 + console.error('Failed to load community integral details:', error)
  65 + } finally {
  66 + this.loading = false
  67 + }
  68 + },
  69 + handleSizeChange(val) {
  70 + this.pagination.size = val
  71 + this.loadData()
  72 + },
  73 + handleCurrentChange(val) {
  74 + this.pagination.current = val
  75 + this.loadData()
  76 + }
  77 + }
  78 +}
  79 +</script>
  80 +
  81 +<style scoped>
  82 +.el-pagination {
  83 + margin-top: 20px;
  84 + text-align: right;
  85 +}
  86 +</style>
0 \ No newline at end of file 87 \ No newline at end of file
src/components/scm/deleteApplyWithholdGold.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteApplyWithholdGold.confirmTitle')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + :before-close="handleClose"
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('deleteApplyWithholdGold.confirmText') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  13 + <el-button type="primary" @click="confirmDelete" :loading="loading">
  14 + {{ $t('common.confirmDelete') }}
  15 + </el-button>
  16 + </span>
  17 + </el-dialog>
  18 +</template>
  19 +
  20 +<script>
  21 +import { deleteGoldWithHold } from '@/api/scm/goldApi'
  22 +
  23 +export default {
  24 + name: 'DeleteApplyWithholdGold',
  25 + data() {
  26 + return {
  27 + visible: false,
  28 + loading: false,
  29 + currentData: null
  30 + }
  31 + },
  32 + methods: {
  33 + open(data) {
  34 + this.currentData = data
  35 + this.visible = true
  36 + },
  37 + handleClose() {
  38 + this.visible = false
  39 + },
  40 + async confirmDelete() {
  41 + try {
  42 + this.loading = true
  43 + await deleteGoldWithHold({
  44 + gwId: this.currentData.gwId,
  45 + communityId: this.currentData.communityId
  46 + })
  47 + this.$emit('success')
  48 + this.$message.success(this.$t('deleteApplyWithholdGold.deleteSuccess'))
  49 + this.visible = false
  50 + } catch (error) {
  51 + console.error('Delete failed:', error)
  52 + this.$message.error(this.$t('deleteApplyWithholdGold.deleteFailed'))
  53 + } finally {
  54 + this.loading = false
  55 + }
  56 + }
  57 + }
  58 +}
  59 +</script>
0 \ No newline at end of file 60 \ No newline at end of file
src/components/scm/deleteApplyWithholdIntegral.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteApplyWithholdIntegral.confirmTitle')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + center
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('deleteApplyWithholdIntegral.confirmText') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="close">{{ $t('deleteApplyWithholdIntegral.cancel') }}</el-button>
  13 + <el-button type="primary" @click="confirmDelete" :loading="loading">
  14 + {{ $t('deleteApplyWithholdIntegral.confirmDelete') }}
  15 + </el-button>
  16 + </span>
  17 + </el-dialog>
  18 +</template>
  19 +
  20 +<script>
  21 +import { deleteIntegralWithdrawal } from '@/api/scm/communityIntegralApi'
  22 +import { getCommunityId } from '@/api/community/communityApi'
  23 +
  24 +export default {
  25 + name: 'DeleteApplyWithholdIntegral',
  26 + data() {
  27 + return {
  28 + visible: false,
  29 + loading: false,
  30 + currentData: null
  31 + }
  32 + },
  33 + methods: {
  34 + open(data) {
  35 + this.currentData = data
  36 + this.visible = true
  37 + },
  38 + close() {
  39 + this.visible = false
  40 + this.loading = false
  41 + },
  42 + async confirmDelete() {
  43 + try {
  44 + this.loading = true
  45 + const params = {
  46 + ...this.currentData,
  47 + communityId: getCommunityId()
  48 + }
  49 + await deleteIntegralWithdrawal(params)
  50 + this.$emit('success')
  51 + this.$message.success(this.$t('deleteApplyWithholdIntegral.deleteSuccess'))
  52 + this.close()
  53 + } catch (error) {
  54 + console.error('Failed to delete integral withdrawal:', error)
  55 + this.$message.error(this.$t('deleteApplyWithholdIntegral.deleteFailed'))
  56 + } finally {
  57 + this.loading = false
  58 + }
  59 + }
  60 + }
  61 +}
  62 +</script>
  63 +
  64 +<style scoped>
  65 +.text-center {
  66 + text-align: center;
  67 +}
  68 +</style>
0 \ No newline at end of file 69 \ No newline at end of file
src/components/scm/deleteReserveCatalog.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('reserveCatalogManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose"
  7 + >
  8 + <div class="delete-content">
  9 + <p>{{ $t('reserveCatalogManage.delete.confirmText1') }}</p>
  10 + <p class="delete-name">{{ formData.name }}</p>
  11 + <p>{{ $t('reserveCatalogManage.delete.confirmText2') }}</p>
  12 + </div>
  13 + <span slot="footer" class="dialog-footer">
  14 + <el-button @click="visible = false">
  15 + {{ $t('common.cancel') }}
  16 + </el-button>
  17 + <el-button type="primary" @click="handleSubmit">
  18 + {{ $t('common.confirm') }}
  19 + </el-button>
  20 + </span>
  21 + </el-dialog>
  22 +</template>
  23 +
  24 +<script>
  25 +import { deleteReserveCatalog } from '@/api/scm/reserveCatalogManageApi'
  26 +import { getCommunityId } from '@/api/community/communityApi'
  27 +
  28 +export default {
  29 + name: 'DeleteReserveCatalog',
  30 + data() {
  31 + return {
  32 + visible: false,
  33 + formData: {
  34 + catalogId: '',
  35 + name: '',
  36 + communityId: ''
  37 + }
  38 + }
  39 + },
  40 + methods: {
  41 + open(row) {
  42 + this.formData = {
  43 + catalogId: row.catalogId,
  44 + name: row.name,
  45 + communityId: getCommunityId()
  46 + }
  47 + this.visible = true
  48 + },
  49 + handleClose() {
  50 + this.formData = {
  51 + catalogId: '',
  52 + name: '',
  53 + communityId: ''
  54 + }
  55 + },
  56 + async handleSubmit() {
  57 + try {
  58 + await deleteReserveCatalog(this.formData)
  59 + this.$message.success(this.$t('reserveCatalogManage.delete.success'))
  60 + this.visible = false
  61 + this.$emit('success')
  62 + } catch (error) {
  63 + this.$message.error(this.$t('reserveCatalogManage.delete.error'))
  64 + }
  65 + }
  66 + }
  67 +}
  68 +</script>
  69 +
  70 +<style scoped>
  71 +.delete-content {
  72 + text-align: center;
  73 + font-size: 16px;
  74 +}
  75 +.delete-name {
  76 + font-weight: bold;
  77 + color: #f56c6c;
  78 + margin: 10px 0;
  79 +}
  80 +</style>
0 \ No newline at end of file 81 \ No newline at end of file
src/components/scm/editReserveCatalog.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('reserveCatalogManage.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('reserveCatalogManage.edit.name')"
  16 + prop="name"
  17 + >
  18 + <el-input
  19 + v-model="formData.name"
  20 + :placeholder="$t('reserveCatalogManage.edit.namePlaceholder')"
  21 + />
  22 + </el-form-item>
  23 + <el-form-item
  24 + :label="$t('reserveCatalogManage.edit.sort')"
  25 + prop="sort"
  26 + >
  27 + <el-input
  28 + v-model="formData.sort"
  29 + :placeholder="$t('reserveCatalogManage.edit.sortPlaceholder')"
  30 + />
  31 + </el-form-item>
  32 + <el-form-item
  33 + :label="$t('reserveCatalogManage.edit.type')"
  34 + prop="type"
  35 + >
  36 + <el-select
  37 + v-model="formData.type"
  38 + :placeholder="$t('reserveCatalogManage.edit.typePlaceholder')"
  39 + style="width:100%"
  40 + >
  41 + <el-option
  42 + :label="$t('reserveCatalogManage.edit.typeOption1')"
  43 + value="1001"
  44 + />
  45 + <el-option
  46 + :label="$t('reserveCatalogManage.edit.typeOption2')"
  47 + value="2002"
  48 + />
  49 + </el-select>
  50 + </el-form-item>
  51 + <el-form-item
  52 + :label="$t('reserveCatalogManage.edit.state')"
  53 + prop="state"
  54 + >
  55 + <el-select
  56 + v-model="formData.state"
  57 + :placeholder="$t('reserveCatalogManage.edit.statePlaceholder')"
  58 + style="width:100%"
  59 + >
  60 + <el-option
  61 + :label="$t('reserveCatalogManage.edit.stateOption1')"
  62 + value="1001"
  63 + />
  64 + <el-option
  65 + :label="$t('reserveCatalogManage.edit.stateOption2')"
  66 + value="2002"
  67 + />
  68 + </el-select>
  69 + </el-form-item>
  70 + </el-form>
  71 + <span slot="footer" class="dialog-footer">
  72 + <el-button @click="visible = false">
  73 + {{ $t('common.cancel') }}
  74 + </el-button>
  75 + <el-button type="primary" @click="handleSubmit">
  76 + {{ $t('common.confirm') }}
  77 + </el-button>
  78 + </span>
  79 + </el-dialog>
  80 +</template>
  81 +
  82 +<script>
  83 +import { updateReserveCatalog } from '@/api/scm/reserveCatalogManageApi'
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +
  86 +export default {
  87 + name: 'EditReserveCatalog',
  88 + data() {
  89 + return {
  90 + visible: false,
  91 + formData: {
  92 + catalogId: '',
  93 + name: '',
  94 + sort: '',
  95 + type: '',
  96 + state: '',
  97 + communityId: ''
  98 + },
  99 + rules: {
  100 + name: [
  101 + { required: true, message: this.$t('reserveCatalogManage.validate.nameRequired'), trigger: 'blur' },
  102 + { max: 128, message: this.$t('reserveCatalogManage.validate.nameMaxLength'), trigger: 'blur' }
  103 + ],
  104 + sort: [
  105 + { required: true, message: this.$t('reserveCatalogManage.validate.sortRequired'), trigger: 'blur' },
  106 + { max: 12, message: this.$t('reserveCatalogManage.validate.sortMaxLength'), trigger: 'blur' }
  107 + ],
  108 + type: [
  109 + { required: true, message: this.$t('reserveCatalogManage.validate.typeRequired'), trigger: 'change' }
  110 + ],
  111 + state: [
  112 + { required: true, message: this.$t('reserveCatalogManage.validate.stateRequired'), trigger: 'change' }
  113 + ],
  114 + catalogId: [
  115 + { required: true, message: this.$t('reserveCatalogManage.validate.catalogIdRequired'), trigger: 'blur' }
  116 + ]
  117 + }
  118 + }
  119 + },
  120 + methods: {
  121 + open(row) {
  122 + this.formData = {
  123 + ...row,
  124 + communityId: getCommunityId()
  125 + }
  126 + this.visible = true
  127 + this.$nextTick(() => {
  128 + this.$refs.form.clearValidate()
  129 + })
  130 + },
  131 + handleClose() {
  132 + this.$refs.form.resetFields()
  133 + },
  134 + handleSubmit() {
  135 + this.$refs.form.validate(async valid => {
  136 + if (valid) {
  137 + try {
  138 + await updateReserveCatalog(this.formData)
  139 + this.$message.success(this.$t('reserveCatalogManage.edit.success'))
  140 + this.visible = false
  141 + this.$emit('success')
  142 + } catch (error) {
  143 + this.$message.error(this.$t('reserveCatalogManage.edit.error'))
  144 + }
  145 + }
  146 + })
  147 + }
  148 + }
  149 +}
  150 +</script>
0 \ No newline at end of file 151 \ No newline at end of file
src/components/scm/goldDetail.vue 0 → 100644
  1 +<template>
  2 + <div class="gold-detail-container">
  3 + <el-table v-loading="loading" :data="goldDetails" border style="width: 100%">
  4 + <el-table-column prop="detailId" :label="$t('goldDetail.id')" align="center" />
  5 + <el-table-column prop="goldName" :label="$t('goldDetail.goldAccount')" align="center" />
  6 + <el-table-column :label="$t('goldDetail.type')" align="center">
  7 + <template slot-scope="scope">
  8 + {{ scope.row.detailType === '1001' ? $t('goldDetail.transferIn') : $t('goldDetail.transferOut') }}
  9 + </template>
  10 + </el-table-column>
  11 + <el-table-column prop="communityName" :label="$t('goldDetail.communityName')" align="center" />
  12 + <el-table-column prop="communityId" :label="$t('goldDetail.communityId')" align="center" />
  13 + <el-table-column prop="amount" :label="$t('goldDetail.transactionAmount')" align="center" />
  14 + <el-table-column prop="totalAmount" :label="$t('goldDetail.currentAmount')" align="center" />
  15 + <el-table-column prop="orderId" :label="$t('goldDetail.transactionNo')" align="center" />
  16 + <el-table-column prop="remark" :label="$t('goldDetail.remark')" align="center" />
  17 + <el-table-column prop="createTime" :label="$t('goldDetail.time')" align="center" />
  18 + </el-table>
  19 +
  20 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  21 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  22 + @current-change="handleCurrentChange" />
  23 + </div>
  24 +</template>
  25 +
  26 +<script>
  27 +import { getCommunityId } from '@/api/community/communityApi'
  28 +import { getPropertyGoldDetail } from '@/api/scm/goldApi'
  29 +
  30 +export default {
  31 + name: 'GoldDetail',
  32 +
  33 + data() {
  34 + return {
  35 + goldId: '',
  36 + goldName: '',
  37 + loading: false,
  38 + goldDetails: [],
  39 + page: {
  40 + current: 1,
  41 + size: 10,
  42 + total: 0
  43 + }
  44 + }
  45 + },
  46 + methods: {
  47 + open(gold) {
  48 + this.goldId = gold.goldId
  49 + this.goldName = gold.goldName
  50 + this.loadData()
  51 + },
  52 + async loadData() {
  53 + if (!this.goldId) return
  54 +
  55 + try {
  56 + this.loading = true
  57 + const params = {
  58 + communityId: getCommunityId(),
  59 + goldId: this.goldId,
  60 + page: this.page.current,
  61 + row: this.page.size
  62 + }
  63 + const { data, total } = await getPropertyGoldDetail(params)
  64 + this.goldDetails = data
  65 + this.page.total = total
  66 + } catch (error) {
  67 + console.error('Failed to load gold details:', error)
  68 + } finally {
  69 + this.loading = false
  70 + }
  71 + },
  72 + handleSizeChange(val) {
  73 + this.page.size = val
  74 + this.loadData()
  75 + },
  76 + handleCurrentChange(val) {
  77 + this.page.current = val
  78 + this.loadData()
  79 + }
  80 + }
  81 +}
  82 +</script>
  83 +
  84 +<style lang="scss" scoped>
  85 +.gold-detail-container {
  86 + padding: 20px 0;
  87 +
  88 + .el-pagination {
  89 + margin-top: 20px;
  90 + text-align: right;
  91 + }
  92 +}
  93 +</style>
0 \ No newline at end of file 94 \ No newline at end of file
src/components/scm/withholdGold.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('withholdGold.applyWithdraw')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="form"
  11 + :rules="rules"
  12 + label-width="120px"
  13 + label-position="right"
  14 + >
  15 + <el-row>
  16 + <el-col :span="12">
  17 + <el-form-item :label="$t('withholdGold.goldAmount')" prop="amount">
  18 + <el-input v-model="form.amount" disabled />
  19 + </el-form-item>
  20 + </el-col>
  21 + <el-col :span="12">
  22 + <el-form-item :label="$t('withholdGold.withdrawAmount')" prop="applyAmount">
  23 + <el-input v-model="form.applyAmount" />
  24 + </el-form-item>
  25 + </el-col>
  26 + </el-row>
  27 +
  28 + <el-row>
  29 + <el-col :span="12">
  30 + <el-form-item :label="$t('withholdGold.applicant')" prop="applyUserName">
  31 + <el-input v-model="form.applyUserName" />
  32 + </el-form-item>
  33 + </el-col>
  34 + <el-col :span="12">
  35 + <el-form-item :label="$t('withholdGold.applicantPhone')" prop="applyUserTel">
  36 + <el-input v-model="form.applyUserTel" />
  37 + </el-form-item>
  38 + </el-col>
  39 + </el-row>
  40 +
  41 + <el-row>
  42 + <el-col :span="12">
  43 + <el-form-item :label="$t('withholdGold.bankAccount')" prop="bankNum">
  44 + <el-input v-model="form.bankNum" />
  45 + </el-form-item>
  46 + </el-col>
  47 + <el-col :span="12">
  48 + <el-form-item :label="$t('withholdGold.accountName')" prop="bankNumName">
  49 + <el-input v-model="form.bankNumName" />
  50 + </el-form-item>
  51 + </el-col>
  52 + </el-row>
  53 +
  54 + <el-row>
  55 + <el-col :span="12">
  56 + <el-form-item :label="$t('withholdGold.bankName')" prop="bankName">
  57 + <el-input v-model="form.bankName" type="textarea" :rows="2" />
  58 + </el-form-item>
  59 + </el-col>
  60 + <el-col :span="12">
  61 + <el-form-item :label="$t('withholdGold.applicationNote')" prop="remark">
  62 + <el-input v-model="form.remark" type="textarea" :rows="2" />
  63 + </el-form-item>
  64 + </el-col>
  65 + </el-row>
  66 + </el-form>
  67 +
  68 + <span slot="footer" class="dialog-footer">
  69 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  70 + <el-button
  71 + type="primary"
  72 + @click="submitForm"
  73 + :loading="loading"
  74 + >
  75 + {{ $t('common.submit') }}
  76 + </el-button>
  77 + </span>
  78 + </el-dialog>
  79 +</template>
  80 +
  81 +<script>
  82 +import { applyGoldWithHold } from '@/api/scm/goldApi'
  83 +import { getCommunityId } from '@/api/community/communityApi'
  84 +
  85 +export default {
  86 + name: 'WithholdGold',
  87 + data() {
  88 + return {
  89 + visible: false,
  90 + loading: false,
  91 + form: {
  92 + goldId: '',
  93 + goldName: '',
  94 + communityId: '',
  95 + amount: '',
  96 + applyAmount: '',
  97 + applyUserName: '',
  98 + applyUserTel: '',
  99 + remark: '',
  100 + bankNum: '',
  101 + bankNumName: '',
  102 + bankName: ''
  103 + },
  104 + rules: {
  105 + applyAmount: [
  106 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  107 + ],
  108 + applyUserName: [
  109 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  110 + ],
  111 + applyUserTel: [
  112 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  113 + ],
  114 + bankNum: [
  115 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  116 + ],
  117 + bankNumName: [
  118 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  119 + ],
  120 + bankName: [
  121 + { required: true, message: this.$t('withholdGold.required'), trigger: 'blur' }
  122 + ]
  123 + }
  124 + }
  125 + },
  126 + methods: {
  127 + open(data) {
  128 + this.form = {
  129 + ...this.form,
  130 + goldId: data.goldId,
  131 + amount: data.amount,
  132 + communityId: data.communityId || getCommunityId()
  133 + }
  134 + this.visible = true
  135 + this.$nextTick(() => {
  136 + this.$refs.form && this.$refs.form.clearValidate()
  137 + })
  138 + },
  139 + handleClose() {
  140 + this.visible = false
  141 + },
  142 + submitForm() {
  143 + this.$refs.form.validate(async valid => {
  144 + if (!valid) return
  145 +
  146 + try {
  147 + this.loading = true
  148 + await applyGoldWithHold(this.form)
  149 + this.$emit('success')
  150 + this.$message.success(this.$t('withholdGold.submitSuccess'))
  151 + this.visible = false
  152 + } catch (error) {
  153 + console.error('Submit failed:', error)
  154 + this.$message.error(this.$t('withholdGold.submitFailed'))
  155 + } finally {
  156 + this.loading = false
  157 + }
  158 + })
  159 + }
  160 + }
  161 +}
  162 +</script>
  163 +
  164 +<style scoped>
  165 +.el-textarea {
  166 + width: 100%;
  167 +}
  168 +</style>
0 \ No newline at end of file 169 \ No newline at end of file
src/components/scm/withholdIntegral.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('withholdIntegral.applyWithdraw')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + center
  7 + >
  8 + <el-form ref="form" :model="formData" label-width="120px" :rules="rules">
  9 + <el-row>
  10 + <el-col :span="12">
  11 + <el-form-item :label="$t('withholdIntegral.totalPoints')" prop="amount">
  12 + <el-input v-model="formData.amount" disabled />
  13 + </el-form-item>
  14 + </el-col>
  15 + <el-col :span="12">
  16 + <el-form-item :label="$t('withholdIntegral.withdrawPoints')" prop="applyAmount">
  17 + <el-input
  18 + v-model="formData.applyAmount"
  19 + :placeholder="$t('withholdIntegral.withdrawPointsPlaceholder')"
  20 + />
  21 + </el-form-item>
  22 + </el-col>
  23 + </el-row>
  24 +
  25 + <el-row>
  26 + <el-col :span="12">
  27 + <el-form-item :label="$t('withholdIntegral.applicant')" prop="applyUserName">
  28 + <el-input
  29 + v-model="formData.applyUserName"
  30 + :placeholder="$t('withholdIntegral.applicantPlaceholder')"
  31 + />
  32 + </el-form-item>
  33 + </el-col>
  34 + <el-col :span="12">
  35 + <el-form-item :label="$t('withholdIntegral.applicantPhone')" prop="applyUserTel">
  36 + <el-input
  37 + v-model="formData.applyUserTel"
  38 + :placeholder="$t('withholdIntegral.applicantPhonePlaceholder')"
  39 + />
  40 + </el-form-item>
  41 + </el-col>
  42 + </el-row>
  43 +
  44 + <el-row>
  45 + <el-col :span="12">
  46 + <el-form-item :label="$t('withholdIntegral.bankAccount')" prop="bankNum">
  47 + <el-input
  48 + v-model="formData.bankNum"
  49 + :placeholder="$t('withholdIntegral.bankAccountPlaceholder')"
  50 + />
  51 + </el-form-item>
  52 + </el-col>
  53 + <el-col :span="12">
  54 + <el-form-item :label="$t('withholdIntegral.accountName')" prop="bankNumName">
  55 + <el-input
  56 + v-model="formData.bankNumName"
  57 + :placeholder="$t('withholdIntegral.accountNamePlaceholder')"
  58 + />
  59 + </el-form-item>
  60 + </el-col>
  61 + </el-row>
  62 +
  63 + <el-row>
  64 + <el-col :span="12">
  65 + <el-form-item :label="$t('withholdIntegral.bank')" prop="bankName">
  66 + <el-input
  67 + v-model="formData.bankName"
  68 + type="textarea"
  69 + :placeholder="$t('withholdIntegral.bankPlaceholder')"
  70 + />
  71 + </el-form-item>
  72 + </el-col>
  73 + <el-col :span="12">
  74 + <el-form-item :label="$t('withholdIntegral.applicationNote')" prop="remark">
  75 + <el-input
  76 + v-model="formData.remark"
  77 + type="textarea"
  78 + :placeholder="$t('withholdIntegral.applicationNotePlaceholder')"
  79 + />
  80 + </el-form-item>
  81 + </el-col>
  82 + </el-row>
  83 + </el-form>
  84 +
  85 + <span slot="footer" class="dialog-footer">
  86 + <el-button @click="close">{{ $t('common.cancel') }}</el-button>
  87 + <el-button type="primary" @click="submit" :loading="loading">
  88 + {{ $t('common.submit') }}
  89 + </el-button>
  90 + </span>
  91 + </el-dialog>
  92 +</template>
  93 +
  94 +<script>
  95 +import { applyIntegralWithdrawal } from '@/api/scm/communityIntegralApi'
  96 +import { getCommunityId } from '@/api/community/communityApi'
  97 +
  98 +export default {
  99 + name: 'WithholdIntegral',
  100 + data() {
  101 + return {
  102 + visible: false,
  103 + loading: false,
  104 + formData: {
  105 + integralId: '',
  106 + integralName: '',
  107 + communityId: '',
  108 + amount: '',
  109 + applyAmount: '',
  110 + applyUserName: '',
  111 + applyUserTel: '',
  112 + remark: '',
  113 + bankNum: '',
  114 + bankNumName: '',
  115 + bankName: ''
  116 + },
  117 + rules: {
  118 + applyAmount: [
  119 + { required: true, message: this.$t('withholdIntegral.withdrawPointsRequired'), trigger: 'blur' }
  120 + ],
  121 + applyUserName: [
  122 + { required: true, message: this.$t('withholdIntegral.applicantRequired'), trigger: 'blur' }
  123 + ],
  124 + applyUserTel: [
  125 + { required: true, message: this.$t('withholdIntegral.applicantPhoneRequired'), trigger: 'blur' }
  126 + ],
  127 + bankNum: [
  128 + { required: true, message: this.$t('withholdIntegral.bankAccountRequired'), trigger: 'blur' }
  129 + ],
  130 + bankNumName: [
  131 + { required: true, message: this.$t('withholdIntegral.accountNameRequired'), trigger: 'blur' }
  132 + ],
  133 + bankName: [
  134 + { required: true, message: this.$t('withholdIntegral.bankRequired'), trigger: 'blur' }
  135 + ]
  136 + }
  137 + }
  138 + },
  139 + methods: {
  140 + open(data) {
  141 + this.resetForm()
  142 + this.formData = {
  143 + ...this.formData,
  144 + ...data,
  145 + communityId: getCommunityId()
  146 + }
  147 + this.visible = true
  148 + },
  149 + close() {
  150 + this.visible = false
  151 + this.loading = false
  152 + this.$refs.form.resetFields()
  153 + },
  154 + resetForm() {
  155 + if (this.$refs.form) {
  156 + this.$refs.form.resetFields()
  157 + }
  158 + },
  159 + async submit() {
  160 + try {
  161 + this.$refs.form.validate(async valid => {
  162 + if (!valid) return
  163 +
  164 + this.loading = true
  165 + await applyIntegralWithdrawal(this.formData)
  166 + this.$emit('success')
  167 + this.$message.success(this.$t('withholdIntegral.applySuccess'))
  168 + this.close()
  169 + })
  170 + } catch (error) {
  171 + console.error('Failed to apply integral withdrawal:', error)
  172 + this.$message.error(this.$t('withholdIntegral.applyFailed'))
  173 + } finally {
  174 + this.loading = false
  175 + }
  176 + }
  177 + }
  178 +}
  179 +</script>
  180 +
  181 +<style scoped>
  182 +.el-textarea {
  183 + width: 100%;
  184 +}
  185 +</style>
0 \ No newline at end of file 186 \ No newline at end of file
src/i18n/scmI18n.js
@@ -7,6 +7,9 @@ import { messages as couponPropertyUserDetailMessages } from &#39;../views/scm/coupo @@ -7,6 +7,9 @@ import { messages as couponPropertyUserDetailMessages } from &#39;../views/scm/coupo
7 import { messages as integralConfigManageMessages } from '../views/scm/integralConfigManageLang' 7 import { messages as integralConfigManageMessages } from '../views/scm/integralConfigManageLang'
8 import { messages as integralRuleMessages } from '../views/scm/integralRuleLang' 8 import { messages as integralRuleMessages } from '../views/scm/integralRuleLang'
9 import { messages as integralGiftDetailManageMessages } from '../views/scm/integralGiftDetailManageLang' 9 import { messages as integralGiftDetailManageMessages } from '../views/scm/integralGiftDetailManageLang'
  10 +import { messages as communityIntegralMessages } from '../views/scm/communityIntegralLang'
  11 +import { messages as goldMessages } from '../views/scm/goldLang'
  12 +import { messages as reserveCatalogManageMessages } from '../views/scm/reserveCatalogManageLang'
10 13
11 export const messages = { 14 export const messages = {
12 en: { 15 en: {
@@ -20,6 +23,9 @@ export const messages = { @@ -20,6 +23,9 @@ export const messages = {
20 ...integralConfigManageMessages.en, 23 ...integralConfigManageMessages.en,
21 ...integralRuleMessages.en, 24 ...integralRuleMessages.en,
22 ...integralGiftDetailManageMessages.en, 25 ...integralGiftDetailManageMessages.en,
  26 + ...communityIntegralMessages.en,
  27 + ...goldMessages.en,
  28 + ...reserveCatalogManageMessages.en,
23 }, 29 },
24 zh: { 30 zh: {
25 ...couponMarketMessages.zh, 31 ...couponMarketMessages.zh,
@@ -31,5 +37,8 @@ export const messages = { @@ -31,5 +37,8 @@ export const messages = {
31 ...integralConfigManageMessages.zh, 37 ...integralConfigManageMessages.zh,
32 ...integralRuleMessages.zh, 38 ...integralRuleMessages.zh,
33 ...integralGiftDetailManageMessages.zh, 39 ...integralGiftDetailManageMessages.zh,
  40 + ...communityIntegralMessages.zh,
  41 + ...goldMessages.zh,
  42 + ...reserveCatalogManageMessages.zh,
34 } 43 }
35 } 44 }
36 \ No newline at end of file 45 \ No newline at end of file
src/router/scmRouter.js
@@ -44,4 +44,19 @@ export default [ @@ -44,4 +44,19 @@ export default [
44 name: '/pages/scm/integralGiftDetailManage', 44 name: '/pages/scm/integralGiftDetailManage',
45 component: () => import('@/views/scm/integralGiftDetailManageList.vue') 45 component: () => import('@/views/scm/integralGiftDetailManageList.vue')
46 }, 46 },
  47 + {
  48 + path: '/pages/scm/communityIntegral',
  49 + name: '/pages/scm/communityIntegral',
  50 + component: () => import('@/views/scm/communityIntegralList.vue')
  51 + },
  52 + {
  53 + path: '/pages/scm/gold',
  54 + name: '/pages/scm/gold',
  55 + component: () => import('@/views/scm/goldList.vue')
  56 + },
  57 + {
  58 + path: '/pages/reserve/reserveCatalogManage',
  59 + name: '/pages/reserve/reserveCatalogManage',
  60 + component: () => import('@/views/scm/reserveCatalogManageList.vue')
  61 + },
47 ] 62 ]
48 \ No newline at end of file 63 \ No newline at end of file
src/views/scm/communityIntegralLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + communityIntegral: {
  4 + title: 'Community Points',
  5 + accountId: 'Account ID:',
  6 + accountName: 'Account Name:',
  7 + points: 'Points:',
  8 + withdraw: 'Withdraw',
  9 + transactionDetails: 'Transaction Details',
  10 + pointsWithdrawal: 'Points Withdrawal'
  11 + },
  12 + communityIntegralDetail: {
  13 + id: 'ID',
  14 + integralAccount: 'Points Account',
  15 + type: 'Type',
  16 + transferIn: 'Transfer In',
  17 + transferOut: 'Transfer Out',
  18 + transactionAmount: 'Amount',
  19 + currentAmount: 'Balance',
  20 + transactionNo: 'Transaction No',
  21 + remark: 'Remark',
  22 + time: 'Time'
  23 + },
  24 + applyWithholdIntegral: {
  25 + id: 'ID',
  26 + integralId: 'Points ID',
  27 + integralName: 'Points Name',
  28 + withdrawAmount: 'Amount',
  29 + applicant: 'Applicant',
  30 + applicantPhone: 'Phone',
  31 + bankAccount: 'Bank Account',
  32 + accountName: 'Account Name',
  33 + bank: 'Bank',
  34 + applicationNote: 'Note',
  35 + status: 'Status',
  36 + reviewNote: 'Review Note'
  37 + },
  38 + deleteApplyWithholdIntegral: {
  39 + confirmTitle: 'Confirm Operation',
  40 + confirmText: 'Are you sure to delete this withdrawal application?',
  41 + cancel: 'Cancel',
  42 + confirmDelete: 'Confirm Delete',
  43 + deleteSuccess: 'Delete successfully',
  44 + deleteFailed: 'Delete failed'
  45 + },
  46 + withholdIntegral: {
  47 + applyWithdraw: 'Apply Withdrawal',
  48 + totalPoints: 'Total Points',
  49 + withdrawPoints: 'Withdraw Points',
  50 + withdrawPointsPlaceholder: 'Required, please enter withdraw points',
  51 + withdrawPointsRequired: 'Withdraw points is required',
  52 + applicant: 'Applicant',
  53 + applicantPlaceholder: 'Required, please enter applicant name',
  54 + applicantRequired: 'Applicant is required',
  55 + applicantPhone: 'Phone',
  56 + applicantPhonePlaceholder: 'Required, please enter phone number',
  57 + applicantPhoneRequired: 'Phone is required',
  58 + bankAccount: 'Bank Account',
  59 + bankAccountPlaceholder: 'Required, please enter bank account',
  60 + bankAccountRequired: 'Bank account is required',
  61 + accountName: 'Account Name',
  62 + accountNamePlaceholder: 'Required, please enter account name',
  63 + accountNameRequired: 'Account name is required',
  64 + bank: 'Bank',
  65 + bankPlaceholder: 'Required, please enter bank name',
  66 + bankRequired: 'Bank is required',
  67 + applicationNote: 'Note',
  68 + applicationNotePlaceholder: 'Required, please enter application note',
  69 + applySuccess: 'Apply successfully',
  70 + applyFailed: 'Apply failed'
  71 + }
  72 + },
  73 + zh: {
  74 + communityIntegral: {
  75 + title: '小区积分',
  76 + accountId: '账户ID:',
  77 + accountName: '账户名称:',
  78 + points: '积分数:',
  79 + withdraw: '提现',
  80 + transactionDetails: '交易明细',
  81 + pointsWithdrawal: '积分提现'
  82 + },
  83 + communityIntegralDetail: {
  84 + id: '编号',
  85 + integralAccount: '金币账户',
  86 + type: '类型',
  87 + transferIn: '转入',
  88 + transferOut: '转出',
  89 + transactionAmount: '交易金额',
  90 + currentAmount: '当前金额',
  91 + transactionNo: '交易单号',
  92 + remark: '备注',
  93 + time: '时间'
  94 + },
  95 + applyWithholdIntegral: {
  96 + id: '编号',
  97 + integralId: '积分ID',
  98 + integralName: '积分名称',
  99 + withdrawAmount: '提现金额',
  100 + applicant: '申请人',
  101 + applicantPhone: '申请人电话',
  102 + bankAccount: '银行账户',
  103 + accountName: '账号名称',
  104 + bank: '开户行',
  105 + applicationNote: '申请说明',
  106 + status: '状态',
  107 + reviewNote: '审核说明'
  108 + },
  109 + deleteApplyWithholdIntegral: {
  110 + confirmTitle: '请确认您的操作!',
  111 + confirmText: '确定删除申请',
  112 + cancel: '点错了',
  113 + confirmDelete: '确认删除',
  114 + deleteSuccess: '删除成功',
  115 + deleteFailed: '删除失败'
  116 + },
  117 + withholdIntegral: {
  118 + applyWithdraw: '申请提现',
  119 + totalPoints: '总积分数',
  120 + withdrawPoints: '提现积分',
  121 + withdrawPointsPlaceholder: '必填,请填写提现积分',
  122 + withdrawPointsRequired: '提现积分不能为空',
  123 + applicant: '申请人',
  124 + applicantPlaceholder: '必填,请填写申请人',
  125 + applicantRequired: '申请人不能为空',
  126 + applicantPhone: '申请人电话',
  127 + applicantPhonePlaceholder: '必填,请填写申请人电话',
  128 + applicantPhoneRequired: '申请人电话不能为空',
  129 + bankAccount: '银行账户',
  130 + bankAccountPlaceholder: '必填,请填写银行账户',
  131 + bankAccountRequired: '银行账户不能为空',
  132 + accountName: '账号名称',
  133 + accountNamePlaceholder: '必填,请填写账号名称',
  134 + accountNameRequired: '账号名称不能为空',
  135 + bank: '开户行',
  136 + bankPlaceholder: '必填,请填写开户行',
  137 + bankRequired: '开户行不能为空',
  138 + applicationNote: '申请说明',
  139 + applicationNotePlaceholder: '必填,请填写申请说明',
  140 + applySuccess: '申请成功',
  141 + applyFailed: '申请失败'
  142 + }
  143 + }
  144 +}
0 \ No newline at end of file 145 \ No newline at end of file
src/views/scm/communityIntegralList.vue 0 → 100644
  1 +<template>
  2 + <el-card class="community-integral-container">
  3 + <div class="white-bg padding-lg padding-top border-radius">
  4 + <div class="flex justify-between">
  5 + <h3>{{ $t('communityIntegral.title') }}</h3>
  6 + </div>
  7 +
  8 + <!-- 业主信息 -->
  9 + <div class="margin-top">
  10 + <el-row>
  11 + <el-col :span="8">
  12 + <div class="form-group">
  13 + <label class="col-form-label">
  14 + {{ $t('communityIntegral.accountId') }}
  15 + </label>
  16 + <label>{{ communityIntegralInfo.integralId }}</label>
  17 + </div>
  18 + </el-col>
  19 + <el-col :span="8">
  20 + <div class="form-group">
  21 + <label class="col-form-label">
  22 + {{ $t('communityIntegral.accountName') }}
  23 + </label>
  24 + <label>{{ communityIntegralInfo.integralName }}</label>
  25 + </div>
  26 + </el-col>
  27 + <el-col :span="8">
  28 + <div class="form-group">
  29 + <label class="col-form-label">
  30 + {{ $t('communityIntegral.points') }}
  31 + </label>
  32 + <label>
  33 + {{ communityIntegralInfo.amount }}
  34 + <el-link type="primary" @click="openApplyWithholdIntegral">{{ $t('communityIntegral.withdraw')
  35 + }}</el-link>
  36 + </label>
  37 + </div>
  38 + </el-col>
  39 + </el-row>
  40 + </div>
  41 +
  42 + <el-divider></el-divider>
  43 +
  44 + <div class="margin-top-sm">
  45 + <el-tabs v-model="communityIntegralInfo._currentTab" @tab-click="changeTab(communityIntegralInfo._currentTab)">
  46 + <el-tab-pane :label="$t('communityIntegral.transactionDetails')" name="communityIntegralDetail">
  47 + <community-integral-detail v-if="communityIntegralInfo._currentTab === 'communityIntegralDetail'"
  48 + ref="communityIntegralDetail" />
  49 + </el-tab-pane>
  50 + <el-tab-pane :label="$t('communityIntegral.pointsWithdrawal')" name="applyWithholdIntegral">
  51 + <apply-withhold-integral v-if="communityIntegralInfo._currentTab === 'applyWithholdIntegral'"
  52 + ref="applyWithholdIntegral" />
  53 + </el-tab-pane>
  54 + </el-tabs>
  55 + </div>
  56 + </div>
  57 +
  58 + <withhold-integral ref="withholdIntegral" @success="handleWithdrawSuccess" />
  59 + </el-card>
  60 +</template>
  61 +
  62 +<script>
  63 +import { getCommunityId } from '@/api/community/communityApi'
  64 +import { queryCommunityIntegral } from '@/api/scm/communityIntegralApi'
  65 +import CommunityIntegralDetail from '@/components/scm/communityIntegralDetail'
  66 +import ApplyWithholdIntegral from '@/components/scm/applyWithholdIntegral'
  67 +import WithholdIntegral from '@/components/scm/withholdIntegral'
  68 +
  69 +export default {
  70 + name: 'CommunityIntegralList',
  71 + components: {
  72 + CommunityIntegralDetail,
  73 + ApplyWithholdIntegral,
  74 + WithholdIntegral
  75 + },
  76 + data() {
  77 + return {
  78 + communityIntegralInfo: {
  79 + integralId: "",
  80 + integralName: '',
  81 + amount: "",
  82 + communityName: "",
  83 + communityId: "",
  84 + _currentTab: 'communityIntegralDetail'
  85 + }
  86 + }
  87 + },
  88 + created() {
  89 + this.communityIntegralInfo.communityId = getCommunityId()
  90 + this.loadCommunityIntegralInfo()
  91 + },
  92 + methods: {
  93 + async loadCommunityIntegralInfo() {
  94 + try {
  95 + const params = {
  96 + page: 1,
  97 + row: 1,
  98 + communityId: this.communityIntegralInfo.communityId
  99 + }
  100 + const { data } = await queryCommunityIntegral(params)
  101 + if (data && data.length > 0) {
  102 + this.communityIntegralInfo = {
  103 + ...this.communityIntegralInfo,
  104 + ...data[0]
  105 + }
  106 + this.changeTab(this.communityIntegralInfo._currentTab)
  107 + }
  108 + } catch (error) {
  109 + console.error('Failed to load community integral info:', error)
  110 + }
  111 + },
  112 + changeTab(tab) {
  113 + this.communityIntegralInfo._currentTab = tab
  114 + setTimeout(() => {
  115 + this.$refs[tab].open(this.communityIntegralInfo.curIntegralRule)
  116 + }, 500);
  117 + },
  118 + openApplyWithholdIntegral() {
  119 + this.$refs.withholdIntegral.open({
  120 + integralId: this.communityIntegralInfo.integralId,
  121 + amount: this.communityIntegralInfo.amount,
  122 + communityId: this.communityIntegralInfo.communityId
  123 + })
  124 + },
  125 + handleWithdrawSuccess() {
  126 + this.communityIntegralInfo._currentTab = 'applyWithholdIntegral'
  127 + this.changeTab(this.communityIntegralInfo._currentTab)
  128 + this.loadCommunityIntegralInfo()
  129 + }
  130 + }
  131 +}
  132 +</script>
  133 +
  134 +<style scoped>
  135 +.community-integral-container {
  136 + padding: 20px;
  137 +}
  138 +
  139 +.white-bg {
  140 + background-color: #fff;
  141 +}
  142 +
  143 +.padding-lg {
  144 + padding: 20px;
  145 +}
  146 +
  147 +.padding-top {
  148 + padding-top: 20px;
  149 +}
  150 +
  151 +.border-radius {
  152 + border-radius: 4px;
  153 +}
  154 +
  155 +.margin-top {
  156 + margin-top: 20px;
  157 +}
  158 +
  159 +.margin-top-sm {
  160 + margin-top: 10px;
  161 +}
  162 +
  163 +.flex {
  164 + display: flex;
  165 +}
  166 +
  167 +.justify-between {
  168 + justify-content: space-between;
  169 +}
  170 +
  171 +.form-group {
  172 + margin-bottom: 20px;
  173 +}
  174 +
  175 +.col-form-label {
  176 + font-weight: bold;
  177 + margin-right: 10px;
  178 +}
  179 +</style>
0 \ No newline at end of file 180 \ No newline at end of file
src/views/scm/goldLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + gold: {
  4 + title: 'Community Gold',
  5 + withdraw: 'Withdraw',
  6 + transactionDetails: 'Transaction Details',
  7 + goldWithdrawal: 'Gold Withdrawal'
  8 + },
  9 + goldInfo: {
  10 + accountId: 'Account ID:',
  11 + accountName: 'Account Name:',
  12 + accountBalance: 'Account Balance:',
  13 + communityName: 'Community Name:'
  14 + },
  15 + goldDetail: {
  16 + id: 'ID',
  17 + goldAccount: 'Gold Account',
  18 + type: 'Type',
  19 + transferIn: 'Transfer In',
  20 + transferOut: 'Transfer Out',
  21 + communityName: 'Community Name',
  22 + communityId: 'Community ID',
  23 + transactionAmount: 'Transaction Amount',
  24 + currentAmount: 'Current Amount',
  25 + transactionNo: 'Transaction No',
  26 + remark: 'Remark',
  27 + time: 'Time'
  28 + },
  29 + applyWithholdGold: {
  30 + id: 'ID',
  31 + goldId: 'Gold ID',
  32 + accountName: 'Account Name',
  33 + communityId: 'Community ID',
  34 + withdrawAmount: 'Withdraw Amount',
  35 + applicant: 'Applicant',
  36 + applicantPhone: 'Applicant Phone',
  37 + bankAccount: 'Bank Account',
  38 + bankName: 'Bank Name',
  39 + applicationNote: 'Application Note',
  40 + status: 'Status',
  41 + reviewNote: 'Review Note'
  42 + },
  43 + deleteApplyWithholdGold: {
  44 + confirmTitle: 'Confirm Operation',
  45 + confirmText: 'Are you sure to delete this gold withdrawal application?',
  46 + deleteSuccess: 'Delete successfully',
  47 + deleteFailed: 'Delete failed'
  48 + },
  49 + withholdGold: {
  50 + applyWithdraw: 'Apply Withdraw',
  51 + goldAmount: 'Gold Amount',
  52 + withdrawAmount: 'Withdraw Amount',
  53 + applicant: 'Applicant',
  54 + applicantPhone: 'Applicant Phone',
  55 + bankAccount: 'Bank Account',
  56 + accountName: 'Account Name',
  57 + bankName: 'Bank Name',
  58 + applicationNote: 'Application Note',
  59 + required: 'Required',
  60 + submitSuccess: 'Submit successfully',
  61 + submitFailed: 'Submit failed'
  62 + }
  63 + },
  64 + zh: {
  65 + gold: {
  66 + title: '小区金币',
  67 + withdraw: '提现',
  68 + transactionDetails: '交易明细',
  69 + goldWithdrawal: '金币提现'
  70 + },
  71 + goldInfo: {
  72 + accountId: '账户ID:',
  73 + accountName: '账户名称:',
  74 + accountBalance: '账户余额:',
  75 + communityName: '小区名称:'
  76 + },
  77 + goldDetail: {
  78 + id: '编号',
  79 + goldAccount: '金币账户',
  80 + type: '类型',
  81 + transferIn: '转入',
  82 + transferOut: '转出',
  83 + communityName: '小区名称',
  84 + communityId: '小区编号',
  85 + transactionAmount: '交易金额',
  86 + currentAmount: '当前金额',
  87 + transactionNo: '交易单号',
  88 + remark: '备注',
  89 + time: '时间'
  90 + },
  91 + applyWithholdGold: {
  92 + id: '编号',
  93 + goldId: '金币ID',
  94 + accountName: '账户名称',
  95 + communityId: '小区编号',
  96 + withdrawAmount: '提现金额',
  97 + applicant: '申请人',
  98 + applicantPhone: '申请人电话',
  99 + bankAccount: '银行账户',
  100 + bankName: '开户行',
  101 + applicationNote: '申请说明',
  102 + status: '状态',
  103 + reviewNote: '审核说明'
  104 + },
  105 + deleteApplyWithholdGold: {
  106 + confirmTitle: '请确认您的操作!',
  107 + confirmText: '确定删除金币提现',
  108 + deleteSuccess: '删除成功',
  109 + deleteFailed: '删除失败'
  110 + },
  111 + withholdGold: {
  112 + applyWithdraw: '申请提现',
  113 + goldAmount: '金币金额',
  114 + withdrawAmount: '提现金额',
  115 + applicant: '申请人',
  116 + applicantPhone: '申请人电话',
  117 + bankAccount: '银行账户',
  118 + accountName: '账号名称',
  119 + bankName: '开户行',
  120 + applicationNote: '申请说明',
  121 + required: '必填',
  122 + submitSuccess: '提交成功',
  123 + submitFailed: '提交失败'
  124 + }
  125 + }
  126 +}
0 \ No newline at end of file 127 \ No newline at end of file
src/views/scm/goldList.vue 0 → 100644
  1 +<template>
  2 + <div class="gold-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <div class="flex justify-between">
  6 + <h3>{{ $t('gold.title') }}</h3>
  7 + <div></div>
  8 + </div>
  9 + </div>
  10 +
  11 + <!-- 业主信息 -->
  12 + <div class="margin-top">
  13 + <el-row>
  14 + <el-col :span="6">
  15 + <div class="form-group">
  16 + <label class="el-form-item__label">
  17 + {{ $t('goldInfo.accountId') }}
  18 + </label>
  19 + <div class="el-form-item__content">
  20 + {{ goldInfo.goldId }}
  21 + </div>
  22 + </div>
  23 + </el-col>
  24 + <el-col :span="6">
  25 + <div class="form-group">
  26 + <label class="el-form-item__label">
  27 + {{ $t('goldInfo.accountName') }}
  28 + </label>
  29 + <div class="el-form-item__content">
  30 + {{ goldInfo.goldName }}
  31 + </div>
  32 + </div>
  33 + </el-col>
  34 + <el-col :span="6">
  35 + <div class="form-group">
  36 + <label class="el-form-item__label">
  37 + {{ $t('goldInfo.accountBalance') }}
  38 + </label>
  39 + <div class="el-form-item__content">
  40 + {{ goldInfo.amount }}
  41 + <el-button type="text" @click="openApplyWithholdGold">
  42 + {{ $t('gold.withdraw') }}
  43 + </el-button>
  44 + </div>
  45 + </div>
  46 + </el-col>
  47 + <el-col :span="6">
  48 + <div class="form-group">
  49 + <label class="el-form-item__label">
  50 + {{ $t('goldInfo.communityName') }}
  51 + </label>
  52 + <div class="el-form-item__content">
  53 + {{ goldInfo.communityName }}
  54 + </div>
  55 + </div>
  56 + </el-col>
  57 + </el-row>
  58 + </div>
  59 +
  60 + <el-divider></el-divider>
  61 +
  62 + <div class="margin-top-sm">
  63 + <el-tabs v-model="goldInfo.currentTab" @tab-click="changeTab(goldInfo.currentTab)">
  64 + <el-tab-pane :label="$t('gold.transactionDetails')" name="goldDetail">
  65 + <gold-detail v-if="goldInfo.currentTab === 'goldDetail'" ref="goldDetail" />
  66 + </el-tab-pane>
  67 + <el-tab-pane :label="$t('gold.goldWithdrawal')" name="applyWithholdGold">
  68 + <apply-withhold-gold v-if="goldInfo.currentTab === 'applyWithholdGold'" ref="applyWithholdGold"
  69 + />
  70 + </el-tab-pane>
  71 + </el-tabs>
  72 + </div>
  73 +
  74 + <withhold-gold ref="withholdGold" @success="handleSuccess" />
  75 + </el-card>
  76 + </div>
  77 +</template>
  78 +
  79 +<script>
  80 +import { getCommunityId } from '@/api/community/communityApi'
  81 +import { getPropertyGoldInfo } from '@/api/scm/goldApi'
  82 +import GoldDetail from '@/components/scm/goldDetail'
  83 +import ApplyWithholdGold from '@/components/scm/applyWithholdGold'
  84 +import WithholdGold from '@/components/scm/withholdGold'
  85 +
  86 +export default {
  87 + name: 'GoldList',
  88 + components: {
  89 + GoldDetail,
  90 + ApplyWithholdGold,
  91 + WithholdGold
  92 + },
  93 + data() {
  94 + return {
  95 + goldInfo: {
  96 + goldId: '',
  97 + goldName: '',
  98 + amount: '',
  99 + communityName: '',
  100 + communityId: '',
  101 + currentTab: 'goldDetail'
  102 + }
  103 + }
  104 + },
  105 + created() {
  106 + this.communityId = getCommunityId()
  107 + this.loadGoldInfo()
  108 + },
  109 + methods: {
  110 + async loadGoldInfo() {
  111 + try {
  112 + const params = {
  113 + page: 1,
  114 + row: 1,
  115 + communityId: this.communityId
  116 + }
  117 + const { data } = await getPropertyGoldInfo(params)
  118 + if (data && data.length > 0) {
  119 + this.goldInfo = {
  120 + ...this.goldInfo,
  121 + goldId: data[0].goldId,
  122 + goldName: data[0].goldName,
  123 + amount: data[0].amount,
  124 + communityName: data[0].communityName,
  125 + communityId: data[0].communityId
  126 + }
  127 + }
  128 + } catch (error) {
  129 + console.error('Failed to load gold info:', error)
  130 + }
  131 + },
  132 + changeTab(tab) {
  133 + this.goldInfo.currentTab = tab.name || tab
  134 + setTimeout(() => {
  135 + this.$refs[tab].open(this.goldInfo)
  136 + }, 500);
  137 + },
  138 + openApplyWithholdGold() {
  139 + this.$refs.withholdGold.open({
  140 + goldId: this.goldInfo.goldId,
  141 + amount: this.goldInfo.amount,
  142 + communityId: this.goldInfo.communityId
  143 + })
  144 + },
  145 + handleSuccess() {
  146 + this.loadGoldInfo()
  147 + this.goldInfo.currentTab = 'applyWithholdGold'
  148 + }
  149 + }
  150 +}
  151 +</script>
  152 +
  153 +<style lang="scss" scoped>
  154 +.gold-container {
  155 + padding: 20px;
  156 +
  157 + .box-card {
  158 + margin-bottom: 20px;
  159 + }
  160 +
  161 + .margin-top {
  162 + margin-top: 20px;
  163 + }
  164 +
  165 + .margin-top-sm {
  166 + margin-top: 10px;
  167 + }
  168 +
  169 + .form-group {
  170 + margin-bottom: 0;
  171 + padding: 10px;
  172 + border-radius: 4px;
  173 + background-color: #f5f7fa;
  174 +
  175 + .el-form-item__label {
  176 + font-weight: bold;
  177 + color: #606266;
  178 + }
  179 +
  180 + .el-form-item__content {
  181 + margin-top: 5px;
  182 + }
  183 + }
  184 +}
  185 +</style>
0 \ No newline at end of file 186 \ No newline at end of file
src/views/scm/reserveCatalogManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + reserveCatalogManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + namePlaceholder: 'Please enter name',
  7 + typePlaceholder: 'Please select type',
  8 + typeOption1: 'Reservation Dining',
  9 + typeOption2: 'Reservation Service'
  10 + },
  11 + list: {
  12 + title: 'Reservation Catalog List'
  13 + },
  14 + table: {
  15 + type: 'Type',
  16 + type1: 'Reservation Dining',
  17 + type2: 'Reservation Service',
  18 + name: 'Name',
  19 + sort: 'Sort',
  20 + state: 'Status',
  21 + state1: 'Show',
  22 + state2: 'Hide',
  23 + createTime: 'Create Time'
  24 + },
  25 + add: {
  26 + title: 'Add Reservation Catalog',
  27 + name: 'Name',
  28 + namePlaceholder: 'Required, please enter name',
  29 + sort: 'Sort',
  30 + sortPlaceholder: 'Required, please enter sort',
  31 + type: 'Type',
  32 + typePlaceholder: 'Required, please select type',
  33 + typeOption1: 'Reservation Dining',
  34 + typeOption2: 'Reservation Service',
  35 + state: 'Status',
  36 + statePlaceholder: 'Required, please select status',
  37 + stateOption1: 'Show',
  38 + stateOption2: 'Hide',
  39 + success: 'Add successfully',
  40 + error: 'Add failed'
  41 + },
  42 + edit: {
  43 + title: 'Edit Reservation Catalog',
  44 + name: 'Name',
  45 + namePlaceholder: 'Required, please enter name',
  46 + sort: 'Sort',
  47 + sortPlaceholder: 'Required, please enter sort',
  48 + type: 'Type',
  49 + typePlaceholder: 'Required, please select type',
  50 + typeOption1: 'Reservation Dining',
  51 + typeOption2: 'Reservation Service',
  52 + state: 'Status',
  53 + statePlaceholder: 'Required, please select status',
  54 + stateOption1: 'Show',
  55 + stateOption2: 'Hide',
  56 + success: 'Edit successfully',
  57 + error: 'Edit failed'
  58 + },
  59 + delete: {
  60 + title: 'Delete Confirmation',
  61 + confirmText1: 'Are you sure to delete the reservation catalog',
  62 + confirmText2: '? This operation cannot be undone.',
  63 + success: 'Delete successfully',
  64 + error: 'Delete failed'
  65 + },
  66 + validate: {
  67 + nameRequired: 'Name is required',
  68 + nameMaxLength: 'Name cannot exceed 128 characters',
  69 + sortRequired: 'Sort is required',
  70 + sortMaxLength: 'Sort cannot exceed 12 characters',
  71 + typeRequired: 'Type is required',
  72 + stateRequired: 'Status is required',
  73 + catalogIdRequired: 'Catalog ID is required'
  74 + },
  75 + fetchError: 'Failed to fetch data'
  76 + }
  77 + },
  78 + zh: {
  79 + reserveCatalogManage: {
  80 + search: {
  81 + title: '查询条件',
  82 + namePlaceholder: '请输入名称',
  83 + typePlaceholder: '请选择类型',
  84 + typeOption1: '预约就餐',
  85 + typeOption2: '预约服务'
  86 + },
  87 + list: {
  88 + title: '预约目录列表'
  89 + },
  90 + table: {
  91 + type: '类型',
  92 + type1: '预约就餐',
  93 + type2: '预约服务',
  94 + name: '名称',
  95 + sort: '排序',
  96 + state: '状态',
  97 + state1: '展示',
  98 + state2: '不展示',
  99 + createTime: '创建时间'
  100 + },
  101 + add: {
  102 + title: '添加预约目录',
  103 + name: '名称',
  104 + namePlaceholder: '必填,请输入名称',
  105 + sort: '排序',
  106 + sortPlaceholder: '必填,请输入排序',
  107 + type: '类型',
  108 + typePlaceholder: '必填,请选择类型',
  109 + typeOption1: '预约就餐',
  110 + typeOption2: '预约服务',
  111 + state: '状态',
  112 + statePlaceholder: '必填,请选择状态',
  113 + stateOption1: '展示',
  114 + stateOption2: '不展示',
  115 + success: '添加成功',
  116 + error: '添加失败'
  117 + },
  118 + edit: {
  119 + title: '修改预约目录',
  120 + name: '名称',
  121 + namePlaceholder: '必填,请输入名称',
  122 + sort: '排序',
  123 + sortPlaceholder: '必填,请输入排序',
  124 + type: '类型',
  125 + typePlaceholder: '必填,请选择类型',
  126 + typeOption1: '预约就餐',
  127 + typeOption2: '预约服务',
  128 + state: '状态',
  129 + statePlaceholder: '必填,请选择状态',
  130 + stateOption1: '展示',
  131 + stateOption2: '不展示',
  132 + success: '修改成功',
  133 + error: '修改失败'
  134 + },
  135 + delete: {
  136 + title: '删除确认',
  137 + confirmText1: '确定要删除预约目录',
  138 + confirmText2: '?此操作不可撤销。',
  139 + success: '删除成功',
  140 + error: '删除失败'
  141 + },
  142 + validate: {
  143 + nameRequired: '名称不能为空',
  144 + nameMaxLength: '名称不能超过128个字符',
  145 + sortRequired: '排序不能为空',
  146 + sortMaxLength: '排序不能超过12个字符',
  147 + typeRequired: '类型不能为空',
  148 + stateRequired: '状态不能为空',
  149 + catalogIdRequired: '目录ID不能为空'
  150 + },
  151 + fetchError: '获取数据失败'
  152 + }
  153 + }
  154 +}
0 \ No newline at end of file 155 \ No newline at end of file
src/views/scm/reserveCatalogManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="reserve-catalog-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-wrapper">
  5 + <div slot="header" class="text-left">
  6 + <span>{{ $t('reserveCatalogManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="searchForm.name" :placeholder="$t('reserveCatalogManage.search.namePlaceholder')"
  11 + clearable />
  12 + </el-col>
  13 + <el-col :span="6">
  14 + <el-select v-model="searchForm.type" :placeholder="$t('reserveCatalogManage.search.typePlaceholder')"
  15 + style="width:100%">
  16 + <el-option :label="$t('reserveCatalogManage.search.typeOption1')" value="1001" />
  17 + <el-option :label="$t('reserveCatalogManage.search.typeOption2')" value="2002" />
  18 + </el-select>
  19 + </el-col>
  20 + <el-col :span="4">
  21 + <el-button type="primary" @click="handleSearch">
  22 + {{ $t('common.search') }}
  23 + </el-button>
  24 + </el-col>
  25 + </el-row>
  26 + </el-card>
  27 +
  28 + <!-- 列表 -->
  29 + <el-card class="list-wrapper">
  30 + <div slot="header" class="flex justify-between">
  31 + <span>{{ $t('reserveCatalogManage.list.title') }}</span>
  32 + <el-button type="primary" size="mini" @click="handleAdd">
  33 + {{ $t('common.add') }}
  34 + </el-button>
  35 + </div>
  36 +
  37 + <el-table v-loading="loading" :data="tableData" border style="width: 100%">
  38 + <el-table-column prop="type" :label="$t('reserveCatalogManage.table.type')" align="center">
  39 + <template slot-scope="scope">
  40 + {{ scope.row.type === '1001' ? $t('reserveCatalogManage.table.type1') :
  41 + $t('reserveCatalogManage.table.type2') }}
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column prop="name" :label="$t('reserveCatalogManage.table.name')" align="center" />
  45 + <el-table-column prop="sort" :label="$t('reserveCatalogManage.table.sort')" align="center" />
  46 + <el-table-column prop="state" :label="$t('reserveCatalogManage.table.state')" align="center">
  47 + <template slot-scope="scope">
  48 + {{ scope.row.state === '1001' ? $t('reserveCatalogManage.table.state1') :
  49 + $t('reserveCatalogManage.table.state2') }}
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column prop="createTime" :label="$t('reserveCatalogManage.table.createTime')" align="center" />
  53 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  54 + <template slot-scope="scope">
  55 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  56 + {{ $t('common.edit') }}
  57 + </el-button>
  58 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  59 + {{ $t('common.delete') }}
  60 + </el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 +
  65 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  66 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  67 + @current-change="handleCurrentChange" />
  68 + </el-card>
  69 +
  70 + <!-- 子组件 -->
  71 + <add-reserve-catalog ref="addDialog" @success="handleSuccess" />
  72 + <edit-reserve-catalog ref="editDialog" @success="handleSuccess" />
  73 + <delete-reserve-catalog ref="deleteDialog" @success="handleSuccess" />
  74 + </div>
  75 +</template>
  76 +
  77 +<script>
  78 +import { listReserveCatalog } from '@/api/scm/reserveCatalogManageApi'
  79 +import { getCommunityId } from '@/api/community/communityApi'
  80 +import AddReserveCatalog from '@/components/scm/addReserveCatalog'
  81 +import EditReserveCatalog from '@/components/scm/editReserveCatalog'
  82 +import DeleteReserveCatalog from '@/components/scm/deleteReserveCatalog'
  83 +
  84 +export default {
  85 + name: 'ReserveCatalogManageList',
  86 + components: {
  87 + AddReserveCatalog,
  88 + EditReserveCatalog,
  89 + DeleteReserveCatalog
  90 + },
  91 + data() {
  92 + return {
  93 + loading: false,
  94 + searchForm: {
  95 + name: '',
  96 + type: '',
  97 + communityId: ''
  98 + },
  99 + tableData: [],
  100 + page: {
  101 + current: 1,
  102 + size: 10,
  103 + total: 0
  104 + }
  105 + }
  106 + },
  107 + created() {
  108 + this.searchForm.communityId = getCommunityId()
  109 + this.getList()
  110 + },
  111 + methods: {
  112 + async getList() {
  113 + try {
  114 + this.loading = true
  115 + const params = {
  116 + page: this.page.current,
  117 + row: this.page.size,
  118 + ...this.searchForm
  119 + }
  120 + const { data, total } = await listReserveCatalog(params)
  121 + this.tableData = data
  122 + this.page.total = total
  123 + } catch (error) {
  124 + this.$message.error(this.$t('reserveCatalogManage.fetchError'))
  125 + } finally {
  126 + this.loading = false
  127 + }
  128 + },
  129 + handleSearch() {
  130 + this.page.current = 1
  131 + this.getList()
  132 + },
  133 + handleAdd() {
  134 + this.$refs.addDialog.open()
  135 + },
  136 + handleEdit(row) {
  137 + this.$refs.editDialog.open(row)
  138 + },
  139 + handleDelete(row) {
  140 + this.$refs.deleteDialog.open(row)
  141 + },
  142 + handleSuccess() {
  143 + this.getList()
  144 + },
  145 + handleSizeChange(val) {
  146 + this.page.size = val
  147 + this.getList()
  148 + },
  149 + handleCurrentChange(val) {
  150 + this.page.current = val
  151 + this.getList()
  152 + }
  153 + }
  154 +}
  155 +</script>
  156 +
  157 +<style lang="scss" scoped>
  158 +.reserve-catalog-manage-container {
  159 + padding: 20px;
  160 +
  161 + .search-wrapper {
  162 + margin-bottom: 20px;
  163 + }
  164 +
  165 + .list-wrapper {
  166 + margin-bottom: 20px;
  167 + }
  168 +
  169 + .el-pagination {
  170 + margin-top: 20px;
  171 + text-align: right;
  172 + }
  173 +}
  174 +</style>
0 \ No newline at end of file 175 \ No newline at end of file