Commit 1c380d6da4f3610bf32e587bacc6c447757f6b0a

Authored by wuxw
1 parent 88f005b5

开发完成账户和账户详情

src/api/account/accountDetailManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询账户明细列表
  5 +export function queryOwnerAccountDetail(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const communityId = getCommunityId()
  8 + request({
  9 + url: '/account/queryOwnerAccountDetail',
  10 + method: 'get',
  11 + params: {
  12 + ...params,
  13 + communityId
  14 + }
  15 + }).then(response => {
  16 + const res = response.data
  17 + if (res.code === 0) {
  18 + resolve(res)
  19 + } else {
  20 + reject(new Error(res.msg || '查询账户明细失败'))
  21 + }
  22 + }).catch(error => {
  23 + reject(error)
  24 + })
  25 + })
  26 +}
  27 +
  28 +// 撤销账户明细
  29 +export function cancelAccountDetail(data) {
  30 + return new Promise((resolve, reject) => {
  31 + const communityId = getCommunityId()
  32 + request({
  33 + url: '/account.cancelAccountDetail',
  34 + method: 'post',
  35 + data: {
  36 + ...data,
  37 + communityId
  38 + }
  39 + }).then(response => {
  40 + const res = response.data
  41 + if (res.code === 0) {
  42 + resolve(res)
  43 + } else {
  44 + reject(new Error(res.msg || '撤销操作失败'))
  45 + }
  46 + }).catch(error => {
  47 + reject(error)
  48 + })
  49 + })
  50 +}
0 51 \ No newline at end of file
... ...
src/api/account/accountManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询账户列表
  5 +export function queryCommunityOwnerAccount(params) {
  6 + return new Promise((resolve, reject) => {
  7 + params.communityId = getCommunityId()
  8 + request({
  9 + url: '/account.queryCommunityOwnerAccount',
  10 + method: 'get',
  11 + params
  12 + }).then(response => {
  13 + const res = response.data
  14 + if (res.code === 0) {
  15 + resolve(res)
  16 + } else {
  17 + reject(new Error(res.msg || '查询账户列表失败'))
  18 + }
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
  24 +
  25 +// 预存账户
  26 +export function ownerPrestoreAccount(data) {
  27 + return new Promise((resolve, reject) => {
  28 + data.communityId = getCommunityId()
  29 + request({
  30 + url: '/account.ownerPrestoreAccount',
  31 + method: 'post',
  32 + data
  33 + }).then(response => {
  34 + const res = response.data
  35 + if (res.code === 0) {
  36 + resolve(res)
  37 + } else {
  38 + reject(new Error(res.msg || '预存账户失败'))
  39 + }
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
  45 +
  46 +// 删除账户
  47 +export function deleteAccount(data) {
  48 + return new Promise((resolve, reject) => {
  49 + request({
  50 + url: '/account.deleteAccount',
  51 + method: 'post',
  52 + data
  53 + }).then(response => {
  54 + const res = response.data
  55 + if (res.code === 0) {
  56 + resolve(res)
  57 + } else {
  58 + reject(new Error(res.msg || '删除账户失败'))
  59 + }
  60 + }).catch(error => {
  61 + reject(error)
  62 + })
  63 + })
  64 +}
  65 +
  66 +// 查询业主列表
  67 +export function queryOwners(params) {
  68 + return new Promise((resolve, reject) => {
  69 + params.communityId = getCommunityId()
  70 + params.ownerTypeCd = '1001'
  71 + request({
  72 + url: '/owner.queryOwners',
  73 + method: 'get',
  74 + params
  75 + }).then(response => {
  76 + const res = response.data
  77 + if (res.code == 0) {
  78 + resolve(res)
  79 + } else {
  80 + reject(new Error(res.msg || '查询业主列表失败'))
  81 + }
  82 + }).catch(error => {
  83 + reject(error)
  84 + })
  85 + })
  86 +}
  87 +
  88 +// 查询业主房间
  89 +export function queryRoomsByOwner(params) {
  90 + return new Promise((resolve, reject) => {
  91 + params.communityId = getCommunityId()
  92 + request({
  93 + url: '/room.queryRoomsByOwner',
  94 + method: 'get',
  95 + params
  96 + }).then(response => {
  97 + const res = response.data
  98 + resolve(res)
  99 + }).catch(error => {
  100 + reject(error)
  101 + })
  102 + })
  103 +}
  104 +
  105 +// 获取字典数据
  106 +export function getDict(dictType, dictName) {
  107 + return new Promise((resolve, reject) => {
  108 + request({
  109 + url: '/dict.getDict',
  110 + method: 'get',
  111 + params: { dictType, dictName }
  112 + }).then(response => {
  113 + const res = response.data
  114 + if (res.code === 0) {
  115 + resolve(res.data)
  116 + } else {
  117 + reject(new Error(res.msg || '获取字典数据失败'))
  118 + }
  119 + }).catch(error => {
  120 + reject(error)
  121 + })
  122 + })
  123 +}
0 124 \ No newline at end of file
... ...
src/api/owner/auditAuthOwnerApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取业主认证列表
  5 +export function listAuditAppUserBindingOwners(params) {
  6 + return new Promise((resolve, reject) => {
  7 + // 确保有社区ID
  8 + if (!params.communityId) {
  9 + params.communityId = getCommunityId()
  10 + }
  11 +
  12 + request({
  13 + url: '/owner.listAuditAppUserBindingOwners',
  14 + method: 'get',
  15 + params
  16 + }).then(response => {
  17 + const res = response.data
  18 + if (res.code === 0) {
  19 + resolve(res)
  20 + } else {
  21 + reject(new Error(res.msg || '获取业主认证列表失败'))
  22 + }
  23 + }).catch(error => {
  24 + reject(error)
  25 + })
  26 + })
  27 +}
  28 +
  29 +// 删除业主绑定
  30 +export function deleteAppUserBindingOwner(data) {
  31 + return new Promise((resolve, reject) => {
  32 + request({
  33 + url: '/owner.deleteAppUserBindingOwner',
  34 + method: 'post',
  35 + data: {
  36 + ...data,
  37 + communityId: getCommunityId()
  38 + }
  39 + }).then(response => {
  40 + const res = response.data
  41 + if (res.code === 0) {
  42 + resolve(res)
  43 + } else {
  44 + reject(new Error(res.msg || '删除业主绑定失败'))
  45 + }
  46 + }).catch(error => {
  47 + reject(error)
  48 + })
  49 + })
  50 +}
  51 +
  52 +// 重置密码
  53 +export function resetStaffPwd(data) {
  54 + return new Promise((resolve, reject) => {
  55 + request({
  56 + url: '/user.resetStaffPwd',
  57 + method: 'post',
  58 + data: {
  59 + ...data,
  60 + communityId: getCommunityId()
  61 + }
  62 + }).then(response => {
  63 + const res = response.data
  64 + if (res.code === 0) {
  65 + resolve(res)
  66 + } else {
  67 + reject(new Error(res.msg || '重置密码失败'))
  68 + }
  69 + }).catch(error => {
  70 + reject(error)
  71 + })
  72 + })
  73 +}
0 74 \ No newline at end of file
... ...
src/api/room/roomApi.js
... ... @@ -48,4 +48,43 @@ export function getUnits(params) {
48 48 reject(error)
49 49 })
50 50 })
  51 +}
  52 +
  53 +export function queryRoomsWithSell(params) {
  54 + return new Promise((resolve, reject) => {
  55 + request({
  56 + url: '/room.queryRoomsWithSell',
  57 + method: 'get',
  58 + params
  59 + }).then(response => {
  60 + const res = response.data
  61 + if (res.code === 0) {
  62 + resolve(res)
  63 + } else {
  64 + reject(new Error(res.msg || '查询已售房屋信息失败'))
  65 + }
  66 + }).catch(error => {
  67 + reject(error)
  68 + })
  69 + })
  70 +}
  71 +
  72 +// 查询未售房屋信息
  73 +export function queryRoomsWithOutSell(params) {
  74 + return new Promise((resolve, reject) => {
  75 + request({
  76 + url: '/room.queryRoomsWithOutSell',
  77 + method: 'get',
  78 + params
  79 + }).then(response => {
  80 + const res = response.data
  81 + if (res.code === 0) {
  82 + resolve(res)
  83 + } else {
  84 + reject(new Error(res.msg || '查询未售房屋信息失败'))
  85 + }
  86 + }).catch(error => {
  87 + reject(error)
  88 + })
  89 + })
51 90 }
52 91 \ No newline at end of file
... ...
src/components/account/cancelAccountDetail.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('cancelAccountDetail.title')"
  4 + :visible.sync="visible"
  5 + width="600px"
  6 + :close-on-click-modal="false">
  7 + <el-form
  8 + ref="form"
  9 + :model="formData"
  10 + label-position="left"
  11 + label-width="120px">
  12 + <el-form-item
  13 + :label="$t('cancelAccountDetail.accountName')"
  14 + prop="acctName">
  15 + <el-input
  16 + v-model="formData.acctName"
  17 + disabled
  18 + :placeholder="$t('cancelAccountDetail.required')"/>
  19 + </el-form-item>
  20 +
  21 + <el-form-item
  22 + :label="$t('cancelAccountDetail.cancelAmount')"
  23 + prop="amount">
  24 + <el-input
  25 + v-model="formData.amount"
  26 + disabled
  27 + :placeholder="$t('cancelAccountDetail.required')"/>
  28 + </el-form-item>
  29 +
  30 + <el-form-item
  31 + :label="$t('cancelAccountDetail.cancelReason')"
  32 + prop="remark"
  33 + :rules="[{ required: true, message: $t('cancelAccountDetail.required') }]">
  34 + <el-input
  35 + type="textarea"
  36 + v-model="formData.remark"
  37 + :rows="4"
  38 + :placeholder="$t('cancelAccountDetail.required')"/>
  39 + </el-form-item>
  40 + </el-form>
  41 +
  42 + <div slot="footer" class="dialog-footer">
  43 + <el-button @click="visible = false">
  44 + {{ $t('cancelAccountDetail.cancel') }}
  45 + </el-button>
  46 + <el-button
  47 + type="primary"
  48 + @click="handleSubmit"
  49 + :loading="submitting">
  50 + {{ $t('cancelAccountDetail.submit') }}
  51 + </el-button>
  52 + </div>
  53 + </el-dialog>
  54 +</template>
  55 +
  56 +<script>
  57 +import { cancelAccountDetail } from '@/api/account/accountDetailManageApi'
  58 +
  59 +export default {
  60 + name: 'CancelAccountDetail',
  61 + data() {
  62 + return {
  63 + visible: false,
  64 + submitting: false,
  65 + formData: {
  66 + detailId: '',
  67 + acctName: '',
  68 + amount: '',
  69 + remark: ''
  70 + }
  71 + }
  72 + },
  73 + methods: {
  74 + open(row) {
  75 + this.formData = {
  76 + detailId: row.detailId,
  77 + acctName: row.acctName,
  78 + amount: row.amount,
  79 + remark: ''
  80 + }
  81 + this.visible = true
  82 + this.$nextTick(() => {
  83 + if (this.$refs.form) {
  84 + this.$refs.form.clearValidate()
  85 + }
  86 + })
  87 + },
  88 + async handleSubmit() {
  89 + try {
  90 + const valid = await this.$refs.form.validate()
  91 + if (!valid) return
  92 +
  93 + this.submitting = true
  94 + await cancelAccountDetail({
  95 + detailId: this.formData.detailId,
  96 + remark: this.formData.remark
  97 + })
  98 +
  99 + this.$message.success(this.$t('common.operationSuccess'))
  100 + this.$emit('success')
  101 + this.visible = false
  102 + } catch (error) {
  103 + this.$message.error(error.message || this.$t('common.operationFailed'))
  104 + } finally {
  105 + this.submitting = false
  106 + }
  107 + }
  108 + }
  109 +}
  110 +</script>
0 111 \ No newline at end of file
... ...
src/components/account/deleteAccount.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteAccount.title')"
  4 + :visible.sync="visible"
  5 + width="500px"
  6 + @close="handleClose"
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('deleteAccount.confirmDelete') }}</p>
  10 + </div>
  11 +
  12 + <div slot="footer" class="dialog-footer">
  13 + <el-button @click="visible = false">{{ $t('deleteAccount.cancel') }}</el-button>
  14 + <el-button type="danger" @click="handleConfirm">{{ $t('deleteAccount.confirm') }}</el-button>
  15 + </div>
  16 + </el-dialog>
  17 +</template>
  18 +
  19 +<script>
  20 +import { deleteAccount } from '@/api/account/accountManageApi'
  21 +
  22 +export default {
  23 + name: 'DeleteAccount',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + accountData: {}
  28 + }
  29 + },
  30 + methods: {
  31 + open(account) {
  32 + this.accountData = { ...account }
  33 + this.visible = true
  34 + },
  35 +
  36 + handleClose() {
  37 + this.accountData = {}
  38 + },
  39 +
  40 + async handleConfirm() {
  41 + if (!this.accountData.acctId) return
  42 +
  43 + try {
  44 + await deleteAccount({ acctId: this.accountData.acctId })
  45 + this.$message.success(this.$t('common.deleteSuccess'))
  46 + this.visible = false
  47 + this.$emit('success')
  48 + } catch (error) {
  49 + this.$message.error(error.message || this.$t('common.deleteError'))
  50 + }
  51 + }
  52 + }
  53 +}
  54 +</script>
0 55 \ No newline at end of file
... ...
src/components/account/prestoreAccount.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('prestoreAccount.title')" :visible.sync="visible" width="800px" @close="handleClose">
  3 + <el-form ref="form" :model="formData" label-width="120px">
  4 + <el-form-item :label="$t('prestoreAccount.accountType')" prop="acctType" required>
  5 + <el-select v-model="formData.acctType" class="w-full" :placeholder="$t('prestoreAccount.placeholderOwner')">
  6 + <el-option v-for="(type, index) in acctTypes" :key="index" :label="type.name" :value="type.statusCd" />
  7 + </el-select>
  8 + </el-form-item>
  9 +
  10 + <el-form-item :label="$t('prestoreAccount.ownerPhone')" prop="tel" required>
  11 + <el-input v-model="formData.tel" :placeholder="$t('prestoreAccount.placeholderPhone')" @blur="handleTelChange" />
  12 + </el-form-item>
  13 +
  14 + <el-form-item :label="$t('prestoreAccount.ownerName')" prop="ownerId" required>
  15 + <el-select v-model="formData.ownerId" class="w-full" :placeholder="$t('prestoreAccount.placeholderOwner')"
  16 + @change="loadOwnerRooms">
  17 + <el-option v-for="owner in owners" :key="owner.ownerId" :label="owner.name" :value="owner.ownerId" />
  18 + </el-select>
  19 + </el-form-item>
  20 +
  21 + <el-form-item v-if="formData.acctType === '2004' || formData.acctType === '2005'"
  22 + :label="$t('prestoreAccount.deductionRoom')" prop="roomId" required>
  23 + <el-select v-model="formData.roomId" class="w-full" :placeholder="$t('prestoreAccount.placeholderRoom')">
  24 + <el-option v-for="room in rooms" :key="room.roomId" :label="room.roomName" :value="room.roomId" />
  25 + </el-select>
  26 + </el-form-item>
  27 +
  28 + <el-form-item :label="$t('prestoreAccount.prestoreAmount')" prop="amount" required>
  29 + <el-input v-model="formData.amount" type="number" :placeholder="$t('prestoreAccount.placeholderAmount')" />
  30 + </el-form-item>
  31 +
  32 + <el-form-item :label="$t('prestoreAccount.paymentMethod')" prop="primeRate" required>
  33 + <el-select v-model="formData.primeRate" class="w-full" :placeholder="$t('prestoreAccount.placeholderPayment')">
  34 + <template v-for="(item,index) in primeRates" >
  35 + <el-option :key="index" v-if="item.statusCd !== '5' && item.statusCd !== '6'"
  36 + :label="item.name" :value="item.statusCd" />
  37 + </template>
  38 + </el-select>
  39 + </el-form-item>
  40 +
  41 + <el-form-item :label="$t('prestoreAccount.remark')" prop="remark">
  42 + <el-input v-model="formData.remark" type="textarea" :placeholder="$t('prestoreAccount.placeholderRemark')"
  43 + :rows="3" />
  44 + </el-form-item>
  45 + </el-form>
  46 +
  47 + <div slot="footer" class="dialog-footer">
  48 + <el-button @click="visible = false">{{ $t('prestoreAccount.cancel') }}</el-button>
  49 + <el-button type="primary" @click="handleSave">{{ $t('prestoreAccount.save') }}</el-button>
  50 + </div>
  51 + </el-dialog>
  52 +</template>
  53 +
  54 +<script>
  55 +import { ownerPrestoreAccount, queryOwners, queryRoomsByOwner } from '@/api/account/accountManageApi'
  56 +import {getDict} from '@/api/community/communityApi'
  57 +export default {
  58 + name: 'PrestoreAccount',
  59 + data() {
  60 + return {
  61 + visible: false,
  62 + formData: {
  63 + tel: '',
  64 + ownerId: '',
  65 + amount: '',
  66 + remark: '',
  67 + acctType: '2003',
  68 + primeRate: '',
  69 + roomId: ''
  70 + },
  71 + acctTypes: [],
  72 + primeRates: [],
  73 + owners: [],
  74 + rooms: []
  75 + }
  76 + },
  77 + methods: {
  78 + open(params = {}) {
  79 + this.visible = true
  80 + this.resetForm()
  81 +
  82 + // 加载字典数据
  83 + Promise.all([
  84 + getDict('account', 'acct_type'),
  85 + getDict('pay_fee_detail', 'prime_rate')
  86 + ]).then(([acctTypes, primeRates]) => {
  87 + this.acctTypes = acctTypes
  88 + this.primeRates = primeRates
  89 +
  90 + // 设置传入参数
  91 + if (params.tel) {
  92 + this.formData = {
  93 + ...this.formData,
  94 + tel: params.tel,
  95 + ownerId: params.ownerId,
  96 + acctType: params.acctType,
  97 + roomId: params.roomId
  98 + }
  99 + this.handleTelChange()
  100 + }
  101 + })
  102 + },
  103 +
  104 + resetForm() {
  105 + this.formData = {
  106 + tel: '',
  107 + ownerId: '',
  108 + amount: '',
  109 + remark: '',
  110 + acctType: '2003',
  111 + primeRate: '',
  112 + roomId: ''
  113 + }
  114 + this.$refs.form && this.$refs.form.resetFields()
  115 + },
  116 +
  117 + handleClose() {
  118 + this.resetForm()
  119 + },
  120 +
  121 + async handleTelChange() {
  122 + if (!this.formData.tel) return
  123 +
  124 + try {
  125 + const res = await queryOwners({
  126 + row: 50,
  127 + page: 1,
  128 + link: this.formData.tel
  129 + })
  130 +
  131 + this.owners = res.data
  132 + } catch (error) {
  133 + console.log(error)
  134 + this.$message.error(this.$t('common.fetchError'))
  135 + this.owners = []
  136 + }
  137 + },
  138 +
  139 + async loadOwnerRooms() {
  140 + if (!this.formData.ownerId) return
  141 +
  142 + try {
  143 + const res = await queryRoomsByOwner({
  144 + row: 50,
  145 + page: 1,
  146 + ownerId: this.formData.ownerId
  147 + })
  148 + this.rooms = res.rooms || []
  149 + } catch (error) {
  150 + this.$message.error(this.$t('common.fetchError'))
  151 + this.rooms = []
  152 + }
  153 + },
  154 +
  155 + validateForm() {
  156 + const requiredFields = [
  157 + 'ownerId', 'amount', 'acctType', 'primeRate'
  158 + ]
  159 +
  160 + if (this.formData.acctType === '2004' || this.formData.acctType === '2005') {
  161 + requiredFields.push('roomId')
  162 + }
  163 +
  164 + for (const field of requiredFields) {
  165 + if (!this.formData[field]) {
  166 + this.$message.warning(this.$t('prestoreAccount.placeholder' + field.charAt(0).toUpperCase() + field.slice(1)))
  167 + return false
  168 + }
  169 + }
  170 +
  171 + if (!this.formData.amount) {
  172 + this.$message.warning(this.$t('prestoreAccount.placeholderAmount'))
  173 + return false
  174 + }
  175 +
  176 + return true
  177 + },
  178 +
  179 + async handleSave() {
  180 + if (!this.validateForm()) return
  181 +
  182 + try {
  183 + await ownerPrestoreAccount(this.formData)
  184 + this.$message.success(this.$t('common.saveSuccess'))
  185 + this.visible = false
  186 + this.$emit('success')
  187 + } catch (error) {
  188 + this.$message.error(error.message || this.$t('common.saveError'))
  189 + }
  190 + }
  191 + }
  192 +}
  193 +</script>
  194 +
  195 +<style scoped>
  196 +.w-full {
  197 + width: 100%;
  198 +}
  199 +</style>
0 200 \ No newline at end of file
... ...
src/components/owner/Audit.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('audit.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="closeDialog"
  7 + >
  8 + <el-form :model="auditInfo" label-width="120px">
  9 + <el-form-item :label="$t('audit.state')" required>
  10 + <el-select
  11 + v-model="auditInfo.state"
  12 + :placeholder="$t('audit.selectPlaceholder')"
  13 + style="width: 100%"
  14 + >
  15 + <el-option
  16 + :label="$t('audit.agree')"
  17 + value="1100"
  18 + />
  19 + <el-option
  20 + :label="$t('audit.reject')"
  21 + value="1200"
  22 + />
  23 + </el-select>
  24 + </el-form-item>
  25 + <el-form-item :label="$t('audit.reason')" required>
  26 + <el-input
  27 + type="textarea"
  28 + :rows="4"
  29 + :placeholder="$t('audit.reasonPlaceholder')"
  30 + v-model="auditInfo.remark"
  31 + />
  32 + </el-form-item>
  33 + </el-form>
  34 +
  35 + <span slot="footer" class="dialog-footer">
  36 + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button>
  37 + <el-button type="primary" @click="submitAudit">{{ $t('common.submit') }}</el-button>
  38 + </span>
  39 + </el-dialog>
  40 +</template>
  41 +
  42 +<script>
  43 +export default {
  44 + name: 'AuditDialog',
  45 + data() {
  46 + return {
  47 + visible: false,
  48 + auditInfo: {
  49 + state: '',
  50 + remark: ''
  51 + }
  52 + }
  53 + },
  54 + watch: {
  55 + 'auditInfo.state'(val) {
  56 + if (val === '1100') {
  57 + this.auditInfo.remark = this.$t('audit.agree')
  58 + } else if (val === '1200') {
  59 + this.auditInfo.remark = ''
  60 + }
  61 + }
  62 + },
  63 + methods: {
  64 + open() {
  65 + this.visible = true
  66 + },
  67 + closeDialog() {
  68 + this.visible = false
  69 + this.resetForm()
  70 + },
  71 + resetForm() {
  72 + this.auditInfo = {
  73 + state: '',
  74 + remark: ''
  75 + }
  76 + },
  77 + submitAudit() {
  78 + if (!this.validateForm()) {
  79 + return
  80 + }
  81 +
  82 + const auditData = { ...this.auditInfo }
  83 + if (auditData.state === '1200') {
  84 + auditData.remark = `${this.$t('audit.reject')}: ${auditData.remark}`
  85 + }
  86 +
  87 + this.$emit('submit', auditData)
  88 + this.closeDialog()
  89 + },
  90 + validateForm() {
  91 + if (!this.auditInfo.state) {
  92 + this.$message.error(this.$t('audit.stateRequired'))
  93 + return false
  94 + }
  95 + if (!this.auditInfo.remark) {
  96 + this.$message.error(this.$t('audit.reasonRequired'))
  97 + return false
  98 + }
  99 + if (this.auditInfo.remark.length > 200) {
  100 + this.$message.error(this.$t('audit.reasonMaxLength'))
  101 + return false
  102 + }
  103 + return true
  104 + }
  105 + }
  106 +}
  107 +</script>
  108 +
  109 +<style scoped>
  110 +.el-select {
  111 + width: 100%;
  112 +}
  113 +</style>
0 114 \ No newline at end of file
... ...
src/components/owner/DeleteAppUserBindingOwner.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('common.delete')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="closeDialog"
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('common.deleteConfirm') }}</p>
  10 + </div>
  11 +
  12 + <span slot="footer" class="dialog-footer">
  13 + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button>
  14 + <el-button type="primary" @click="confirmDelete">{{ $t('common.confirm') }}</el-button>
  15 + </span>
  16 + </el-dialog>
  17 +</template>
  18 +
  19 +<script>
  20 +import { deleteAppUserBindingOwner } from '@/api/owner/auditAuthOwnerApi'
  21 +
  22 +export default {
  23 + name: 'DeleteBindingOwnerDialog',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + currentData: null
  28 + }
  29 + },
  30 + methods: {
  31 + open(data) {
  32 + this.currentData = data
  33 + this.visible = true
  34 + },
  35 + closeDialog() {
  36 + this.visible = false
  37 + this.currentData = null
  38 + },
  39 + async confirmDelete() {
  40 + try {
  41 + if (!this.currentData) return
  42 +
  43 + const params = {
  44 + appUserId: this.currentData.appUserId,
  45 + roomId: this.currentData.roomId
  46 + }
  47 +
  48 + await deleteAppUserBindingOwner(params)
  49 + this.$message.success(this.$t('deleteBinding.successMsg'))
  50 + this.$emit('delete-success')
  51 + this.closeDialog()
  52 + } catch (error) {
  53 + console.error('删除失败:', error)
  54 + this.$message.error(this.$t('deleteBinding.errorMsg'))
  55 + }
  56 + }
  57 + }
  58 +}
  59 +</script>
0 60 \ No newline at end of file
... ...
src/components/owner/ResetStaffPwd.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('staff.confirmOperation')" :visible.sync="visible" width="30%" @close="closeDialog">
  3 + <div class="text-center">
  4 + <p>{{ $t('staff.confirmResetPassword') }}</p>
  5 + </div>
  6 +
  7 + <span slot="footer" class="dialog-footer">
  8 + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button>
  9 + <el-button type="primary" @click="confirmReset">{{ $t('common.confirm') }}</el-button>
  10 + </span>
  11 + </el-dialog>
  12 +</template>
  13 +
  14 +<script>
  15 +import { resetStaffPwd } from '@/api/owner/auditAuthOwnerApi'
  16 +
  17 +export default {
  18 + name: 'ResetPwdDialog',
  19 + data() {
  20 + return {
  21 + visible: false,
  22 + currentStaff: null
  23 + }
  24 + },
  25 + methods: {
  26 + open(staff) {
  27 + this.currentStaff = staff
  28 + this.visible = true
  29 + },
  30 + closeDialog() {
  31 + this.visible = false
  32 + this.currentStaff = null
  33 + },
  34 + async confirmReset() {
  35 + try {
  36 + if (!this.currentStaff) return
  37 +
  38 + const params = {
  39 + userId: this.currentStaff.userId
  40 + }
  41 +
  42 + const res = await resetStaffPwd(params)
  43 + this.$message.success(
  44 + this.$t('resetPwd.successMsg', { pwd: res.pwd }),
  45 + 10000
  46 + )
  47 + this.closeDialog()
  48 + } catch (error) {
  49 + console.error('重置密码失败:', error)
  50 + this.$message.error(this.$t('resetPwd.errorMsg'))
  51 + }
  52 + }
  53 + }
  54 +}
  55 +</script>
0 56 \ No newline at end of file
... ...
src/components/staff/resetStaffPwd.vue
1 1 <!-- components/staff/resetStaffPwd.vue -->
2 2 <template>
3   - <el-dialog
4   - :title="$t('staff.confirmOperation')"
5   - :visible.sync="visible"
6   - width="30%"
7   - @close="handleClose"
8   - >
  3 + <el-dialog :title="$t('staff.confirmOperation')" :visible.sync="visible" width="30%" @close="handleClose">
9 4 <div class="text-center">
10 5 <p>{{ $t('staff.confirmResetPassword') }}?</p>
11 6 </div>
... ... @@ -37,9 +32,9 @@ export default {
37 32 }
38 33 },
39 34 methods: {
40   - open(row){
41   - this.visible = true
42   - this.staffInfo = {...row}
  35 + open(row) {
  36 + this.visible = true
  37 + this.staffInfo = { ...row }
43 38 },
44 39 handleClose() {
45 40 this.visible = false
... ... @@ -52,7 +47,7 @@ export default {
52 47 communityId: '-1',
53 48 staffId: this.staffInfo.userId
54 49 }
55   -
  50 +
56 51 const res = await resetStaffPwd(data)
57 52 this.$message.success(
58 53 this.$t('staff.resetPasswordSuccess', { pwd: res.pwd }),
... ...
src/i18n/index.js
... ... @@ -128,6 +128,9 @@ import { messages as roomBindOwnerMessages } from &#39;../views/owner/roomBindOwnerL
128 128 import { messages as deleteOwnerRoomMessages } from '../views/owner/deleteOwnerRoomLang'
129 129 import { messages as shopsMessages } from '../views/room/shopsLang'
130 130 import { messages as listOwnerMessages } from '../views/owner/listOwnerLang'
  131 +import { messages as auditAuthOwnerMessages } from '../views/owner/auditAuthOwnerLang'
  132 +import { messages as accountManageMessages } from '../views/account/accountManageLang'
  133 +import { messages as accountDetailManageMessages } from '../views/account/accountDetailManageLang'
131 134  
132 135 Vue.use(VueI18n)
133 136  
... ... @@ -260,6 +263,9 @@ const messages = {
260 263 ...deleteOwnerRoomMessages.en,
261 264 ...shopsMessages.en,
262 265 ...listOwnerMessages.en,
  266 + ...auditAuthOwnerMessages.en,
  267 + ...accountManageMessages.en,
  268 + ...accountDetailManageMessages.en,
263 269 },
264 270 zh: {
265 271 ...loginMessages.zh,
... ... @@ -388,6 +394,9 @@ const messages = {
388 394 ...deleteOwnerRoomMessages.zh,
389 395 ...shopsMessages.zh,
390 396 ...listOwnerMessages.zh,
  397 + ...auditAuthOwnerMessages.zh,
  398 + ...accountManageMessages.zh,
  399 + ...accountDetailManageMessages.zh,
391 400 }
392 401 }
393 402  
... ...
src/router/index.js
... ... @@ -631,6 +631,21 @@ const routes = [
631 631 name: '/views/owner/ownerBindRoom',
632 632 component: () => import('@/views/owner/ownerBindRoom.vue')
633 633 },
  634 + {
  635 + path: '/pages/property/auditAuthOwner',
  636 + name: '/pages/property/auditAuthOwner',
  637 + component: () => import('@/views/owner/auditAuthOwnerList.vue')
  638 + },
  639 + {
  640 + path: '/pages/property/accountManage',
  641 + name: '/pages/property/accountManage',
  642 + component: () => import('@/views/account/accountManageList.vue')
  643 + },
  644 + {
  645 + path: '/views/account/accountDetailManage',
  646 + name: '/views/account/accountDetailManage',
  647 + component: () => import('@/views/account/accountDetailManageList.vue')
  648 + },
634 649  
635 650 // 其他子路由可以在这里添加
636 651 ]
... ...
src/views/account/accountDetailManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + accountDetailManage: {
  4 + title: 'Account Details',
  5 + detailId: 'Detail ID',
  6 + transactionId: 'Transaction ID',
  7 + accountName: 'Account Name',
  8 + detailType: 'Detail Type',
  9 + amountPoints: 'Amount/Points',
  10 + transactionTime: 'Transaction Time',
  11 + description: 'Description',
  12 + deposit: 'Deposit',
  13 + depositCancelled: 'Deposit Cancelled',
  14 + withdrawal: 'Withdrawal',
  15 + back: 'Back'
  16 + },
  17 + cancelAccountDetail: {
  18 + title: 'Cancel Deposit',
  19 + accountName: 'Account Name',
  20 + cancelAmount: 'Cancel Amount',
  21 + cancelReason: 'Cancel Reason',
  22 + submit: 'Submit',
  23 + cancel: 'Cancel',
  24 + required: 'Required field'
  25 + }
  26 + },
  27 + zh: {
  28 + accountDetailManage: {
  29 + title: '账户明细',
  30 + detailId: '明细编号',
  31 + transactionId: '交易编号',
  32 + accountName: '账户名称',
  33 + detailType: '明细类型',
  34 + amountPoints: '金额/积分',
  35 + transactionTime: '交易时间',
  36 + description: '说明',
  37 + deposit: '转入',
  38 + depositCancelled: '转入已撤销',
  39 + withdrawal: '转出',
  40 + back: '返回'
  41 + },
  42 + cancelAccountDetail: {
  43 + title: '预存撤销',
  44 + accountName: '账户名称',
  45 + cancelAmount: '撤销金额',
  46 + cancelReason: '撤销原因',
  47 + submit: '提交',
  48 + cancel: '取消',
  49 + required: '必填项'
  50 + }
  51 + }
  52 +}
0 53 \ No newline at end of file
... ...
src/views/account/accountDetailManageList.vue 0 → 100644
  1 +<template>
  2 + <el-card class="box-card">
  3 + <div slot="header" class="clearfix flex justify-between">
  4 + <div>{{ $t('accountDetailManage.title') }}</div>
  5 + <div class="header-tools">
  6 + <el-button type="primary" size="small" @click="goBack" icon="el-icon-close">
  7 + {{ $t('accountDetailManage.back') }}
  8 + </el-button>
  9 + </div>
  10 + </div>
  11 +
  12 + <el-table :data="accountDetails" border stripe v-loading="loading" style="width: 100%">
  13 + <el-table-column prop="detailId" :label="$t('accountDetailManage.detailId')" align="center" min-width="120" />
  14 +
  15 + <el-table-column prop="orderId" :label="$t('accountDetailManage.transactionId')" align="center" min-width="150" />
  16 +
  17 + <el-table-column prop="acctName" :label="$t('accountDetailManage.accountName')" align="center" min-width="120" />
  18 +
  19 + <el-table-column :label="$t('accountDetailManage.detailType')" align="center" min-width="150">
  20 + <template slot-scope="scope">
  21 + <span v-if="scope.row.detailType === '1001'">
  22 + {{ $t('accountDetailManage.deposit') }}
  23 + <span v-if="hasPrivilege('502023032835101743')">
  24 + (<el-link type="primary" @click="openCancelDialog(scope.row)">
  25 + {{ $t('common.cancel') }}
  26 + </el-link>)
  27 + </span>
  28 + </span>
  29 + <span v-else-if="scope.row.detailType === '3003'">
  30 + {{ $t('accountDetailManage.depositCancelled') }}
  31 + </span>
  32 + <span v-else>
  33 + {{ $t('accountDetailManage.withdrawal') }}
  34 + </span>
  35 + </template>
  36 + </el-table-column>
  37 +
  38 + <el-table-column prop="amount" :label="$t('accountDetailManage.amountPoints')" align="center" min-width="120" />
  39 +
  40 + <el-table-column prop="createTime" :label="$t('accountDetailManage.transactionTime')" align="center"
  41 + min-width="180" />
  42 +
  43 + <el-table-column :label="$t('accountDetailManage.description')" align="center" min-width="200">
  44 + <template slot-scope="scope">
  45 + {{ scope.row.remark || $t('common.none') }}
  46 + </template>
  47 + </el-table-column>
  48 + </el-table>
  49 +
  50 + <el-pagination class="pagination-wrapper" :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]"
  51 + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
  52 + @size-change="handleSizeChange" @current-change="handlePageChange" />
  53 +
  54 + <cancel-account-detail ref="cancelDialog" @success="fetchAccountDetails" />
  55 + </el-card>
  56 +</template>
  57 +
  58 +<script>
  59 +import { queryOwnerAccountDetail } from '@/api/account/accountDetailManageApi'
  60 +import CancelAccountDetail from '@/components/account/cancelAccountDetail'
  61 +
  62 +export default {
  63 + name: 'AccountDetailManageList',
  64 + components: { CancelAccountDetail },
  65 + data() {
  66 + return {
  67 + loading: false,
  68 + accountDetails: [],
  69 + pagination: {
  70 + current: 1,
  71 + size: 10,
  72 + total: 0
  73 + },
  74 + queryParams: {
  75 + acctId: '',
  76 + detailType: '',
  77 + orderId: ''
  78 + }
  79 + }
  80 + },
  81 + created() {
  82 + this.queryParams.acctId = this.$route.query.acctId
  83 + this.fetchAccountDetails()
  84 + },
  85 + methods: {
  86 + async fetchAccountDetails() {
  87 + try {
  88 + this.loading = true
  89 + const params = {
  90 + page: this.pagination.current,
  91 + row: this.pagination.size,
  92 + ...this.queryParams
  93 + }
  94 +
  95 + const res = await queryOwnerAccountDetail(params)
  96 + this.accountDetails = res.data || []
  97 + this.pagination.total = res.total || 0
  98 + } catch (error) {
  99 + this.$message.error(this.$t('common.fetchError'))
  100 + } finally {
  101 + this.loading = false
  102 + }
  103 + },
  104 + openCancelDialog(row) {
  105 + this.$refs.cancelDialog.open(row)
  106 + },
  107 + handleSizeChange(size) {
  108 + this.pagination.size = size
  109 + this.fetchAccountDetails()
  110 + },
  111 + handlePageChange(page) {
  112 + this.pagination.current = page
  113 + this.fetchAccountDetails()
  114 + },
  115 + goBack() {
  116 + this.$router.go(-1)
  117 + },
  118 + }
  119 +}
  120 +</script>
  121 +
  122 +<style scoped>
  123 +.header-tools {
  124 +}
  125 +
  126 +.pagination-wrapper {
  127 + margin-top: 20px;
  128 + text-align: right;
  129 +}
  130 +
  131 +.box-card {
  132 + margin: 20px;
  133 +}
  134 +</style>
0 135 \ No newline at end of file
... ...
src/views/account/accountManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + accountManage: {
  4 + searchTitle: "Search Conditions",
  5 + ownerAccount: "Owner Account",
  6 + accountId: "Account ID",
  7 + accountName: "Account Name",
  8 + idCard: "ID Card",
  9 + phone: "Phone",
  10 + accountType: "Account Type",
  11 + accountAmount: "Account Amount",
  12 + deductionRoom: "Deduction Room",
  13 + createTime: "Create Time",
  14 + operations: "Operations",
  15 + accountDetail: "Account Details",
  16 + delete: "Delete",
  17 + prestore: "Prestore",
  18 + query: "Query",
  19 + reset: "Reset",
  20 + placeholderName: "Please enter account name",
  21 + placeholderIdCard: "Please enter ID card number",
  22 + placeholderLink: "Please enter contact information"
  23 + },
  24 + prestoreAccount: {
  25 + title: "Prestore",
  26 + accountType: "Account Type",
  27 + ownerPhone: "Owner Phone",
  28 + ownerName: "Owner Name",
  29 + deductionRoom: "Deduction Room",
  30 + prestoreAmount: "Prestore Amount",
  31 + paymentMethod: "Payment Method",
  32 + remark: "Remark",
  33 + placeholderPhone: "Required, please enter owner phone",
  34 + placeholderOwner: "Required, please select owner",
  35 + placeholderRoom: "Required, please select room",
  36 + placeholderAmount: "Required, please enter prestore amount",
  37 + placeholderPayment: "Required, please select payment method",
  38 + placeholderRemark: "Optional, please enter remark",
  39 + save: "Save",
  40 + cancel: "Cancel"
  41 + },
  42 + deleteAccount: {
  43 + title: "Please confirm your operation!",
  44 + confirmDelete: "Confirm to delete deposit?",
  45 + cancel: "Cancel",
  46 + confirm: "Confirm Delete"
  47 + }
  48 + },
  49 + zh: {
  50 + accountManage: {
  51 + searchTitle: "查询条件",
  52 + ownerAccount: "业主账户",
  53 + accountId: "账户编号",
  54 + accountName: "账户名称",
  55 + idCard: "身份证号",
  56 + phone: "手机号",
  57 + accountType: "账户类型",
  58 + accountAmount: "账户金额",
  59 + deductionRoom: "扣款房号",
  60 + createTime: "创建时间",
  61 + operations: "操作",
  62 + accountDetail: "账户明细",
  63 + delete: "删除",
  64 + prestore: "预存",
  65 + query: "查询",
  66 + reset: "重置",
  67 + placeholderName: "请输入账户名称",
  68 + placeholderIdCard: "请输入身份证号",
  69 + placeholderLink: "请输入联系方式"
  70 + },
  71 + prestoreAccount: {
  72 + title: "预存",
  73 + accountType: "账户类型",
  74 + ownerPhone: "业主手机",
  75 + ownerName: "业主名称",
  76 + deductionRoom: "扣款房屋",
  77 + prestoreAmount: "预存金额",
  78 + paymentMethod: "支付方式",
  79 + remark: "备注",
  80 + placeholderPhone: "必填,请填写业主手机号",
  81 + placeholderOwner: "必填,请选择业主",
  82 + placeholderRoom: "必填,请选择房屋",
  83 + placeholderAmount: "必填,请填写预存金额",
  84 + placeholderPayment: "必填,请选择支付方式",
  85 + placeholderRemark: "可填,请填写备注",
  86 + save: "保存",
  87 + cancel: "取消"
  88 + },
  89 + deleteAccount: {
  90 + title: "请确认您的操作!",
  91 + confirmDelete: "确定删除保证金",
  92 + cancel: "点错了",
  93 + confirm: "确认删除"
  94 + }
  95 + }
  96 +}
0 97 \ No newline at end of file
... ...
src/views/account/accountManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="account-manage-container">
  3 + <el-row :gutter="20">
  4 + <el-col :span="3">
  5 + <el-card class="tree-card">
  6 + <ul class="account-type-list">
  7 + <li v-for="(item, index) in accountTypes" :key="index" class="account-type-item"
  8 + :class="{ 'active': conditions.acctType === item.statusCd }" @click="switchAccountType(item)">
  9 + {{ item.name }}
  10 + </li>
  11 + </ul>
  12 + </el-card>
  13 + </el-col>
  14 +
  15 + <el-col :span="21">
  16 + <el-card class="search-card">
  17 + <div slot="header" class="text-left">
  18 + <span>{{ $t('accountManage.searchTitle') }}</span>
  19 + </div>
  20 +
  21 + <el-row :gutter="20">
  22 + <el-col :span="6">
  23 + <el-input v-model="conditions.ownerName" :placeholder="$t('accountManage.placeholderName')" clearable />
  24 + </el-col>
  25 +
  26 + <el-col :span="6">
  27 + <el-input v-model="conditions.idCard" :placeholder="$t('accountManage.placeholderIdCard')" clearable />
  28 + </el-col>
  29 +
  30 + <el-col :span="6">
  31 + <el-input v-model="conditions.link" :placeholder="$t('accountManage.placeholderLink')" clearable />
  32 + </el-col>
  33 +
  34 + <el-col :span="6">
  35 + <el-button type="primary" @click="queryAccounts">
  36 + {{ $t('accountManage.query') }}
  37 + </el-button>
  38 + <el-button @click="resetConditions">
  39 + {{ $t('accountManage.reset') }}
  40 + </el-button>
  41 + </el-col>
  42 + </el-row>
  43 + </el-card>
  44 +
  45 + <el-card class="mt-20">
  46 + <div slot="header" class="flex-between">
  47 + <span>{{ $t('accountManage.ownerAccount') }}</span>
  48 + <el-button type="primary" size="small" @click="openPrestoreDialog">
  49 + {{ $t('accountManage.prestore') }}
  50 + </el-button>
  51 + </div>
  52 +
  53 + <el-table :data="accounts" border v-loading="loading">
  54 + <el-table-column prop="acctId" :label="$t('accountManage.accountId')" align="center" />
  55 +
  56 + <el-table-column prop="acctName" :label="$t('accountManage.accountName')" align="center" />
  57 +
  58 + <el-table-column prop="idCard" :label="$t('accountManage.idCard')" align="center" />
  59 +
  60 + <el-table-column prop="link" :label="$t('accountManage.phone')" align="center" />
  61 +
  62 + <el-table-column prop="acctTypeName" :label="$t('accountManage.accountType')" align="center" />
  63 +
  64 + <el-table-column prop="amount" :label="$t('accountManage.accountAmount')" align="center" />
  65 +
  66 + <el-table-column prop="roomName" :label="$t('accountManage.deductionRoom')" align="center">
  67 + <template slot-scope="scope">
  68 + {{ scope.row.roomName || $t('common.none') }}
  69 + </template>
  70 + </el-table-column>
  71 +
  72 + <el-table-column prop="createTime" :label="$t('accountManage.createTime')" align="center" />
  73 +
  74 + <el-table-column :label="$t('accountManage.operations')" align="center" width="200">
  75 + <template slot-scope="scope">
  76 + <el-button size="mini" @click="viewAccountDetail(scope.row)">
  77 + {{ $t('accountManage.accountDetail') }}
  78 + </el-button>
  79 + <el-button size="mini" type="danger" @click="openDeleteDialog(scope.row)">
  80 + {{ $t('accountManage.delete') }}
  81 + </el-button>
  82 + </template>
  83 + </el-table-column>
  84 + </el-table>
  85 +
  86 + <el-pagination class="mt-20" :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]"
  87 + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
  88 + @size-change="handleSizeChange" @current-change="handlePageChange" />
  89 + </el-card>
  90 + </el-col>
  91 + </el-row>
  92 +
  93 + <prestore-account ref="prestoreDialog" @success="fetchAccounts" />
  94 + <delete-account ref="deleteDialog" @success="fetchAccounts" />
  95 + </div>
  96 +</template>
  97 +
  98 +<script>
  99 +import { queryCommunityOwnerAccount } from '@/api/account/accountManageApi'
  100 +import PrestoreAccount from '@/components/account/prestoreAccount'
  101 +import DeleteAccount from '@/components/account/deleteAccount'
  102 +import { getDict } from '@/api/community/communityApi'
  103 +
  104 +export default {
  105 + name: 'AccountManageList',
  106 + components: {
  107 + PrestoreAccount,
  108 + DeleteAccount
  109 + },
  110 + data() {
  111 + return {
  112 + loading: false,
  113 + accounts: [],
  114 + accountTypes: [],
  115 + conditions: {
  116 + acctType: '',
  117 + ownerName: '',
  118 + idCard: '',
  119 + link: '',
  120 + page: 1,
  121 + row: 10
  122 + },
  123 + pagination: {
  124 + current: 1,
  125 + size: 10,
  126 + total: 0
  127 + }
  128 + }
  129 + },
  130 + created() {
  131 + this.loadAccountTypes()
  132 + this.fetchAccounts()
  133 + },
  134 + methods: {
  135 + async loadAccountTypes() {
  136 + try {
  137 + const data = await getDict('account', 'acct_type')
  138 + this.accountTypes = [{ name: this.$t('common.all'), statusCd: '' }, ...data]
  139 + } catch (error) {
  140 + console.error('Failed to load account types:', error)
  141 + }
  142 + },
  143 +
  144 + async fetchAccounts() {
  145 + this.loading = true
  146 + try {
  147 + const res = await queryCommunityOwnerAccount(this.conditions)
  148 + this.accounts = res.data || []
  149 + this.pagination.total = res.total || 0
  150 + this.pagination.size = this.conditions.row
  151 + } catch (error) {
  152 + this.$message.error(this.$t('common.fetchError'))
  153 + } finally {
  154 + this.loading = false
  155 + }
  156 + },
  157 +
  158 + queryAccounts() {
  159 + this.conditions.page = 1
  160 + this.fetchAccounts()
  161 + },
  162 +
  163 + resetConditions() {
  164 + this.conditions = {
  165 + ...this.conditions,
  166 + ownerName: '',
  167 + idCard: '',
  168 + link: '',
  169 + acctType: '',
  170 + page: 1
  171 + }
  172 + this.fetchAccounts()
  173 + },
  174 +
  175 + switchAccountType(item) {
  176 + this.conditions.acctType = item.statusCd
  177 + this.queryAccounts()
  178 + },
  179 +
  180 + openPrestoreDialog() {
  181 + this.$refs.prestoreDialog.open()
  182 + },
  183 +
  184 + openDeleteDialog(account) {
  185 + this.$refs.deleteDialog.open(account)
  186 + },
  187 +
  188 + viewAccountDetail(account) {
  189 + this.$router.push(`/views/account/accountDetailManage?acctId=${account.acctId}`)
  190 + },
  191 +
  192 + handleSizeChange(size) {
  193 + this.conditions.row = size
  194 + this.fetchAccounts()
  195 + },
  196 +
  197 + handlePageChange(page) {
  198 + this.conditions.page = page
  199 + this.fetchAccounts()
  200 + }
  201 + }
  202 +}
  203 +</script>
  204 +
  205 +<style scoped>
  206 +.account-manage-container {
  207 + padding: 20px;
  208 +}
  209 +
  210 +.tree-card {
  211 + height: 100%;
  212 +}
  213 +
  214 +.account-type-list {
  215 + list-style: none;
  216 + padding: 0;
  217 + margin: 0;
  218 +}
  219 +
  220 +.account-type-item {
  221 + padding: 12px 15px;
  222 + margin-bottom: 8px;
  223 + border-radius: 4px;
  224 + cursor: pointer;
  225 + text-align: center;
  226 + transition: all 0.3s;
  227 +}
  228 +
  229 +.account-type-item:hover {
  230 + background-color: #f5f7fa;
  231 +}
  232 +
  233 +.account-type-item.active {
  234 + background-color: #409eff;
  235 + color: white;
  236 + border-color: #409eff;
  237 +}
  238 +
  239 +.search-card {
  240 + margin-bottom: 20px;
  241 +}
  242 +
  243 +.flex-between {
  244 + display: flex;
  245 + justify-content: space-between;
  246 + align-items: center;
  247 +}
  248 +
  249 +.mt-20 {
  250 + margin-top: 20px;
  251 +}
  252 +</style>
0 253 \ No newline at end of file
... ...
src/views/owner/auditAuthOwnerLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + auditAuthOwner: {
  4 + searchTitle: 'Search Conditions',
  5 + authTitle: 'Owner Property Certification',
  6 + appUserNamePlaceholder: 'Please enter associated owner name',
  7 + idCardPlaceholder: 'Please enter associated owner ID card',
  8 + linkPlaceholder: 'Please enter associated owner phone',
  9 + communityName: 'Community Name',
  10 + owner: 'Owner',
  11 + phone: 'Phone',
  12 + room: 'Room',
  13 + ownerType: 'Person Type',
  14 + idCard: 'ID Card',
  15 + state: 'Status',
  16 + remark: 'Audit Remark',
  17 + createTime: 'Application Time',
  18 + appType: 'App Type',
  19 + operation: 'Operation',
  20 + audit: 'Audit',
  21 + resetPwd: 'Reset Password',
  22 + all: 'All',
  23 + pending: 'Pending',
  24 + success: 'Success',
  25 + failed: 'Failed',
  26 + fetchError: 'Failed to fetch data'
  27 + }
  28 + },
  29 + zh: {
  30 + auditAuthOwner: {
  31 + searchTitle: '查询条件',
  32 + authTitle: '业主房产认证',
  33 + appUserNamePlaceholder: '请输入关联业主名称',
  34 + idCardPlaceholder: '请输入关联业主身份证',
  35 + linkPlaceholder: '请输入关联业主手机号',
  36 + communityName: '小区名称',
  37 + owner: '业主',
  38 + phone: '手机号',
  39 + room: '房屋',
  40 + ownerType: '人员类型',
  41 + idCard: '身份证',
  42 + state: '状态',
  43 + remark: '审核说明',
  44 + createTime: '申请时间',
  45 + appType: '手机端类型',
  46 + operation: '操作',
  47 + audit: '审核',
  48 + resetPwd: '重置密码',
  49 + all: '全部',
  50 + pending: '待审核',
  51 + success: '审核成功',
  52 + failed: '审核失败',
  53 + fetchError: '获取数据失败'
  54 + }
  55 + }
  56 +}
0 57 \ No newline at end of file
... ...
src/views/owner/auditAuthOwnerList.vue 0 → 100644
  1 +<template>
  2 + <div class="animated fadeInRight ecommerce">
  3 + <el-row :gutter="20">
  4 + <el-col :span="3">
  5 + <div class="border-radius white-bg">
  6 + <div class="margin-xs-r treeview">
  7 + <ul class="list-group text-center border-radius">
  8 + <li v-for="(item, index) in auditAuthOwnerInfo.states" :key="index" @click="_swatchState(item)"
  9 + :class="{ 'vc-node-selected': auditAuthOwnerInfo.conditions.state == item.statusCd }"
  10 + class="list-group-item node-orgTree">
  11 + {{ item.name }}
  12 + </li>
  13 + </ul>
  14 + </div>
  15 + </div>
  16 + </el-col>
  17 + <el-col :span="21">
  18 + <el-card class="box-card">
  19 + <div slot="header" class="clearfix flex justify-between">
  20 + <div>{{ $t('auditAuthOwner.searchTitle') }}</div>
  21 + </div>
  22 + <div class="">
  23 + <el-row :gutter="20">
  24 + <el-col :span="6">
  25 + <el-input :placeholder="$t('auditAuthOwner.appUserNamePlaceholder')"
  26 + v-model="auditAuthOwnerInfo.conditions.appUserName" clearable />
  27 + </el-col>
  28 + <el-col :span="6">
  29 + <el-input :placeholder="$t('auditAuthOwner.idCardPlaceholder')"
  30 + v-model="auditAuthOwnerInfo.conditions.idCard" clearable />
  31 + </el-col>
  32 + <el-col :span="6">
  33 + <el-input :placeholder="$t('auditAuthOwner.linkPlaceholder')" v-model="auditAuthOwnerInfo.conditions.link"
  34 + clearable />
  35 + </el-col>
  36 + <el-col :span="6">
  37 + <el-button type="primary" size="small" @click="_queryAuditAuthOwnerMethod">
  38 + {{ $t('common.search') }}
  39 + </el-button>
  40 + <el-button type="info" size="small" @click="_resetAuditAuthOwnerMethod">
  41 + {{ $t('common.reset') }}
  42 + </el-button>
  43 + </el-col>
  44 + </el-row>
  45 + </div>
  46 + </el-card>
  47 +
  48 + <el-card class="box-card mt-20">
  49 + <div slot="header" class="clearfix flex justify-between">
  50 + <div>{{ $t('auditAuthOwner.authTitle') }}</div>
  51 + </div>
  52 + <div class="">
  53 + <el-table :data="auditAuthOwnerInfo.appUsers" border style="width: 100%" v-loading="loading">
  54 + <el-table-column prop="communityName" :label="$t('auditAuthOwner.communityName')" align="center" />
  55 + <el-table-column :label="$t('auditAuthOwner.owner')" align="center">
  56 + <template slot-scope="scope">
  57 + <div>{{ scope.row.appUserName }}</div>
  58 + <div v-if="scope.row.ownerId">({{ scope.row.ownerId }})</div>
  59 + </template>
  60 + </el-table-column>
  61 + <el-table-column prop="link" :label="$t('auditAuthOwner.phone')" align="center" />
  62 + <el-table-column prop="roomName" :label="$t('auditAuthOwner.room')" align="center">
  63 + <template slot-scope="scope">
  64 + {{ scope.row.roomName || '-' }}
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column prop="ownerTypeCdName" :label="$t('auditAuthOwner.ownerType')" align="center">
  68 + <template slot-scope="scope">
  69 + {{ scope.row.ownerTypeCdName || '-' }}
  70 + </template>
  71 + </el-table-column>
  72 + <el-table-column prop="idCard" :label="$t('auditAuthOwner.idCard')" align="center">
  73 + <template slot-scope="scope">
  74 + {{ scope.row.idCard || '-' }}
  75 + </template>
  76 + </el-table-column>
  77 + <el-table-column prop="stateName" :label="$t('auditAuthOwner.state')" align="center" />
  78 + <el-table-column prop="remark" :label="$t('auditAuthOwner.remark')" align="center">
  79 + <template slot-scope="scope">
  80 + {{ scope.row.remark || '-' }}
  81 + </template>
  82 + </el-table-column>
  83 + <el-table-column prop="createTime" :label="$t('auditAuthOwner.createTime')" align="center" />
  84 + <el-table-column prop="appTypeName" :label="$t('auditAuthOwner.appType')" align="center" />
  85 + <el-table-column :label="$t('common.operation')" align="center" width="220">
  86 + <template slot-scope="scope">
  87 + <el-button v-if="scope.row.state == '10000'" size="mini" type="primary"
  88 + @click="_openAuditAuthOwnerModel(scope.row)">
  89 + {{ $t('auditAuthOwner.audit') }}
  90 + </el-button>
  91 + <el-button size="mini" type="danger" @click="_deleteAppUserBindingOwnerModel(scope.row)">
  92 + {{ $t('common.delete') }}
  93 + </el-button>
  94 + <el-button size="mini" type="warning" @click="_resetUserPwdModel(scope.row)">
  95 + {{ $t('auditAuthOwner.resetPwd') }}
  96 + </el-button>
  97 + </template>
  98 + </el-table-column>
  99 + </el-table>
  100 +
  101 + <el-pagination class="mt-20" @size-change="handleSizeChange" @current-change="handleCurrentChange"
  102 + :current-page="auditAuthOwnerInfo.conditions.page" :page-sizes="[10, 20, 30, 50]"
  103 + :page-size="auditAuthOwnerInfo.conditions.row" layout="total, sizes, prev, pager, next, jumper"
  104 + :total="auditAuthOwnerInfo.total" />
  105 + </div>
  106 + </el-card>
  107 + </el-col>
  108 + </el-row>
  109 +
  110 + <audit-dialog ref="auditDialog" @submit="_auditSubmit" />
  111 + <delete-binding-owner-dialog ref="deleteDialog" @delete-success="_deleteSuccess" />
  112 + <reset-pwd-dialog ref="resetPwdDialog" />
  113 + </div>
  114 +</template>
  115 +
  116 +<script>
  117 +import { listAuditAppUserBindingOwners } from '@/api/owner/auditAuthOwnerApi'
  118 +import { getCommunityId } from '@/api/community/communityApi'
  119 +import AuditDialog from '@/components/owner/Audit'
  120 +import DeleteBindingOwnerDialog from '@/components/owner/DeleteAppUserBindingOwner'
  121 +import ResetPwdDialog from '@/components/owner/ResetStaffPwd'
  122 +
  123 +export default {
  124 + name: 'AuditAuthOwnerList',
  125 + components: {
  126 + AuditDialog,
  127 + DeleteBindingOwnerDialog,
  128 + ResetPwdDialog
  129 + },
  130 + data() {
  131 + return {
  132 + loading: false,
  133 + auditAuthOwnerInfo: {
  134 + appUsers: [],
  135 + total: 0,
  136 + conditions: {
  137 + page: 1,
  138 + row: 10,
  139 + appUserName: '',
  140 + idCard: '',
  141 + link: '',
  142 + state: '',
  143 + communityId: ''
  144 + },
  145 + states: [
  146 + { name: this.$t('auditAuthOwner.all'), statusCd: '' },
  147 + { name: this.$t('auditAuthOwner.pending'), statusCd: '10000' },
  148 + { name: this.$t('auditAuthOwner.success'), statusCd: '12000' },
  149 + { name: this.$t('auditAuthOwner.failed'), statusCd: '13000' }
  150 + ]
  151 + }
  152 + }
  153 + },
  154 + created() {
  155 + this.communityId = getCommunityId()
  156 + this.auditAuthOwnerInfo.conditions.communityId = this.communityId
  157 + this._listAuditAuthOwners()
  158 + },
  159 + methods: {
  160 + async _listAuditAuthOwners() {
  161 + try {
  162 + this.loading = true
  163 + const params = { ...this.auditAuthOwnerInfo.conditions }
  164 +
  165 + // 清理参数
  166 + params.appUserName = params.appUserName.trim()
  167 + params.link = params.link.trim()
  168 + params.idCard = params.idCard.trim()
  169 +
  170 + const res = await listAuditAppUserBindingOwners(params)
  171 + this.auditAuthOwnerInfo.appUsers = res.data
  172 + this.auditAuthOwnerInfo.total = res.total
  173 + } catch (error) {
  174 + console.error('获取数据失败:', error)
  175 + this.$message.error(this.$t('auditAuthOwner.fetchError'))
  176 + } finally {
  177 + this.loading = false
  178 + }
  179 + },
  180 + _openAuditAuthOwnerModel(appUser) {
  181 + this.$router.push({
  182 + path: '/owner/auditAuthOwnerUndo',
  183 + query: {
  184 + appUserId: appUser.appUserId,
  185 + roomId: appUser.roomId,
  186 + appUserName: appUser.appUserName,
  187 + link: appUser.link
  188 + }
  189 + })
  190 + },
  191 + _queryAuditAuthOwnerMethod() {
  192 + this.auditAuthOwnerInfo.conditions.page = 1
  193 + this._listAuditAuthOwners()
  194 + },
  195 + _resetAuditAuthOwnerMethod() {
  196 + this.auditAuthOwnerInfo.conditions = {
  197 + page: 1,
  198 + row: 10,
  199 + appUserName: '',
  200 + idCard: '',
  201 + link: '',
  202 + state: '',
  203 + communityId: this.communityId
  204 + }
  205 + this._listAuditAuthOwners()
  206 + },
  207 + _deleteAppUserBindingOwnerModel(row) {
  208 + this.$refs.deleteDialog.open(row)
  209 + },
  210 + _resetUserPwdModel(staff) {
  211 + this.$refs.resetPwdDialog.open(staff)
  212 + },
  213 + _swatchState(item) {
  214 + this.auditAuthOwnerInfo.conditions.state = item.statusCd
  215 + this._listAuditAuthOwners()
  216 + },
  217 + _deleteSuccess() {
  218 + this._listAuditAuthOwners()
  219 + },
  220 + handleSizeChange(val) {
  221 + this.auditAuthOwnerInfo.conditions.row = val
  222 + this._listAuditAuthOwners()
  223 + },
  224 + handleCurrentChange(val) {
  225 + this.auditAuthOwnerInfo.conditions.page = val
  226 + this._listAuditAuthOwners()
  227 + }
  228 + }
  229 +}
  230 +</script>
  231 +
  232 +<style scoped>
  233 +.animated {
  234 + padding: 20px;
  235 +}
  236 +
  237 +.border-radius {
  238 + border-radius: 4px;
  239 + overflow: hidden;
  240 +}
  241 +
  242 +.list-group {
  243 + padding: 0;
  244 + margin: 0;
  245 + list-style: none;
  246 +}
  247 +
  248 +.list-group-item {
  249 + padding: 12px 15px;
  250 + border: 1px solid #ebeef5;
  251 + border-bottom: none;
  252 + cursor: pointer;
  253 + background: #fff;
  254 +}
  255 +
  256 +.list-group-item:last-child {
  257 + border-bottom: 1px solid #ebeef5;
  258 +}
  259 +
  260 +.list-group-item:hover {
  261 + background: #ecf5ff;
  262 +}
  263 +
  264 +.vc-node-selected {
  265 + background: #409eff;
  266 + color: white;
  267 +}
  268 +
  269 +.mt-20 {
  270 + margin-top: 20px;
  271 +}
  272 +</style>
0 273 \ No newline at end of file
... ...