|
|
@@ -0,0 +1,429 @@
|
|
|
+<!--
|
|
|
+ * @Author: wanglj 471442253@qq.com
|
|
|
+ * @Date: 2023-02-13 13:51:45
|
|
|
+ * @LastEditors: wanglj
|
|
|
+ * @LastEditTime: 2023-02-14 18:05:38
|
|
|
+ * @Description: file content
|
|
|
+ * @FilePath: \opms_frontend\src\views\base\regionAuth\index.vue
|
|
|
+-->
|
|
|
+<template>
|
|
|
+ <div class="region-auth-container">
|
|
|
+ <vab-query-form>
|
|
|
+ <el-form>
|
|
|
+ <vab-query-form-left-panel>
|
|
|
+ <el-form-item>
|
|
|
+ <el-input v-model="queryForm.keyWords" placeholder="姓名" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button icon="el-icon-search" type="primary" @click="handleSearch">查询</el-button>
|
|
|
+ <el-button icon="el-icon-refresh-right" @click="reset">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </vab-query-form-left-panel>
|
|
|
+ <vab-query-form-right-panel>
|
|
|
+ <el-button icon="el-icon-circle-check" type="primary" @click="handleAuth">授权</el-button>
|
|
|
+ <table-tool :check-list.sync="checkList" :columns="columns" />
|
|
|
+ </vab-query-form-right-panel>
|
|
|
+ </el-form>
|
|
|
+ </vab-query-form>
|
|
|
+ <el-row :gutter="10">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-table
|
|
|
+ v-loading="listLoading"
|
|
|
+ border
|
|
|
+ :data="list"
|
|
|
+ :height="$baseTableHeight(1)"
|
|
|
+ style="width: 100%"
|
|
|
+ @row-click="handleRowClick">
|
|
|
+ <el-table-column
|
|
|
+ v-for="(item, index) in finallyColumns"
|
|
|
+ :key="index"
|
|
|
+ align="center"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.prop"
|
|
|
+ show-overflow-tooltip
|
|
|
+ :sortable="item.sortable"
|
|
|
+ :width="item.width">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span>{{ row[item.prop] }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" label="选择" width="80">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <i v-if="form.userId == row.userId" class="el-icon-check"></i>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <template #empty>
|
|
|
+ <el-image class="vab-data-empty" :src="require('@/assets/empty_images/data_empty.png')" />
|
|
|
+ </template>
|
|
|
+ </el-table>
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ :current-page="queryForm.pageNum"
|
|
|
+ :layout="layout"
|
|
|
+ :page-size="queryForm.pageSize"
|
|
|
+ :total="total"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ @size-change="handleSizeChange" />
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-table v-loading="listLoading" border :data="regionList" :height="$baseTableHeight(0)" style="width: 100%">
|
|
|
+ <el-table-column align="center" label="销售区域" prop="saleRegionName" />
|
|
|
+ <el-table-column align="center" label="省" prop="provinceName" />
|
|
|
+ <el-table-column align="center" label="市" prop="cityName" />
|
|
|
+ </el-table>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-dialog title="授权区域" top="5vh" :visible.sync="visible" width="80%" @close="handleClose">
|
|
|
+ <div v-loading="dialogLoading" class="side-layout">
|
|
|
+ <div class="tree-side">
|
|
|
+ <el-tree
|
|
|
+ ref="tree"
|
|
|
+ class="filter-tree"
|
|
|
+ :data="deptOptions"
|
|
|
+ default-expand-all
|
|
|
+ :default-expanded-keys="[1]"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ highlight-current
|
|
|
+ node-key="id"
|
|
|
+ :props="defaultProps"
|
|
|
+ @node-click="handleNodeClick">
|
|
|
+ <span slot-scope="{ node }" class="custom-tree-node">
|
|
|
+ <span>{{ node.label }}</span>
|
|
|
+ <span><i class="el-icon-more"></i></span>
|
|
|
+ </span>
|
|
|
+ </el-tree>
|
|
|
+ </div>
|
|
|
+ <div class="tree-table">
|
|
|
+ <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
|
|
|
+ 全选
|
|
|
+ </el-checkbox>
|
|
|
+ <div v-for="item in options" :key="item.custProvinceId" class="province" :label="item.custProvince">
|
|
|
+ <h3>{{ item.custProvince }}</h3>
|
|
|
+ <div class="check-container">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="item.checkAll"
|
|
|
+ :indeterminate="item.isIndeterminate"
|
|
|
+ @change="(val) => handleSndCheckAllChange(val, item)">
|
|
|
+ 全选
|
|
|
+ </el-checkbox>
|
|
|
+ <el-checkbox-group v-model="form.checkList" @change="(val) => handleChange(val, item)">
|
|
|
+ <el-checkbox v-for="city in item.children" :key="city.id" :label="city.custCityId">
|
|
|
+ {{ city.custCity }}
|
|
|
+ <span v-if="city.allocator.length">({{ city.allocator.join() }})</span>
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="visible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import to from 'await-to-js'
|
|
|
+ import regionApi from '@/api/base/region'
|
|
|
+ import regAuthApi from '@/api/base/regionAuth'
|
|
|
+ import TableTool from '@/components/table/TableTool'
|
|
|
+ export default {
|
|
|
+ name: 'RegionAuth',
|
|
|
+ components: {
|
|
|
+ TableTool,
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ queryForm: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ keyWords: '',
|
|
|
+ deptId: 2,
|
|
|
+ },
|
|
|
+ layout: 'total, sizes, prev, pager, next, jumper',
|
|
|
+ listLoading: false,
|
|
|
+ total: 0,
|
|
|
+ list: [],
|
|
|
+ regionList: [],
|
|
|
+ checkList: [],
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ label: '姓名',
|
|
|
+ width: '120px',
|
|
|
+ prop: 'userName',
|
|
|
+ sortable: false,
|
|
|
+ disableCheck: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '岗位',
|
|
|
+ width: 'auto',
|
|
|
+ prop: 'userPost',
|
|
|
+ sortable: false,
|
|
|
+ disableCheck: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '电话',
|
|
|
+ width: 'auto',
|
|
|
+ prop: 'userPhone',
|
|
|
+ sortable: false,
|
|
|
+ disableCheck: false,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ checkAll: false,
|
|
|
+ isIndeterminate: false,
|
|
|
+ form: {
|
|
|
+ userId: 0,
|
|
|
+ checkList: [],
|
|
|
+ },
|
|
|
+ regionId: 0,
|
|
|
+ saleRegionName: '',
|
|
|
+ visible: false,
|
|
|
+ deptOptions: [],
|
|
|
+ defaultProps: {
|
|
|
+ id: 'id',
|
|
|
+ regionCode: 'regionCode',
|
|
|
+ label: 'regionDesc',
|
|
|
+ },
|
|
|
+ options: [], //区域选项
|
|
|
+ flatOptions: [], //扁平化区域
|
|
|
+ dialogLoading: false,
|
|
|
+ allocated: [], //已被分配的城市
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ finallyColumns() {
|
|
|
+ return this.columns.filter((item) => this.checkList.includes(item.label))
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async fetchData() {
|
|
|
+ const [err, res] = await to(regAuthApi.getList(this.queryForm))
|
|
|
+ if (err) return
|
|
|
+ this.list = res.data.list || []
|
|
|
+ this.total = res.data.total
|
|
|
+ this.form = {
|
|
|
+ userId: 0,
|
|
|
+ checkList: [],
|
|
|
+ }
|
|
|
+ this.regionList = []
|
|
|
+ },
|
|
|
+ handleRowClick(row) {
|
|
|
+ this.form.userId = row.userId
|
|
|
+ this.form.userName = row.userName
|
|
|
+ this.form.userPost = row.userPost
|
|
|
+ this.form.userPhone = row.userPhone
|
|
|
+ this.getSndList()
|
|
|
+ },
|
|
|
+ async getSndList() {
|
|
|
+ const [err, res] = await to(
|
|
|
+ regAuthApi.getDetail({
|
|
|
+ userId: this.form.userId,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
+ this.regionList = res.data.list || []
|
|
|
+ },
|
|
|
+ handleSearch() {
|
|
|
+ this.queryForm.pageNum = 1
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
+ reset() {
|
|
|
+ this.queryForm = {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ keyWords: '',
|
|
|
+ deptId: 2,
|
|
|
+ }
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
+ handleSizeChange(val) {
|
|
|
+ this.queryForm.pageSize = val
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
+ handleCurrentChange(val) {
|
|
|
+ this.queryForm.pageNum = val
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
+ async handleAuth() {
|
|
|
+ if (!this.form.userId) return this.$message.warning('请选择用户')
|
|
|
+ this.visible = true
|
|
|
+ this.getRegionList()
|
|
|
+ },
|
|
|
+ async getRegionList() {
|
|
|
+ const { data: data } = await regionApi.getRegionList()
|
|
|
+ this.deptOptions = data.list
|
|
|
+ this.regionId = data.list[0].id
|
|
|
+ this.saleRegionName = data.list[0].regionDesc
|
|
|
+ //默认第一选中
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$refs.tree.setCurrentKey(this.regionId)
|
|
|
+ this.handleNodeClick({ id: this.regionId, regionDesc: this.saleRegionName })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async handleDetail() {
|
|
|
+ this.form.checkList = []
|
|
|
+ this.allocated = []
|
|
|
+ const [err, res] = await to(
|
|
|
+ regAuthApi.getDetail({
|
|
|
+ // userId: this.form.userId,
|
|
|
+ saleRegionId: this.regionId,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
+ const list = res.data.list || []
|
|
|
+ for (const item of list) {
|
|
|
+ if (item.userId == this.form.userId) this.form.checkList.push(item.cityId)
|
|
|
+ else this.allocated.push(item)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async handleNodeClick(data) {
|
|
|
+ this.checkAll = false
|
|
|
+ this.isIndeterminate = false
|
|
|
+ this.regionId = data.id
|
|
|
+ this.saleRegionName = data.regionDesc
|
|
|
+ await this.handleDetail()
|
|
|
+ const [err, res] = await to(regionApi.getRegionDetailList({ regionId: data.id }))
|
|
|
+ if (err) return
|
|
|
+ this.flatOptions = res.data.list || []
|
|
|
+ this.flatOptions.forEach((item) => (item.saleRegionName = data.regionDesc))
|
|
|
+ let obj = []
|
|
|
+ for (const item of this.flatOptions) {
|
|
|
+ const target = obj.findIndex((each) => each.custProvinceId == item.custProvinceId)
|
|
|
+ const newItem = { ...item, allocator: [] }
|
|
|
+ const allocator = this.allocated.find((each) => each.cityId == item.custCityId)
|
|
|
+ if (allocator) {
|
|
|
+ newItem.allocator.push(allocator.userName)
|
|
|
+ }
|
|
|
+ if (target > -1) {
|
|
|
+ obj[target].children.push(newItem)
|
|
|
+ } else {
|
|
|
+ obj.push({
|
|
|
+ checkAll: false,
|
|
|
+ isIndeterminate: false,
|
|
|
+ custProvinceId: item.custProvinceId,
|
|
|
+ custProvince: item.custProvince,
|
|
|
+ children: [newItem],
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.options = obj
|
|
|
+ this.handleChange(this.form.checkList)
|
|
|
+ },
|
|
|
+ // 筛选节点
|
|
|
+ filterNode(value, data) {
|
|
|
+ if (!value) return true
|
|
|
+ return data[this.defaultProps.label].indexOf(value) !== -1
|
|
|
+ },
|
|
|
+ handleClose() {
|
|
|
+ // this.form = {
|
|
|
+ // userId: 0,
|
|
|
+ // checkList: [],
|
|
|
+ // }
|
|
|
+ this.getSndList()
|
|
|
+ },
|
|
|
+ handleCheckAllChange(val) {
|
|
|
+ this.form.checkList = val ? this.flatOptions.map((item) => item.custCityId) : []
|
|
|
+ this.options.forEach((item) => {
|
|
|
+ item.checkAll = val
|
|
|
+ })
|
|
|
+ this.isIndeterminate = false
|
|
|
+ this.$forceUpdate()
|
|
|
+ this.save()
|
|
|
+ },
|
|
|
+ handleSndCheckAllChange(val, item) {
|
|
|
+ item.isIndeterminate = false
|
|
|
+ for (let i = 0; i < item.children.length; i++) {
|
|
|
+ const index = this.form.checkList.findIndex((each) => each == item.children[i].custCityId)
|
|
|
+ if (index > -1) {
|
|
|
+ this.form.checkList.splice(index, 1)
|
|
|
+ i--
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const arr = item.children.map((each) => each.custCityId)
|
|
|
+ if (val) this.form.checkList = [...this.form.checkList, ...arr]
|
|
|
+ this.$forceUpdate()
|
|
|
+ this.save()
|
|
|
+ },
|
|
|
+ handleChange(val, item) {
|
|
|
+ if (item) {
|
|
|
+ let count = 0
|
|
|
+ for (const child of item.children) {
|
|
|
+ console.log(child, child.custCityId, this.form.checkList, '---')
|
|
|
+ if (this.form.checkList.includes(child.custCityId)) count++
|
|
|
+ }
|
|
|
+ item.checkAll = count == item.children.length
|
|
|
+ item.isIndeterminate = count > 0 && count < item.children.length
|
|
|
+ this.save()
|
|
|
+ } else {
|
|
|
+ for (const pro of this.options) {
|
|
|
+ let count = 0
|
|
|
+ pro.children.forEach((city) => {
|
|
|
+ if (this.form.checkList.includes(city.custCityId)) count++
|
|
|
+ })
|
|
|
+ pro.checkAll = count == pro.children.length
|
|
|
+ pro.isIndeterminate = count > 0 && count < pro.children.length
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.$forceUpdate()
|
|
|
+ this.isIndeterminate = val.length > 0 && val.length < this.flatOptions.length
|
|
|
+ this.checkAll = val.length == this.flatOptions.length && val.length > 0
|
|
|
+ },
|
|
|
+ async save() {
|
|
|
+ this.dialogLoading = true
|
|
|
+ let params = { ...this.form }
|
|
|
+ params.saleRegionId = this.regionId
|
|
|
+ params.saleRegionName = this.saleRegionName
|
|
|
+ let arr = []
|
|
|
+ for (const item of params.checkList) {
|
|
|
+ const obj = this.flatOptions.find((each) => each.id == item)
|
|
|
+ if (obj)
|
|
|
+ arr.push({
|
|
|
+ saleRegionId: obj.regionId,
|
|
|
+ saleRegionName: obj.saleRegionName,
|
|
|
+ provinceId: obj.custProvinceId,
|
|
|
+ provinceName: obj.custProvince,
|
|
|
+ cityId: obj.custCityId,
|
|
|
+ cityName: obj.custCity,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ params.regions = arr
|
|
|
+ const [err, res] = await to(regAuthApi.saveRegion(params))
|
|
|
+ if (err) return (this.dialogLoading = false)
|
|
|
+ this.$message.success(res.msg)
|
|
|
+ this.dialogLoading = false
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .side-layout {
|
|
|
+ height: 600px;
|
|
|
+ }
|
|
|
+ .el-icon-check {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #67c23a;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .vab-theme-blue-black .side-layout .tree-table {
|
|
|
+ padding: 10px 20px;
|
|
|
+ .province {
|
|
|
+ margin: 20px 0;
|
|
|
+ line-height: 24px;
|
|
|
+ h3 {
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 5px;
|
|
|
+ background: #eee;
|
|
|
+ }
|
|
|
+ .check-container {
|
|
|
+ padding-left: 8px;
|
|
|
+ line-height: 30px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|