Commit 6c157c6e0629e70ea0698a19bb629832a335cd09
1 parent
9d4e862a
优化完成员工认证 员工小区功能
Showing
14 changed files
with
1007 additions
and
0 deletions
src/api/staff/staffAppAuthManageApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询员工应用认证信息 | |
| 5 | +export function queryStaffAppAuth(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + request({ | |
| 8 | + url: '/staff/queryStaffAppAuth', | |
| 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 generatorQrCode(params) { | |
| 25 | + return new Promise((resolve, reject) => { | |
| 26 | + request({ | |
| 27 | + url: '/staff/generatorQrCode', | |
| 28 | + method: 'get', | |
| 29 | + params: { | |
| 30 | + ...params, | |
| 31 | + communityId: getCommunityId() | |
| 32 | + } | |
| 33 | + }).then(response => { | |
| 34 | + const res = response.data | |
| 35 | + resolve(res) | |
| 36 | + }).catch(error => { | |
| 37 | + reject(error) | |
| 38 | + }) | |
| 39 | + }) | |
| 40 | +} | |
| 0 | 41 | \ No newline at end of file | ... | ... |
src/api/staff/staffCommunityApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 获取员工列表 | |
| 5 | +export function listStaffs(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + request({ | |
| 8 | + url: '/query.staff.infos', | |
| 9 | + method: 'get', | |
| 10 | + params: { | |
| 11 | + ...params, | |
| 12 | + communityId: getCommunityId() | |
| 13 | + } | |
| 14 | + }).then(response => { | |
| 15 | + resolve(response.data) | |
| 16 | + }).catch(error => { | |
| 17 | + reject(error) | |
| 18 | + }) | |
| 19 | + }) | |
| 20 | +} | |
| 21 | + | |
| 22 | +// 获取员工关联的小区列表 | |
| 23 | +export function listStaffCommunity(params) { | |
| 24 | + return new Promise((resolve, reject) => { | |
| 25 | + request({ | |
| 26 | + url: '/role.listStaffCommunity', | |
| 27 | + method: 'get', | |
| 28 | + params: { | |
| 29 | + ...params, | |
| 30 | + communityId: getCommunityId() | |
| 31 | + } | |
| 32 | + }).then(response => { | |
| 33 | + resolve(response.data) | |
| 34 | + }).catch(error => { | |
| 35 | + reject(error) | |
| 36 | + }) | |
| 37 | + }) | |
| 38 | +} | |
| 39 | + | |
| 40 | +// 获取可关联的小区列表 | |
| 41 | +export function listWaitStaffCommunity(params) { | |
| 42 | + return new Promise((resolve, reject) => { | |
| 43 | + request({ | |
| 44 | + url: '/role.listWaitStaffCommunity', | |
| 45 | + method: 'get', | |
| 46 | + params: { | |
| 47 | + ...params, | |
| 48 | + communityId: getCommunityId() | |
| 49 | + } | |
| 50 | + }).then(response => { | |
| 51 | + resolve(response.data) | |
| 52 | + }).catch(error => { | |
| 53 | + reject(error) | |
| 54 | + }) | |
| 55 | + }) | |
| 56 | +} | |
| 57 | + | |
| 58 | +// 获取组织树 | |
| 59 | +export function listOrgTree() { | |
| 60 | + return new Promise((resolve, reject) => { | |
| 61 | + request({ | |
| 62 | + url: '/org.listOrgTree', | |
| 63 | + method: 'get', | |
| 64 | + params: { | |
| 65 | + communityId: getCommunityId() | |
| 66 | + } | |
| 67 | + }).then(response => { | |
| 68 | + resolve(response.data) | |
| 69 | + }).catch(error => { | |
| 70 | + reject(error) | |
| 71 | + }) | |
| 72 | + }) | |
| 73 | +} | |
| 74 | + | |
| 75 | +// 关联小区到员工 | |
| 76 | +export function saveStaffCommunity(data) { | |
| 77 | + return new Promise((resolve, reject) => { | |
| 78 | + request({ | |
| 79 | + url: '/role.saveStaffCommunity', | |
| 80 | + method: 'post', | |
| 81 | + data: { | |
| 82 | + ...data, | |
| 83 | + communityId: getCommunityId() | |
| 84 | + } | |
| 85 | + }).then(response => { | |
| 86 | + resolve(response.data) | |
| 87 | + }).catch(error => { | |
| 88 | + reject(error) | |
| 89 | + }) | |
| 90 | + }) | |
| 91 | +} | |
| 92 | + | |
| 93 | +// 删除员工小区关联 | |
| 94 | +export function deleteStaffCommunity(data) { | |
| 95 | + return new Promise((resolve, reject) => { | |
| 96 | + request({ | |
| 97 | + url: '/role.deleteStaffCommunity', | |
| 98 | + method: 'post', | |
| 99 | + data: { | |
| 100 | + ...data, | |
| 101 | + communityId: getCommunityId() | |
| 102 | + } | |
| 103 | + }).then(response => { | |
| 104 | + resolve(response.data) | |
| 105 | + }).catch(error => { | |
| 106 | + reject(error) | |
| 107 | + }) | |
| 108 | + }) | |
| 109 | +} | |
| 0 | 110 | \ No newline at end of file | ... | ... |
src/components/staff/addStaffAppAuth.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('addStaffAppAuth.title')" :visible.sync="visible" width="50%" @close="handleClose"> | |
| 3 | + <el-form label-width="120px"> | |
| 4 | + <el-form-item :label="$t('addStaffAppAuth.authType')"> | |
| 5 | + <el-select v-model="qrCodeInfo.appType" style="width:100%" @change="handleChangeAppType"> | |
| 6 | + <el-option disabled value="" :label="$t('addStaffAppAuth.requiredSelect')" /> | |
| 7 | + <el-option value="WECHAT" :label="$t('addStaffAppAuth.wechat')" /> | |
| 8 | + </el-select> | |
| 9 | + </el-form-item> | |
| 10 | + | |
| 11 | + <el-form-item :label="$t('addStaffAppAuth.qrcode')"> | |
| 12 | + <el-row :gutter="20"> | |
| 13 | + <el-col :span="10"> | |
| 14 | + <div class="qrcode-container"> | |
| 15 | + <img v-if="qrCodeInfo.showRefresh" class="refresh-icon" src="/assets/qrcode-refresh.png" | |
| 16 | + @click="handleChangeAppType" /> | |
| 17 | + <div id="qrcode" class="qrcode"></div> | |
| 18 | + </div> | |
| 19 | + </el-col> | |
| 20 | + <el-col :span="14"> | |
| 21 | + <p>{{ $t('addStaffAppAuth.scanTip') }}</p> | |
| 22 | + </el-col> | |
| 23 | + </el-row> | |
| 24 | + </el-form-item> | |
| 25 | + </el-form> | |
| 26 | + | |
| 27 | + <div slot="footer" class="dialog-footer"> | |
| 28 | + <el-button @click="visible = false"> | |
| 29 | + {{ $t('common.cancel') }} | |
| 30 | + </el-button> | |
| 31 | + <el-button type="primary" @click="handleFinish"> | |
| 32 | + {{ $t('addStaffAppAuth.finishScan') }} | |
| 33 | + </el-button> | |
| 34 | + </div> | |
| 35 | + </el-dialog> | |
| 36 | +</template> | |
| 37 | + | |
| 38 | +<script> | |
| 39 | +import { generatorQrCode } from '@/api/staff/staffAppAuthManageApi' // 假设这是员工认证专用API | |
| 40 | +import QRCode from 'qrcodejs2' | |
| 41 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 42 | + | |
| 43 | +export default { | |
| 44 | + name: 'StaffAuthQrCode', | |
| 45 | + data() { | |
| 46 | + return { | |
| 47 | + visible: false, | |
| 48 | + qrCodeInfo: { | |
| 49 | + appType: 'WECHAT', | |
| 50 | + showRefresh: false, | |
| 51 | + timer: null, | |
| 52 | + qrCodeUrl: '' // 新增字段存储二维码URL | |
| 53 | + } | |
| 54 | + } | |
| 55 | + }, | |
| 56 | + methods: { | |
| 57 | + open() { | |
| 58 | + this.visible = true | |
| 59 | + this.$nextTick(() => { | |
| 60 | + this.generateQrCode() | |
| 61 | + }) | |
| 62 | + }, | |
| 63 | + handleClose() { | |
| 64 | + clearTimeout(this.qrCodeInfo.timer) | |
| 65 | + }, | |
| 66 | + startRefreshTimer() { | |
| 67 | + this.qrCodeInfo.timer = setTimeout(() => { | |
| 68 | + this.qrCodeInfo.showRefresh = true | |
| 69 | + }, 120000) // 2分钟后显示刷新按钮 | |
| 70 | + }, | |
| 71 | + async generateQrCode() { | |
| 72 | + this.qrCodeInfo.showRefresh = false | |
| 73 | + clearTimeout(this.qrCodeInfo.timer) | |
| 74 | + | |
| 75 | + try { | |
| 76 | + const params = { | |
| 77 | + communityId: getCommunityId(), | |
| 78 | + appType: this.qrCodeInfo.appType | |
| 79 | + } | |
| 80 | + const { data } = await generatorQrCode(params) | |
| 81 | + this.qrCodeInfo.qrCodeUrl = data | |
| 82 | + this.renderQrCode(data) | |
| 83 | + this.startRefreshTimer() | |
| 84 | + } catch (error) { | |
| 85 | + this.$message.error(this.$t('staffAuth.qrcodeError')) | |
| 86 | + this.qrCodeInfo.showRefresh = true // 出错时立即显示刷新按钮 | |
| 87 | + } | |
| 88 | + }, | |
| 89 | + renderQrCode(url) { | |
| 90 | + const container = document.getElementById('qrcode') | |
| 91 | + container.innerHTML = '' | |
| 92 | + new QRCode(container, { | |
| 93 | + text: url, | |
| 94 | + width: 200, | |
| 95 | + height: 200, | |
| 96 | + colorDark: '#000000', | |
| 97 | + colorLight: '#ffffff', | |
| 98 | + correctLevel: QRCode.CorrectLevel.H | |
| 99 | + }) | |
| 100 | + }, | |
| 101 | + handleFinish() { | |
| 102 | + this.$emit('success') | |
| 103 | + this.visible = false | |
| 104 | + }, | |
| 105 | + handleChangeAppType() { | |
| 106 | + this.generateQrCode() | |
| 107 | + } | |
| 108 | + } | |
| 109 | +} | |
| 110 | +</script> | |
| 111 | + | |
| 112 | +<style lang="scss" scoped> | |
| 113 | +/* 保持现有样式不变 */ | |
| 114 | +.qrcode-container { | |
| 115 | + position: relative; | |
| 116 | + width: 200px; | |
| 117 | + height: 200px; | |
| 118 | + border: 1px solid #eee; | |
| 119 | + padding: 10px; | |
| 120 | + display: flex; | |
| 121 | + align-items: center; | |
| 122 | + justify-content: center; | |
| 123 | + | |
| 124 | + .refresh-icon { | |
| 125 | + position: absolute; | |
| 126 | + top: 10px; | |
| 127 | + left: 10px; | |
| 128 | + z-index: 10; | |
| 129 | + width: 24px; | |
| 130 | + height: 24px; | |
| 131 | + cursor: pointer; | |
| 132 | + transition: all 0.3s; | |
| 133 | + | |
| 134 | + &:hover { | |
| 135 | + transform: rotate(180deg); | |
| 136 | + } | |
| 137 | + } | |
| 138 | +} | |
| 139 | +</style> | |
| 0 | 140 | \ No newline at end of file | ... | ... |
src/components/staff/addStaffCommunity.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('staffCommunity.addCommunityTitle')" :visible.sync="visible" width="70%"> | |
| 3 | + | |
| 4 | + <el-row :gutter="20"> | |
| 5 | + <el-col :span="8"> | |
| 6 | + <el-input v-model="form.communityName" :placeholder="$t('staffCommunity.communityNamePlaceholder')" clearable | |
| 7 | + @keyup.enter.native="queryCommunitys" /> | |
| 8 | + </el-col> | |
| 9 | + <el-col :span="4"> | |
| 10 | + <el-button type="primary" @click="queryCommunitys"> | |
| 11 | + {{ $t('common.search') }} | |
| 12 | + </el-button> | |
| 13 | + </el-col> | |
| 14 | + </el-row> | |
| 15 | + | |
| 16 | + <el-table :data="communitys" border style="width: 100%" class="margin-top" | |
| 17 | + @selection-change="handleSelectionChange"> | |
| 18 | + <el-table-column type="selection" width="55" /> | |
| 19 | + <el-table-column prop="communityId" :label="$t('staffCommunity.communityId')" align="center" /> | |
| 20 | + <el-table-column prop="name" :label="$t('staffCommunity.communityName')" align="center" /> | |
| 21 | + <el-table-column prop="address" :label="$t('staffCommunity.communityAddress')" align="center" /> | |
| 22 | + </el-table> | |
| 23 | + | |
| 24 | + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size" | |
| 25 | + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" | |
| 26 | + @current-change="handleCurrentChange" /> | |
| 27 | + | |
| 28 | + <div class="text-right margin-top"> | |
| 29 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 30 | + <el-button type="primary" @click="submit">{{ $t('common.submit') }}</el-button> | |
| 31 | + </div> | |
| 32 | + | |
| 33 | + </el-dialog> | |
| 34 | +</template> | |
| 35 | + | |
| 36 | +<script> | |
| 37 | +import { listWaitStaffCommunity, saveStaffCommunity } from '@/api/staff/staffCommunityApi' | |
| 38 | + | |
| 39 | +export default { | |
| 40 | + name: 'AddStaffCommunity', | |
| 41 | + data() { | |
| 42 | + return { | |
| 43 | + visible: false, | |
| 44 | + form: { | |
| 45 | + staffId: '', | |
| 46 | + staffName: '', | |
| 47 | + communityName: '', | |
| 48 | + selectCommunitys: [] | |
| 49 | + }, | |
| 50 | + communitys: [], | |
| 51 | + selectedCommunities: [], | |
| 52 | + pagination: { | |
| 53 | + current: 1, | |
| 54 | + size: 10, | |
| 55 | + total: 0 | |
| 56 | + } | |
| 57 | + } | |
| 58 | + }, | |
| 59 | + methods: { | |
| 60 | + open(params) { | |
| 61 | + this.visible = true | |
| 62 | + this.form.staffId = params.staffId | |
| 63 | + this.form.staffName = params.staffName || '' | |
| 64 | + this.queryCommunitys() | |
| 65 | + }, | |
| 66 | + async queryCommunitys() { | |
| 67 | + try { | |
| 68 | + const params = { | |
| 69 | + page: this.pagination.current, | |
| 70 | + row: this.pagination.size, | |
| 71 | + nameLike: this.form.communityName, | |
| 72 | + staffId: this.form.staffId | |
| 73 | + } | |
| 74 | + const { data, total } = await listWaitStaffCommunity(params) | |
| 75 | + this.communitys = data | |
| 76 | + this.pagination.total = total | |
| 77 | + } catch (error) { | |
| 78 | + this.$message.error(this.$t('staffCommunity.fetchCommunityError')) | |
| 79 | + } | |
| 80 | + }, | |
| 81 | + handleSelectionChange(val) { | |
| 82 | + this.selectedCommunities = val | |
| 83 | + }, | |
| 84 | + async submit() { | |
| 85 | + if (this.selectedCommunities.length === 0) { | |
| 86 | + this.$message.warning(this.$t('staffCommunity.selectCommunityTip')) | |
| 87 | + return | |
| 88 | + } | |
| 89 | + | |
| 90 | + try { | |
| 91 | + const params = { | |
| 92 | + staffId: this.form.staffId, | |
| 93 | + staffName: this.form.staffName, | |
| 94 | + communitys: this.selectedCommunities.map(item => ({ | |
| 95 | + communityId: item.communityId, | |
| 96 | + communityName: item.name | |
| 97 | + })) | |
| 98 | + } | |
| 99 | + await saveStaffCommunity(params) | |
| 100 | + this.$message.success(this.$t('staffCommunity.addSuccess')) | |
| 101 | + this.$emit('success') | |
| 102 | + this.visible = false | |
| 103 | + } catch (error) { | |
| 104 | + this.$message.error(this.$t('staffCommunity.addError')) | |
| 105 | + } | |
| 106 | + }, | |
| 107 | + handleSizeChange(val) { | |
| 108 | + this.pagination.size = val | |
| 109 | + this.queryCommunitys() | |
| 110 | + }, | |
| 111 | + handleCurrentChange(val) { | |
| 112 | + this.pagination.current = val | |
| 113 | + this.queryCommunitys() | |
| 114 | + } | |
| 115 | + } | |
| 116 | +} | |
| 117 | +</script> | |
| 118 | + | |
| 119 | +<style scoped> | |
| 120 | +.margin-top { | |
| 121 | + margin-top: 15px; | |
| 122 | +} | |
| 123 | + | |
| 124 | +.text-right { | |
| 125 | + text-align: right; | |
| 126 | +} | |
| 127 | +</style> | |
| 0 | 128 | \ No newline at end of file | ... | ... |
src/components/staff/chooseOrgTree.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('staffCommunity.chooseOrgTitle')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="60%" | |
| 6 | + > | |
| 7 | + <el-tree | |
| 8 | + ref="orgTree" | |
| 9 | + :data="orgs" | |
| 10 | + node-key="id" | |
| 11 | + show-checkbox | |
| 12 | + :props="defaultProps" | |
| 13 | + @check-change="handleCheckChange" | |
| 14 | + /> | |
| 15 | + <div slot="footer" class="dialog-footer"> | |
| 16 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 17 | + <el-button type="primary" @click="confirmChoose">{{ $t('common.confirm') }}</el-button> | |
| 18 | + </div> | |
| 19 | + </el-dialog> | |
| 20 | +</template> | |
| 21 | + | |
| 22 | +<script> | |
| 23 | +import { listOrgTree } from '@/api/staff/staffCommunityApi' | |
| 24 | + | |
| 25 | +export default { | |
| 26 | + name: 'ChooseOrgTree', | |
| 27 | + data() { | |
| 28 | + return { | |
| 29 | + visible: false, | |
| 30 | + orgs: [], | |
| 31 | + currentOrg: {}, | |
| 32 | + defaultProps: { | |
| 33 | + children: 'children', | |
| 34 | + label: 'name' | |
| 35 | + } | |
| 36 | + } | |
| 37 | + }, | |
| 38 | + methods: { | |
| 39 | + open() { | |
| 40 | + this.visible = true | |
| 41 | + this.loadOrgs() | |
| 42 | + }, | |
| 43 | + async loadOrgs() { | |
| 44 | + try { | |
| 45 | + const { data } = await listOrgTree({ | |
| 46 | + communityId: this.$store.getters.communityId | |
| 47 | + }) | |
| 48 | + this.orgs = data | |
| 49 | + } catch (error) { | |
| 50 | + this.$message.error(this.$t('staffCommunity.fetchOrgError')) | |
| 51 | + } | |
| 52 | + }, | |
| 53 | + handleCheckChange(data, checked) { | |
| 54 | + if (checked) { | |
| 55 | + this.currentOrg = { | |
| 56 | + orgId: data.id, | |
| 57 | + allOrgName: data.name | |
| 58 | + } | |
| 59 | + } | |
| 60 | + }, | |
| 61 | + confirmChoose() { | |
| 62 | + if (!this.currentOrg.orgId) { | |
| 63 | + this.$message.warning(this.$t('staffCommunity.selectOrgTip')) | |
| 64 | + return | |
| 65 | + } | |
| 66 | + this.$emit('switchOrg', this.currentOrg) | |
| 67 | + this.visible = false | |
| 68 | + } | |
| 69 | + } | |
| 70 | +} | |
| 71 | +</script> | |
| 72 | + | |
| 73 | +<style scoped> | |
| 74 | +.dialog-footer { | |
| 75 | + text-align: right; | |
| 76 | +} | |
| 77 | +</style> | |
| 0 | 78 | \ No newline at end of file | ... | ... |
src/components/staff/deleteStaffCommunity.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('staffCommunity.deleteConfirmTitle')" :visible.sync="visible" width="30%"> | |
| 3 | + | |
| 4 | + <div class="text-center"> | |
| 5 | + <p>{{ $t('staffCommunity.deleteConfirmText') }}</p> | |
| 6 | + </div> | |
| 7 | + <div slot="footer" class="dialog-footer"> | |
| 8 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 9 | + <el-button type="primary" @click="confirmDelete">{{ $t('common.confirm') }}</el-button> | |
| 10 | + </div> | |
| 11 | + | |
| 12 | + </el-dialog> | |
| 13 | +</template> | |
| 14 | + | |
| 15 | +<script> | |
| 16 | +import { deleteStaffCommunity } from '@/api/staff/staffCommunityApi' | |
| 17 | + | |
| 18 | +export default { | |
| 19 | + name: 'DeleteStaffCommunity', | |
| 20 | + data() { | |
| 21 | + return { | |
| 22 | + visible: false, | |
| 23 | + currentData: {} | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + methods: { | |
| 27 | + open(data) { | |
| 28 | + this.visible = true | |
| 29 | + this.currentData = { ...data } | |
| 30 | + }, | |
| 31 | + async confirmDelete() { | |
| 32 | + try { | |
| 33 | + await deleteStaffCommunity(this.currentData) | |
| 34 | + this.$message.success(this.$t('staffCommunity.deleteSuccess')) | |
| 35 | + this.$emit('success') | |
| 36 | + this.visible = false | |
| 37 | + } catch (error) { | |
| 38 | + this.$message.error(this.$t('staffCommunity.deleteError')) | |
| 39 | + } | |
| 40 | + } | |
| 41 | + } | |
| 42 | +} | |
| 43 | +</script> | |
| 44 | + | |
| 45 | +<style scoped> | |
| 46 | +.text-center { | |
| 47 | + text-align: center; | |
| 48 | + margin: 20px 0; | |
| 49 | + font-size: 16px; | |
| 50 | +} | |
| 51 | + | |
| 52 | +.dialog-footer { | |
| 53 | + text-align: right; | |
| 54 | + margin-top: 20px; | |
| 55 | +} | |
| 56 | +</style> | |
| 0 | 57 | \ No newline at end of file | ... | ... |
src/i18n/index.js
| ... | ... | @@ -142,6 +142,7 @@ import { messages as devI18n } from './devI18n' |
| 142 | 142 | import { messages as resourceI18n } from './resourceI18n' |
| 143 | 143 | import { messages as carI18n } from './carI18n' |
| 144 | 144 | import { messages as scmI18n } from './scmI18n' |
| 145 | +import { messages as userI18n } from './userI18n' | |
| 145 | 146 | |
| 146 | 147 | Vue.use(VueI18n) |
| 147 | 148 | |
| ... | ... | @@ -282,6 +283,7 @@ const messages = { |
| 282 | 283 | ...resourceI18n.en, |
| 283 | 284 | ...carI18n.en, |
| 284 | 285 | ...scmI18n.en, |
| 286 | + ...userI18n.en, | |
| 285 | 287 | }, |
| 286 | 288 | zh: { |
| 287 | 289 | ...loginMessages.zh, |
| ... | ... | @@ -416,6 +418,7 @@ const messages = { |
| 416 | 418 | ...resourceI18n.zh, |
| 417 | 419 | ...carI18n.zh, |
| 418 | 420 | ...scmI18n.zh, |
| 421 | + ...userI18n.zh, | |
| 419 | 422 | } |
| 420 | 423 | } |
| 421 | 424 | ... | ... |
src/i18n/userI18n.js
0 → 100644
| 1 | +import { messages as staffCommunityMessages } from '../views/staff/staffCommunityLang' | |
| 2 | +import { messages as staffAppAuthManageMessages } from '../views/staff/staffAppAuthManageLang' | |
| 3 | + | |
| 4 | +export const messages = { | |
| 5 | + en: { | |
| 6 | + ...staffCommunityMessages.en, | |
| 7 | + ...staffAppAuthManageMessages.en, | |
| 8 | + }, | |
| 9 | + zh: { | |
| 10 | + ...staffCommunityMessages.zh, | |
| 11 | + ...staffAppAuthManageMessages.zh, | |
| 12 | + } | |
| 13 | +} | |
| 0 | 14 | \ No newline at end of file | ... | ... |
src/router/index.js
| ... | ... | @@ -12,6 +12,7 @@ import devRouter from './devRouter' |
| 12 | 12 | import resourceRouter from './resourceRouter' |
| 13 | 13 | import carRouter from './carRouter' |
| 14 | 14 | import scmRouter from './scmRouter' |
| 15 | +import userRouter from './userRouter' | |
| 15 | 16 | |
| 16 | 17 | Vue.use(VueRouter) |
| 17 | 18 | |
| ... | ... | @@ -632,6 +633,7 @@ const routes = [ |
| 632 | 633 | ...resourceRouter, |
| 633 | 634 | ...carRouter, |
| 634 | 635 | ...scmRouter, |
| 636 | + ...userRouter, | |
| 635 | 637 | // 其他子路由可以在这里添加 |
| 636 | 638 | ] |
| 637 | 639 | }, | ... | ... |
src/router/userRouter.js
0 → 100644
| 1 | +export default [ | |
| 2 | + { | |
| 3 | + path: '/pages/staff/staffCommunity', | |
| 4 | + name: '/pages/staff/staffCommunity', | |
| 5 | + component: () => import('@/views/staff/staffCommunityList.vue') | |
| 6 | + }, | |
| 7 | + { | |
| 8 | + path:'/pages/property/staffAppAuthManage', | |
| 9 | + name:'/pages/property/staffAppAuthManage', | |
| 10 | + component: () => import('@/views/staff/staffAppAuthManageList.vue') | |
| 11 | + }, | |
| 12 | +] | |
| 0 | 13 | \ No newline at end of file | ... | ... |
src/views/staff/staffAppAuthManageLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + staffAppAuthManage: { | |
| 4 | + title: 'Authentication Information', | |
| 5 | + staffName: 'Staff Name', | |
| 6 | + authType: 'Authentication Type', | |
| 7 | + authName: 'Authentication Name', | |
| 8 | + authId: 'Authentication ID', | |
| 9 | + authStatus: 'Authentication Status', | |
| 10 | + authTime: 'Authentication Time', | |
| 11 | + auth: 'Authenticate', | |
| 12 | + fetchError: 'Failed to fetch authentication data' | |
| 13 | + }, | |
| 14 | + addStaffAppAuth: { | |
| 15 | + title: 'Start Authentication', | |
| 16 | + authType: 'Authentication Type', | |
| 17 | + qrcode: 'QR Code', | |
| 18 | + scanTip: 'Please scan the QR code with WeChat for authentication', | |
| 19 | + finishScan: 'Scan Completed', | |
| 20 | + requiredSelect: 'Required, please select authentication type', | |
| 21 | + wechat: 'WeChat', | |
| 22 | + qrcodeError: 'Failed to generate QR code' | |
| 23 | + } | |
| 24 | + }, | |
| 25 | + zh: { | |
| 26 | + staffAppAuthManage: { | |
| 27 | + title: '认证信息', | |
| 28 | + staffName: '员工名称', | |
| 29 | + authType: '认证方式', | |
| 30 | + authName: '认证名称', | |
| 31 | + authId: '认证ID', | |
| 32 | + authStatus: '认证状态', | |
| 33 | + authTime: '认证时间', | |
| 34 | + auth: '认证', | |
| 35 | + fetchError: '获取认证数据失败' | |
| 36 | + }, | |
| 37 | + addStaffAppAuth: { | |
| 38 | + title: '开始认证', | |
| 39 | + authType: '认证方式', | |
| 40 | + qrcode: '二维码', | |
| 41 | + scanTip: '请用微信扫一扫二维码认证', | |
| 42 | + finishScan: '扫码完成', | |
| 43 | + requiredSelect: '必填,请选择认证方式', | |
| 44 | + wechat: '微信', | |
| 45 | + qrcodeError: '生成二维码失败' | |
| 46 | + } | |
| 47 | + } | |
| 48 | +} | |
| 0 | 49 | \ No newline at end of file | ... | ... |
src/views/staff/staffAppAuthManageList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="staff-app-auth-manage-container"> | |
| 3 | + <el-card class="box-card"> | |
| 4 | + <div slot="header" class="clearfix"> | |
| 5 | + <span>{{ $t('staffAppAuthManage.title') }}</span> | |
| 6 | + <div class="card-header-actions"> | |
| 7 | + <el-button type="primary" size="small" @click="_refreshStaffAppAuth"> | |
| 8 | + <i class="el-icon-refresh"></i> {{ $t('common.refresh') }} | |
| 9 | + </el-button> | |
| 10 | + </div> | |
| 11 | + </div> | |
| 12 | + | |
| 13 | + <el-row :gutter="20"> | |
| 14 | + <el-col :span="24"> | |
| 15 | + <el-table :data="[staffAppAuthManageInfo]" border style="width: 100%" v-loading="loading"> | |
| 16 | + <el-table-column prop="staffName" :label="$t('staffAppAuthManage.staffName')" align="center" /> | |
| 17 | + <el-table-column prop="appType" :label="$t('staffAppAuthManage.authType')" align="center" /> | |
| 18 | + <el-table-column prop="openName" :label="$t('staffAppAuthManage.authName')" align="center" /> | |
| 19 | + <el-table-column prop="openId" :label="$t('staffAppAuthManage.authId')" align="center" /> | |
| 20 | + <el-table-column prop="stateName" :label="$t('staffAppAuthManage.authStatus')" align="center" /> | |
| 21 | + <el-table-column prop="createTime" :label="$t('staffAppAuthManage.authTime')" align="center" /> | |
| 22 | + <el-table-column :label="$t('common.operation')" align="center" width="150"> | |
| 23 | + <template > | |
| 24 | + <el-button size="mini" type="primary" @click="_openAddStaffAppAuthModal"> | |
| 25 | + {{ $t('staffAppAuthManage.auth') }} | |
| 26 | + </el-button> | |
| 27 | + </template> | |
| 28 | + </el-table-column> | |
| 29 | + </el-table> | |
| 30 | + </el-col> | |
| 31 | + </el-row> | |
| 32 | + | |
| 33 | + <add-staff-app-auth ref="addStaffAppAuth" @success="_refreshStaffAppAuth" /> | |
| 34 | + </el-card> | |
| 35 | + </div> | |
| 36 | +</template> | |
| 37 | + | |
| 38 | +<script> | |
| 39 | +import { queryStaffAppAuth } from '@/api/staff/staffAppAuthManageApi' | |
| 40 | +import AddStaffAppAuth from '@/components/staff/addStaffAppAuth' | |
| 41 | + | |
| 42 | +export default { | |
| 43 | + name: 'StaffAppAuthManageList', | |
| 44 | + components: { | |
| 45 | + AddStaffAppAuth | |
| 46 | + }, | |
| 47 | + data() { | |
| 48 | + return { | |
| 49 | + loading: false, | |
| 50 | + staffAppAuthManageInfo: { | |
| 51 | + staffName: '', | |
| 52 | + appType: '', | |
| 53 | + stateName: '', | |
| 54 | + auId: '', | |
| 55 | + openId: '', | |
| 56 | + createTime: '', | |
| 57 | + openName: '' | |
| 58 | + } | |
| 59 | + } | |
| 60 | + }, | |
| 61 | + created() { | |
| 62 | + this._listStaffAppAuths() | |
| 63 | + }, | |
| 64 | + methods: { | |
| 65 | + async _listStaffAppAuths() { | |
| 66 | + try { | |
| 67 | + this.loading = true | |
| 68 | + const params = { | |
| 69 | + page: 1, | |
| 70 | + row: 1 | |
| 71 | + } | |
| 72 | + const { data } = await queryStaffAppAuth(params) | |
| 73 | + this.staffAppAuthManageInfo = data | |
| 74 | + } catch (error) { | |
| 75 | + this.$message.error(this.$t('staffAppAuthManage.fetchError')) | |
| 76 | + } finally { | |
| 77 | + this.loading = false | |
| 78 | + } | |
| 79 | + }, | |
| 80 | + _openAddStaffAppAuthModal() { | |
| 81 | + this.$refs.addStaffAppAuth.open() | |
| 82 | + }, | |
| 83 | + _refreshStaffAppAuth() { | |
| 84 | + this._listStaffAppAuths() | |
| 85 | + } | |
| 86 | + } | |
| 87 | +} | |
| 88 | +</script> | |
| 89 | + | |
| 90 | +<style lang="scss" scoped> | |
| 91 | +.staff-app-auth-manage-container { | |
| 92 | + padding: 20px; | |
| 93 | + | |
| 94 | + .box-card { | |
| 95 | + margin-bottom: 20px; | |
| 96 | + } | |
| 97 | + | |
| 98 | + .card-header-actions { | |
| 99 | + float: right; | |
| 100 | + } | |
| 101 | + | |
| 102 | + .el-table { | |
| 103 | + margin-top: 20px; | |
| 104 | + } | |
| 105 | +} | |
| 106 | +</style> | |
| 0 | 107 | \ No newline at end of file | ... | ... |
src/views/staff/staffCommunityLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + staffCommunity: { | |
| 4 | + orgPlaceholder: 'Select organization', | |
| 5 | + staffNamePlaceholder: 'Enter staff name', | |
| 6 | + linkCommunity: 'Link Community', | |
| 7 | + staffName: 'Staff Name', | |
| 8 | + staffId: 'Staff ID', | |
| 9 | + communityId: 'Community ID', | |
| 10 | + communityName: 'Community Name', | |
| 11 | + operation: 'Operation', | |
| 12 | + chooseOrgTitle: 'Select Organization', | |
| 13 | + fetchOrgError: 'Failed to load organization data', | |
| 14 | + selectOrgTip: 'Please select an organization', | |
| 15 | + addCommunityTitle: 'Add Community', | |
| 16 | + communityNamePlaceholder: 'Enter community name', | |
| 17 | + communityAddress: 'Community Address', | |
| 18 | + fetchCommunityError: 'Failed to load community data', | |
| 19 | + selectCommunityTip: 'Please select at least one community', | |
| 20 | + addSuccess: 'Added successfully', | |
| 21 | + addError: 'Failed to add', | |
| 22 | + deleteConfirmTitle: 'Confirm Delete', | |
| 23 | + deleteConfirmText: 'Are you sure to delete this community association?', | |
| 24 | + deleteSuccess: 'Deleted successfully', | |
| 25 | + deleteError: 'Failed to delete', | |
| 26 | + fetchStaffError: 'Failed to load staff data' | |
| 27 | + } | |
| 28 | + }, | |
| 29 | + zh: { | |
| 30 | + staffCommunity: { | |
| 31 | + orgPlaceholder: '选择组织', | |
| 32 | + staffNamePlaceholder: '输入员工名称', | |
| 33 | + linkCommunity: '关联小区', | |
| 34 | + staffName: '员工名称', | |
| 35 | + staffId: '员工编号', | |
| 36 | + communityId: '小区编号', | |
| 37 | + communityName: '小区名称', | |
| 38 | + operation: '操作', | |
| 39 | + chooseOrgTitle: '选择组织', | |
| 40 | + fetchOrgError: '加载组织数据失败', | |
| 41 | + selectOrgTip: '请选择组织', | |
| 42 | + addCommunityTitle: '添加小区', | |
| 43 | + communityNamePlaceholder: '输入小区名称', | |
| 44 | + communityAddress: '小区地址', | |
| 45 | + fetchCommunityError: '加载小区数据失败', | |
| 46 | + selectCommunityTip: '请至少选择一个小', | |
| 47 | + addSuccess: '添加成功', | |
| 48 | + addError: '添加失败', | |
| 49 | + deleteConfirmTitle: '确认删除', | |
| 50 | + deleteConfirmText: '确定删除该小区关联吗?', | |
| 51 | + deleteSuccess: '删除成功', | |
| 52 | + deleteError: '删除失败', | |
| 53 | + fetchStaffError: '加载员工数据失败' | |
| 54 | + } | |
| 55 | + } | |
| 56 | +} | |
| 0 | 57 | \ No newline at end of file | ... | ... |
src/views/staff/staffCommunityList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="staff-community-container"> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="4"> | |
| 5 | + <el-card class="box-card"> | |
| 6 | + <div class="margin-bottom"> | |
| 7 | + <el-input v-model="staffCommunityInfo.orgName" readonly @focus="handleOrgChange" | |
| 8 | + :placeholder="$t('staffCommunity.orgPlaceholder')" /> | |
| 9 | + </div> | |
| 10 | + <div class="margin-bottom"> | |
| 11 | + <el-input v-model="staffCommunityInfo.staffNameLike" | |
| 12 | + :placeholder="$t('staffCommunity.staffNamePlaceholder')" @keyup.enter.native="loadStaffs" /> | |
| 13 | + </div> | |
| 14 | + <div class="text-right"> | |
| 15 | + <el-button type="primary" @click="loadStaffs"> | |
| 16 | + {{ $t('common.search') }} | |
| 17 | + </el-button> | |
| 18 | + </div> | |
| 19 | + | |
| 20 | + <div class="staff-list"> | |
| 21 | + <ul class="staff-ul"> | |
| 22 | + <li v-for="(item, index) in staffCommunityInfo.staffs" :key="index" @click="switchStaff(item)" | |
| 23 | + :class="{ 'active-staff': staffCommunityInfo.curStaffId === item.userId }"> | |
| 24 | + {{ item.name }} | |
| 25 | + </li> | |
| 26 | + </ul> | |
| 27 | + </div> | |
| 28 | + </el-card> | |
| 29 | + </el-col> | |
| 30 | + <el-col :span="20"> | |
| 31 | + <el-card class="box-card"> | |
| 32 | + <div class="text-right" v-if="staffCommunityInfo.curStaffId"> | |
| 33 | + <el-button type="primary" size="small" @click="openAddModal"> | |
| 34 | + {{ $t('staffCommunity.linkCommunity') }} | |
| 35 | + </el-button> | |
| 36 | + </div> | |
| 37 | + | |
| 38 | + <el-table :data="staffCommunityInfo.communitys" border style="width: 100%" v-loading="loading"> | |
| 39 | + <el-table-column prop="staffName" :label="$t('staffCommunity.staffName')" align="center" /> | |
| 40 | + <el-table-column prop="staffId" :label="$t('staffCommunity.staffId')" align="center" /> | |
| 41 | + <el-table-column prop="communityId" :label="$t('staffCommunity.communityId')" align="center" /> | |
| 42 | + <el-table-column prop="communityName" :label="$t('staffCommunity.communityName')" align="center" /> | |
| 43 | + <el-table-column :label="$t('common.operation')" align="center" width="150"> | |
| 44 | + <template slot-scope="scope"> | |
| 45 | + <el-button size="mini" type="danger" @click="openDeleteModal(scope.row)"> | |
| 46 | + {{ $t('common.delete') }} | |
| 47 | + </el-button> | |
| 48 | + </template> | |
| 49 | + </el-table-column> | |
| 50 | + </el-table> | |
| 51 | + | |
| 52 | + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" | |
| 53 | + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" | |
| 54 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | |
| 55 | + </el-card> | |
| 56 | + </el-col> | |
| 57 | + </el-row> | |
| 58 | + | |
| 59 | + <choose-org-tree ref="chooseOrgTree" @switchOrg="handleSwitchOrg" /> | |
| 60 | + <add-staff-community ref="addStaffCommunity" @success="handleSuccess" /> | |
| 61 | + <delete-staff-community ref="deleteStaffCommunity" @success="handleSuccess" /> | |
| 62 | + </div> | |
| 63 | +</template> | |
| 64 | + | |
| 65 | +<script> | |
| 66 | +import { listStaffs, listStaffCommunity } from '@/api/staff/staffCommunityApi' | |
| 67 | +import ChooseOrgTree from '@/components/org/ChooseOrgTree' | |
| 68 | +import AddStaffCommunity from '@/components/staff/addStaffCommunity' | |
| 69 | +import DeleteStaffCommunity from '@/components/staff/deleteStaffCommunity' | |
| 70 | + | |
| 71 | +export default { | |
| 72 | + name: 'StaffCommunityList', | |
| 73 | + components: { | |
| 74 | + ChooseOrgTree, | |
| 75 | + AddStaffCommunity, | |
| 76 | + DeleteStaffCommunity | |
| 77 | + }, | |
| 78 | + data() { | |
| 79 | + return { | |
| 80 | + loading: false, | |
| 81 | + staffCommunityInfo: { | |
| 82 | + staffs: [], | |
| 83 | + communitys: [], | |
| 84 | + orgId: '', | |
| 85 | + orgName: '', | |
| 86 | + curStaffId: '', | |
| 87 | + staffNameLike: '' | |
| 88 | + }, | |
| 89 | + pagination: { | |
| 90 | + current: 1, | |
| 91 | + size: 10, | |
| 92 | + total: 0 | |
| 93 | + } | |
| 94 | + } | |
| 95 | + }, | |
| 96 | + created() { | |
| 97 | + this.loadStaffs() | |
| 98 | + }, | |
| 99 | + methods: { | |
| 100 | + async loadStaffs() { | |
| 101 | + try { | |
| 102 | + this.loading = true | |
| 103 | + const params = { | |
| 104 | + page: 1, | |
| 105 | + row: 100, | |
| 106 | + orgId: this.staffCommunityInfo.orgId, | |
| 107 | + staffName: this.staffCommunityInfo.staffNameLike | |
| 108 | + } | |
| 109 | + const data = await listStaffs(params) | |
| 110 | + this.staffCommunityInfo.staffs = data.staffs || [] | |
| 111 | + if (this.staffCommunityInfo.staffs.length > 0) { | |
| 112 | + this.staffCommunityInfo.curStaffId = this.staffCommunityInfo.staffs[0].userId | |
| 113 | + this.loadStaffCommunitys() | |
| 114 | + } | |
| 115 | + } catch (error) { | |
| 116 | + this.$message.error(this.$t('staffCommunity.fetchStaffError')) | |
| 117 | + } finally { | |
| 118 | + this.loading = false | |
| 119 | + } | |
| 120 | + }, | |
| 121 | + async loadStaffCommunitys() { | |
| 122 | + try { | |
| 123 | + this.loading = true | |
| 124 | + const params = { | |
| 125 | + page: this.pagination.current, | |
| 126 | + row: this.pagination.size, | |
| 127 | + staffId: this.staffCommunityInfo.curStaffId | |
| 128 | + } | |
| 129 | + const { data, total } = await listStaffCommunity(params) | |
| 130 | + this.staffCommunityInfo.communitys = data | |
| 131 | + this.pagination.total = total | |
| 132 | + } catch (error) { | |
| 133 | + this.$message.error(this.$t('staffCommunity.fetchCommunityError')) | |
| 134 | + } finally { | |
| 135 | + this.loading = false | |
| 136 | + } | |
| 137 | + }, | |
| 138 | + handleOrgChange() { | |
| 139 | + this.$refs.chooseOrgTree.open() | |
| 140 | + }, | |
| 141 | + handleSwitchOrg(org) { | |
| 142 | + this.staffCommunityInfo.orgId = org.orgId | |
| 143 | + this.staffCommunityInfo.orgName = org.allOrgName | |
| 144 | + this.loadStaffs() | |
| 145 | + }, | |
| 146 | + switchStaff(staff) { | |
| 147 | + this.staffCommunityInfo.curStaffId = staff.userId | |
| 148 | + this.pagination.current = 1 | |
| 149 | + this.loadStaffCommunitys() | |
| 150 | + }, | |
| 151 | + openAddModal() { | |
| 152 | + this.$refs.addStaffCommunity.open({ | |
| 153 | + staffId: this.staffCommunityInfo.curStaffId | |
| 154 | + }) | |
| 155 | + }, | |
| 156 | + openDeleteModal(row) { | |
| 157 | + this.$refs.deleteStaffCommunity.open(row) | |
| 158 | + }, | |
| 159 | + handleSuccess() { | |
| 160 | + this.loadStaffCommunitys() | |
| 161 | + }, | |
| 162 | + handleSizeChange(val) { | |
| 163 | + this.pagination.size = val | |
| 164 | + this.loadStaffCommunitys() | |
| 165 | + }, | |
| 166 | + handleCurrentChange(val) { | |
| 167 | + this.pagination.current = val | |
| 168 | + this.loadStaffCommunitys() | |
| 169 | + } | |
| 170 | + } | |
| 171 | +} | |
| 172 | +</script> | |
| 173 | + | |
| 174 | +<style lang="scss" scoped> | |
| 175 | +.staff-community-container { | |
| 176 | + padding: 20px; | |
| 177 | + | |
| 178 | + .box-card { | |
| 179 | + margin-bottom: 20px; | |
| 180 | + } | |
| 181 | + | |
| 182 | + .margin-bottom { | |
| 183 | + margin-bottom: 15px; | |
| 184 | + } | |
| 185 | + | |
| 186 | + .staff-list { | |
| 187 | + margin-top: 15px; | |
| 188 | + max-height: 500px; | |
| 189 | + overflow-y: auto; | |
| 190 | + | |
| 191 | + .staff-ul { | |
| 192 | + list-style: none; | |
| 193 | + padding: 0; | |
| 194 | + margin: 0; | |
| 195 | + | |
| 196 | + li { | |
| 197 | + padding: 10px; | |
| 198 | + text-align: center; | |
| 199 | + cursor: pointer; | |
| 200 | + border-bottom: 1px solid #eee; | |
| 201 | + | |
| 202 | + &:hover { | |
| 203 | + background-color: #f5f7fa; | |
| 204 | + } | |
| 205 | + | |
| 206 | + &.active-staff { | |
| 207 | + background-color: #409EFF; | |
| 208 | + color: white; | |
| 209 | + } | |
| 210 | + } | |
| 211 | + } | |
| 212 | + } | |
| 213 | + | |
| 214 | + .el-pagination { | |
| 215 | + margin-top: 15px; | |
| 216 | + text-align: right; | |
| 217 | + } | |
| 218 | +} | |
| 219 | +</style> | |
| 0 | 220 | \ No newline at end of file | ... | ... |