Commit 6c157c6e0629e70ea0698a19bb629832a335cd09

Authored by wuxw
1 parent 9d4e862a

优化完成员工认证 员工小区功能

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 &#39;./devI18n&#39;
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 &#39;./devRouter&#39;
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
... ...