10 files modified
5 files added
| | |
| | | <div class="top-bar__right"> |
| | | <div class="top-user"> |
| | | <div class="icon-box"> |
| | | <img class="gateway" @click="jumpMH" src="@/assets/images/mh.png" alt="进入门户" title="进入门户"> |
| | | <img class="gateway" @click="jumpMH" src="@/assets/images/mh.png" alt="进入门户" title="进入门户"> |
| | | </div> |
| | | |
| | | <el-dropdown> |
| | | <el-dropdown popper-class="ztzf-custom-dropdown"> |
| | | <span class="el-dropdown-link"> |
| | | <!-- <img v-if="userInfo.avatar" class="top-bar__img top-bar__user__img" :src="userInfo.avatar" alt="" /> --> |
| | | <img class="top-bar__img" :src="defaultAva" alt="" /> |
| | | <img class="top-bar__img" :src="userInfo.avatar" alt="" /> |
| | | </span> |
| | | |
| | | <template #dropdown> |
| | |
| | | <!-- <el-dropdown-item> |
| | | <router-link to="/">{{ $t('navbar.dashboard') }}</router-link> |
| | | </el-dropdown-item>--> |
| | | <el-dropdown-item> |
| | | <!-- <el-dropdown-item> |
| | | <router-link to="/info/index">{{ $t('navbar.userinfo') }}</router-link> |
| | | </el-dropdown-item> |
| | | </el-dropdown-item> --> |
| | | <el-dropdown-item @click="logout" divided>{{ $t('navbar.logOut') }} |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import defaultAva from '@/assets/images/defaultava.png' |
| | | |
| | | import logo from '@/assets/images/topContainer/logo.png' |
| | | |
| | | import { mapGetters } from 'vuex' |
| | |
| | | data () { |
| | | return { |
| | | logoUrl: logo, |
| | | defaultAva: defaultAva |
| | | } |
| | | }, |
| | | filters: {}, |
| | |
| | | |
| | | .top-bar__img { |
| | | margin-top: 5px; |
| | | width: 16px; |
| | | height: 21px; |
| | | } |
| | | |
| | | .top-bar__user__img { |
| | | width: 24px; |
| | | height: 24px; |
| | | width: 20px; |
| | | height: 20px; |
| | | border: 2px solid #383874; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .el-dropdown-link { |
| | |
| | | import { setStore, getStore } from '@/utils/store'; |
| | | import { validatenull } from '@/utils/validate'; |
| | | import { deepClone } from '@/utils/util'; |
| | | import defaultAva from '@/assets/images/defaultava.png' |
| | | import { |
| | | loginByUsername, |
| | | loginBySocial, |
| | |
| | | if (validatenull(userInfo.user_id) && validatenull(userInfo.account)) { |
| | | state.userInfo = { user_name: 'unauth', role_name: 'unauth' }; |
| | | } else { |
| | | if (validatenull(userInfo.avatar)) { |
| | | userInfo.avatar = defaultAva; |
| | | } |
| | | state.userInfo = userInfo; |
| | | } |
| | | setStore({ name: 'userInfo', content: state.userInfo }); |
| | |
| | | /* 下拉菜单整体样式 */ |
| | | .ztzf-custom-dropdown { |
| | | background: #1A1A2A !important; |
| | | border-radius: 8px; |
| | | border: none !important; |
| | | .el-popper__arrow::before { |
| | | background: #1A1A2A !important; |
| | | border: 1px solid #1A1A2A !important; |
| | | } |
| | | |
| | | /* 菜单项样式 */ |
| | | .el-dropdown-menu { |
| | | background: transparent !important; |
| | | |
| | | .el-dropdown-menu__item { |
| | | color: #fff !important; /* 文字颜色 */ |
| | | |
| | | a { |
| | | color: #fff !important; /* 文字颜色 */ |
| | | } |
| | | |
| | | &:hover { |
| | | background: none !important; |
| | | } |
| | | |
| | | &.is-disabled { |
| | | color: #8f9bb3 !important; |
| | | } |
| | | } |
| | | |
| | | .el-dropdown-menu__item--divided { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 数据驾驶舱专属 |
| | | .ztzf-data-cockpit-search-input { |
| | | .el-input__wrapper { |
| | |
| | | border-radius: 0px 0px 8px 8px; |
| | | } |
| | | } |
| | | |
| | | .el-popper__arrow::before { |
| | | background: #2E2E48 !important; |
| | | border: 1px solid #2E2E48 !important; |
| | | } |
| | | } |
| | | |
| | | .ztzf-data-cockpit-select-popper.el-cascader__dropdown { |
| | | border: none; |
| | | background: #2E2E48 !important; |
| | | |
| | | .el-popper__arrow::before { |
| | | background: #2E2E48 !important; |
| | |
| | | |
| | | .el-button { |
| | | min-width: 88px; |
| | | border: none; |
| | | } |
| | | |
| | | .el-button.is-disabled, .el-button.is-disabled:hover { |
| | |
| | | |
| | | th.el-table__cell { |
| | | height: 40px; |
| | | border-bottom: 1px solid #323241; |
| | | background: transparent !important; |
| | | border-bottom: 1px solid #323241 !important; |
| | | |
| | | .cell { |
| | | padding: 0; |
| | |
| | | td.el-table__cell { |
| | | padding: 9px 0; |
| | | height: 56px; |
| | | border-bottom: 1px solid #323241; |
| | | background: transparent !important; |
| | | border-bottom: 1px solid #323241 !important; |
| | | |
| | | .cell { |
| | | padding: 0; |
| | |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | th.el-table__cell:not(.fixed-column), |
| | | td.el-table__cell:not(.fixed-column) { |
| | | background: transparent !important; |
| | | } |
| | | |
| | | .fixed-column { |
| | | background-color: #1A1A2A !important; |
| | | } |
| | | } |
| | | |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .el-input { |
| | | .el-input, |
| | | .el-input-number { |
| | | width: 0; |
| | | flex: 1; |
| | | } |
| | | |
| | | .el-cascader { |
| | | width: 0; |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | border: none; |
| | | |
| | | .el-input__wrapper { |
| | | box-shadow: none !important; |
| | | } |
| | | } |
| | | |
| | | .el-textarea { |
| | |
| | | .el-input { |
| | | .el-input__wrapper { |
| | | background: #2E2E48 !important; |
| | | box-shadow: none; |
| | | |
| | | .el-input__inner { |
| | | color: #ffffff; |
| | |
| | | align-items: center; |
| | | |
| | | .label { |
| | | width: 112px; |
| | | width: 96px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 500; |
| | | font-size: 14px; |
| | |
| | | |
| | | .left-box, |
| | | .right-box { |
| | | position: relative; |
| | | padding: 17px 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100px; |
| | | background: #05050F; |
| | | background: rgba(0,0,0,0.3); |
| | | box-sizing: border-box; |
| | | border-radius: 16px 16px 16px 16px; |
| | | pointer-events: auto; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | z-index: -1; |
| | | background: rgba(17, 23, 34, 0.56); |
| | | backdrop-filter: blur(2px); |
| | | border-radius: 16px 16px 16px 16px; |
| | | } |
| | | |
| | | |
| | | .logo { |
| | | img { |
| | | width: 40px; |
| | |
| | | {{ getWorkModeLabel(row.workMode) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" class-name="operation-btns" width="100"> |
| | | <el-table-column fixed="right" label="操作" class-name="operation-btns fixed-column" width="100"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="openForm('view', row)" type="primary">查看</el-link> |
| | | </template> |
| | |
| | | <template> |
| | | <basic-container> |
| | | 部门管理 |
| | | </basic-container> |
| | | <PermissionDept /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import PermissionDept from './permissionDept/index.vue' |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <el-dialog class="ztzf-page-view-dialog" v-model="visible" :title="dialogTitle" @closed="handleClosed" destroy-on-close> |
| | | <div class="detail-container" v-if="dialogReadonly"> |
| | | <div class="detail-title">机构详情</div> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div class="label">部门名称</div> |
| | | <div class="val">{{ formData.deptName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">部门全称</div> |
| | | <div class="val">{{ formData.fullName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">上级部门</div> |
| | | <div class="val">{{ formData.parentName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">部门类型</div> |
| | | <div class="val">{{ getDictLabel(formData.deptCategory, dictObj.org_category) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">部门性质</div> |
| | | <div class="val">{{ getDictLabel(formData.deptNature, dictObj.org_nature) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">行政区划</div> |
| | | <div class="val">{{ formData.areaName || '-' }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">部署模式</div> |
| | | <div class="val">{{ deploymentModeLabel(formData.deploymentMode) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">排序</div> |
| | | <div class="val">{{ formData.sort }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div class="label">备注</div> |
| | | <div class="val">{{ formData.remark || '-' }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="部门名称" prop="deptName"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="formData.deptName" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="部门全称" prop="fullName"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="formData.fullName" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="上级部门" prop="parentId"> |
| | | <el-tree-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-tree-select-popper" |
| | | v-model="formData.parentId" |
| | | :data="deptTree" |
| | | :props="treeProps" |
| | | node-key="id" |
| | | check-strictly |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="部门类型" prop="deptCategory"> |
| | | <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper" v-model="formData.deptCategory" placeholder="请选择" clearable> |
| | | <el-option v-for="item in dictObj.org_category" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="部门性质" prop="deptNature"> |
| | | <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper" v-model="formData.deptNature" placeholder="请选择" clearable> |
| | | <el-option v-for="item in dictObj.org_nature" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="排序" prop="sort"> |
| | | <el-input-number v-model="formData.sort" :min="0" :controls="false" placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="行政区划" prop="areaCode"> |
| | | <el-cascader |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="formData.areaCode" |
| | | :props="areaProps" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="部署模式" prop="deploymentMode"> |
| | | <el-radio-group v-model="formData.deploymentMode"> |
| | | <el-radio :label="0">统一部署</el-radio> |
| | | <el-radio :label="1">独立部署</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="备注" prop="remark"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button color="#284FE3" v-if="!dialogReadonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> |
| | | 保存 |
| | | </el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, inject, ref } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { add, getDept, getDeptTree, update } from '@/api/system/dept' |
| | | import { getLazyTree } from '@/api/base/region' |
| | | import { fieldRules, getDictLabel } from '@ztzf/utils' |
| | | |
| | | const initForm = () => ({ |
| | | deptName: '', |
| | | fullName: '', |
| | | parentId: '', |
| | | parentName: '', |
| | | deptCategory: '', |
| | | deptNature: '', |
| | | areaCode: '', |
| | | areaName: '', |
| | | deploymentMode: 0, |
| | | sort: 0, |
| | | remark: '', |
| | | }) |
| | | |
| | | const treeProps = { |
| | | label: 'name', |
| | | children: 'children', |
| | | } |
| | | |
| | | const areaProps = { |
| | | label: 'title', |
| | | value: 'value', |
| | | emitPath: false, |
| | | checkStrictly: true, |
| | | lazy: true, |
| | | lazyLoad(node, resolve) { |
| | | const level = node.level |
| | | let list = [] |
| | | const callback = () => { |
| | | resolve( |
| | | (list || []).map(ele => ({ |
| | | ...ele, |
| | | value: ele.value, |
| | | leaf: level >= 2, |
| | | })) |
| | | ) |
| | | } |
| | | if (level === 0) { |
| | | getLazyTree('00').then(res => { |
| | | list = res.data.data |
| | | callback() |
| | | }) |
| | | } else { |
| | | getLazyTree(node.value).then(res => { |
| | | list = res.data.data |
| | | callback() |
| | | }) |
| | | } |
| | | }, |
| | | } |
| | | |
| | | const dictObj = inject('dictObj') |
| | | const deptTree = inject('deptTree') |
| | | const emit = defineEmits(['success']) |
| | | const formRef = ref(null) |
| | | const formData = ref(initForm()) |
| | | const visible = ref(false) |
| | | const dialogMode = ref('add') |
| | | const submitting = ref(false) |
| | | const dialogReadonly = computed(() => dialogMode.value === 'view') |
| | | const dialogTitle = computed(() => { |
| | | if (dialogMode.value === 'edit') return '编辑' |
| | | if (dialogMode.value === 'view') return '查看' |
| | | return '新增' |
| | | }) |
| | | |
| | | const rules = { |
| | | deptName: fieldRules(true, 50), |
| | | fullName: fieldRules(true, 50), |
| | | parentId: fieldRules(false), |
| | | deptCategory: fieldRules(true), |
| | | deptNature: fieldRules(true), |
| | | areaCode: fieldRules(true), |
| | | deploymentMode: fieldRules(true), |
| | | sort: fieldRules(true), |
| | | } |
| | | |
| | | function deploymentModeLabel(value) { |
| | | if (value === 1) return '独立部署' |
| | | if (value === 0) return '统一部署' |
| | | return value ?? '-' |
| | | } |
| | | |
| | | function normalizeAreaCode(value) { |
| | | if (!value) return '' |
| | | if (Array.isArray(value)) { |
| | | return value[value.length - 1] |
| | | } |
| | | if (typeof value === 'string' && value.includes(',')) { |
| | | const codes = value.split(',') |
| | | return codes[codes.length - 1] |
| | | } |
| | | return value |
| | | } |
| | | |
| | | function getFullAreaCode(areaCode) { |
| | | if (!areaCode) return '' |
| | | const code = areaCode.toString() |
| | | if (code.includes(',')) return code |
| | | if (code.endsWith('0000000000')) { |
| | | return code |
| | | } else if (code.endsWith('00000000') && !code.endsWith('0000000000')) { |
| | | const provinceCode = code.substring(0, 2) + '0000000000' |
| | | return `${provinceCode},${code}` |
| | | } else { |
| | | const provinceCode = code.substring(0, 2) + '0000000000' |
| | | const cityCode = code.substring(0, 4) + '00000000' |
| | | return `${provinceCode},${cityCode},${code}` |
| | | } |
| | | } |
| | | |
| | | function handleCancel() { |
| | | visible.value = false |
| | | } |
| | | |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | const payload = { |
| | | ...formData.value, |
| | | areaCode: normalizeAreaCode(formData.value.areaCode), |
| | | } |
| | | if (dialogMode.value === 'edit') { |
| | | await update(payload) |
| | | } else { |
| | | await add(payload) |
| | | } |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | async function loadDetail(id) { |
| | | if (!id) return |
| | | const res = await getDept(id) |
| | | const data = res?.data?.data ?? {} |
| | | formData.value = { |
| | | ...data, |
| | | areaCode: getFullAreaCode(data.areaCode), |
| | | } |
| | | } |
| | | |
| | | function handleClosed() { |
| | | formData.value = initForm() |
| | | } |
| | | |
| | | async function open({ mode, row, parent } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | | visible.value = true |
| | | await getDeptTree().then(res => { |
| | | if (deptTree) { |
| | | deptTree.value = res?.data?.data ?? [] |
| | | } |
| | | }) |
| | | if (dialogMode.value === 'add') { |
| | | formData.value = initForm() |
| | | if (parent?.id) { |
| | | formData.value.parentId = parent.id |
| | | formData.value.parentName = parent.deptName |
| | | } |
| | | return |
| | | } |
| | | formData.value = row |
| | | await loadDetail(row?.id) |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| New file |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search"> |
| | | <el-form-item label="部门名称" prop="deptName"> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.deptName" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="部门全称" prop="fullName"> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.fullName" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item class="history-search-actions"> |
| | | <el-button :icon="RefreshRight" @click="resetForm"></el-button> |
| | | <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="ztzf-table-toolbar"> |
| | | <el-button :icon="Plus" color="#284FE3" type="primary" @click="handleAdd">新增</el-button> |
| | | <el-button :icon="Delete" color="#1A2652" type="primary" :disabled="!selectedIds.length" @click="handleDelete()"> |
| | | 删除 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)"> |
| | | <div class="ztzf-table-content ztzf-table-content-bg"> |
| | | <el-table |
| | | class="ztzf-data-cockpit-table" |
| | | :data="list" |
| | | row-key="id" |
| | | lazy |
| | | :load="loadChildren" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="46" /> |
| | | <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> |
| | | <el-table-column prop="deptName" show-overflow-tooltip label="部门名称" /> |
| | | <el-table-column prop="fullName" show-overflow-tooltip label="部门全称" /> |
| | | <el-table-column prop="deptCategory" show-overflow-tooltip width="120" label="部门类型"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.deptCategory, dictObj.org_category) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deptNature" show-overflow-tooltip width="120" label="部门性质"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.deptNature, dictObj.org_nature) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="sort" show-overflow-tooltip width="80" label="排序" /> |
| | | <el-table-column prop="bingId" show-overflow-tooltip width="100" label="组织id" /> |
| | | <el-table-column prop="areaName" show-overflow-tooltip width="180" label="行政区划" /> |
| | | <el-table-column prop="deploymentMode" show-overflow-tooltip width="120" label="部署模式"> |
| | | <template v-slot="{ row }"> |
| | | {{ deploymentModeLabel(row.deploymentMode) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" class-name="operation-btns" width="220"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="handleView(row)">查看</el-link> |
| | | <el-link @click="handleEdit(row)">编辑</el-link> |
| | | <el-link @click="handleAddChild(row)">新增子项</el-link> |
| | | <el-link type="danger" @click="handleDelete(row)">删除</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-pagination"> |
| | | <el-pagination |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <FormDiaLog ref="dialogRef" @success="getList" /> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Delete, Plus, RefreshRight, Search } from '@element-plus/icons-vue' |
| | | import { onMounted, provide, ref } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { getDictionary } from '@/api/system/dict' |
| | | import { getChildLazyTree, getDeptTree, getLazyList, remove } from '@/api/system/dept' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | |
| | | const initSearchParams = () => ({ |
| | | deptName: '', |
| | | fullName: '', |
| | | current: 1, |
| | | size: 10, |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) |
| | | const loading = ref(true) |
| | | const list = ref([]) |
| | | const total = ref(0) |
| | | const selectedIds = ref([]) |
| | | const queryParamsRef = ref(null) |
| | | const dialogRef = ref(null) |
| | | const dictObj = ref({ |
| | | org_category: [], |
| | | org_nature: [], |
| | | }) |
| | | const deptTree = ref([]) |
| | | |
| | | provide('dictObj', dictObj) |
| | | provide('deptTree', deptTree) |
| | | |
| | | function deploymentModeLabel(value) { |
| | | if (value === 1) return '独立部署' |
| | | if (value === 0) return '统一部署' |
| | | return value ?? '-' |
| | | } |
| | | |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const res = await getLazyList(0, searchParams.value) |
| | | list.value = res?.data?.data ?? [] |
| | | total.value = list.value.length |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | function handleAdd() { |
| | | dialogRef.value?.open({ mode: 'add' }) |
| | | } |
| | | |
| | | function handleAddChild(row) { |
| | | dialogRef.value?.open({ mode: 'add', parent: row }) |
| | | } |
| | | |
| | | function handleView(row) { |
| | | dialogRef.value?.open({ mode: 'view', row: { ...row } }) |
| | | } |
| | | |
| | | function handleEdit(row) { |
| | | dialogRef.value?.open({ mode: 'edit', row: { ...row } }) |
| | | } |
| | | |
| | | async function handleDelete(row) { |
| | | const tips = row ? '该条' : '选中的项' |
| | | await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { |
| | | type: 'warning', |
| | | customClass: 'ztzf-page-view-message-box', |
| | | confirmButtonClass: 'ztzf-message-box-confirm', |
| | | cancelButtonClass: 'ztzf-message-box-cancel', |
| | | }) |
| | | const ids = row ? row.id : selectedIds.value.join(',') |
| | | await remove(ids) |
| | | ElMessage.success('删除成功') |
| | | selectedIds.value = [] |
| | | getList() |
| | | } |
| | | |
| | | function handleSelectionChange(rows) { |
| | | selectedIds.value = rows.map(item => item.id) |
| | | } |
| | | |
| | | function getDictList() { |
| | | Promise.all([getDictionary({ code: 'org_category' }), getDictionary({ code: 'org_nature' })]).then( |
| | | ([categoryRes, natureRes]) => { |
| | | dictObj.value = { |
| | | org_category: categoryRes?.data?.data ?? [], |
| | | org_nature: natureRes?.data?.data ?? [], |
| | | } |
| | | } |
| | | ) |
| | | } |
| | | |
| | | function getDeptTreeList() { |
| | | getDeptTree().then(res => { |
| | | deptTree.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | function loadChildren(row, treeNode, resolve) { |
| | | getChildLazyTree({ parentId: row.id }) |
| | | .then(res => { |
| | | resolve(res?.data?.data ?? []) |
| | | }) |
| | | .catch(() => resolve([])) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | getDictList() |
| | | getDeptTreeList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| | |
| | | <template> |
| | | <basic-container> |
| | | 角色管理 |
| | | </basic-container> |
| | | <PermissionRole /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import PermissionRole from './permissionRole/index.vue' |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <el-dialog class="ztzf-page-view-dialog" v-model="visible" :title="dialogTitle" @closed="handleClosed" destroy-on-close> |
| | | <div class="detail-container" v-if="dialogReadonly"> |
| | | <div class="detail-title">角色详情</div> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div class="label">角色名称</div> |
| | | <div class="val">{{ formData.roleName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">角色别名</div> |
| | | <div class="val">{{ formData.roleAlias }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">上级角色</div> |
| | | <div class="val">{{ formData.parentName || '-' }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">角色排序</div> |
| | | <div class="val">{{ formData.sort }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="角色名称" prop="roleName"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="formData.roleName" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="角色别名" prop="roleAlias"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="formData.roleAlias" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="上级角色" prop="parentId"> |
| | | <el-tree-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-tree-select-popper" |
| | | v-model="formData.parentId" |
| | | :data="roleTree" |
| | | :props="treeProps" |
| | | node-key="id" |
| | | check-strictly |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="角色排序" prop="sort"> |
| | | <el-input-number v-model="formData.sort" :min="0" :controls="false" placeholder="请输入" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button color="#284FE3" v-if="!dialogReadonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> |
| | | 保存 |
| | | </el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { add, getRoleTreeById, update } from '@/api/system/role' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | |
| | | const initForm = () => ({ |
| | | roleName: '', |
| | | roleAlias: '', |
| | | parentId: '', |
| | | parentName: '', |
| | | sort: 0, |
| | | }) |
| | | |
| | | const treeProps = { |
| | | label: 'title', |
| | | children: 'children', |
| | | value: 'id', |
| | | } |
| | | |
| | | const emit = defineEmits(['success']) |
| | | const formRef = ref(null) |
| | | const formData = ref(initForm()) |
| | | const visible = ref(false) |
| | | const dialogMode = ref('add') |
| | | const submitting = ref(false) |
| | | const dialogReadonly = computed(() => dialogMode.value === 'view') |
| | | const dialogTitle = computed(() => { |
| | | if (dialogMode.value === 'edit') return '编辑' |
| | | if (dialogMode.value === 'view') return '查看' |
| | | return '新增' |
| | | }) |
| | | const roleTree = ref([]) |
| | | |
| | | const rules = { |
| | | roleName: fieldRules(true, 50), |
| | | roleAlias: fieldRules(true, 50), |
| | | parentId: fieldRules(false), |
| | | sort: fieldRules(true), |
| | | } |
| | | |
| | | function handleCancel() { |
| | | visible.value = false |
| | | } |
| | | |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | if (dialogMode.value === 'edit') { |
| | | await update(formData.value) |
| | | } else { |
| | | await add(formData.value) |
| | | } |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | async function loadRoleTree(roleId) { |
| | | const res = await getRoleTreeById(roleId) |
| | | roleTree.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | function handleClosed() { |
| | | formData.value = initForm() |
| | | } |
| | | |
| | | async function open({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | | visible.value = true |
| | | if (dialogMode.value === 'add') { |
| | | formData.value = initForm() |
| | | await loadRoleTree() |
| | | return |
| | | } |
| | | formData.value = { ...row } |
| | | await loadRoleTree(row?.id) |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| New file |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | title="角色权限配置" |
| | | width="620px" |
| | | append-to-body |
| | | :close-on-click-modal="false" |
| | | @closed="handleClosed" |
| | | > |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="后台管理"> |
| | | <el-tree |
| | | ref="treeMenu" |
| | | :data="menuGrantList" |
| | | show-checkbox |
| | | node-key="id" |
| | | :default-checked-keys="menuTreeObj" |
| | | :props="treeProps" |
| | | /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="移动app"> |
| | | <el-tree |
| | | ref="treeMenuApp" |
| | | :data="menuGrantListApp" |
| | | show-checkbox |
| | | node-key="id" |
| | | :default-checked-keys="menuTreeObjApp" |
| | | :props="treeProps" |
| | | /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="新大屏菜单"> |
| | | <el-tree |
| | | ref="treeMenuWebNew" |
| | | :data="menuGrantListNew" |
| | | show-checkbox |
| | | node-key="id" |
| | | :default-checked-keys="menuTreeObjNew" |
| | | :props="treeProps" |
| | | /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="无人机管控"> |
| | | <el-tree |
| | | ref="droneControl" |
| | | :data="menuGrantListDroneControl" |
| | | show-checkbox |
| | | node-key="id" |
| | | :default-checked-keys="droneControlMenuTreeObj" |
| | | :props="treeProps" |
| | | /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="大屏菜单"> |
| | | <el-tree |
| | | ref="treeMenuWebOld" |
| | | :data="menuGrantListOld" |
| | | show-checkbox |
| | | node-key="id" |
| | | :default-checked-keys="menuTreeObjOld" |
| | | :props="treeProps" |
| | | /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <template #footer> |
| | | <el-button @click="visible = false">取 消</el-button> |
| | | <el-button type="primary" @click="submit">确 定</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import { grant, grantTree, getRole } from '@/api/system/role' |
| | | |
| | | const visible = ref(false) |
| | | const roleId = ref('') |
| | | const treeProps = { |
| | | label: 'title', |
| | | value: 'key', |
| | | } |
| | | const menuGrantList = ref([]) |
| | | const menuGrantListApp = ref([]) |
| | | const menuGrantListOld = ref([]) |
| | | const menuGrantListNew = ref([]) |
| | | const menuGrantListDroneControl = ref([]) |
| | | const menuTreeObj = ref([]) |
| | | const menuTreeObjApp = ref([]) |
| | | const menuTreeObjOld = ref([]) |
| | | const menuTreeObjNew = ref([]) |
| | | const droneControlMenuTreeObj = ref([]) |
| | | |
| | | const treeMenu = ref(null) |
| | | const treeMenuApp = ref(null) |
| | | const treeMenuWebOld = ref(null) |
| | | const treeMenuWebNew = ref(null) |
| | | const droneControl = ref(null) |
| | | |
| | | const emit = defineEmits(['success']) |
| | | |
| | | function resetState() { |
| | | menuGrantList.value = [] |
| | | menuGrantListApp.value = [] |
| | | menuGrantListOld.value = [] |
| | | menuGrantListNew.value = [] |
| | | menuGrantListDroneControl.value = [] |
| | | menuTreeObj.value = [] |
| | | menuTreeObjApp.value = [] |
| | | menuTreeObjOld.value = [] |
| | | menuTreeObjNew.value = [] |
| | | droneControlMenuTreeObj.value = [] |
| | | } |
| | | |
| | | async function loadGrantTree(sysType, setter, keysSetter) { |
| | | const grantRes = await grantTree({ sysType }) |
| | | setter.value = grantRes?.data?.data?.menu ?? [] |
| | | const roleRes = await getRole(roleId.value) |
| | | keysSetter.value = roleRes?.data?.data?.menu ?? [] |
| | | } |
| | | |
| | | async function open({ roleId: id } = {}) { |
| | | roleId.value = id || '' |
| | | visible.value = true |
| | | resetState() |
| | | await Promise.all([ |
| | | loadGrantTree(1, menuGrantList, menuTreeObj), |
| | | loadGrantTree(3, menuGrantListApp, menuTreeObjApp), |
| | | loadGrantTree(4, menuGrantListNew, menuTreeObjNew), |
| | | loadGrantTree(5, menuGrantListDroneControl, droneControlMenuTreeObj), |
| | | loadGrantTree(2, menuGrantListOld, menuTreeObjOld), |
| | | ]) |
| | | } |
| | | |
| | | function submit() { |
| | | const menuList = treeMenu.value?.getCheckedKeys?.() ?? [] |
| | | const menuListApp = treeMenuApp.value?.getCheckedKeys?.() ?? [] |
| | | const menuListWebNew = treeMenuWebNew.value?.getCheckedKeys?.() ?? [] |
| | | const menuListDroneControl = droneControl.value?.getCheckedKeys?.() ?? [] |
| | | const menuListWebOld = treeMenuWebOld.value?.getCheckedKeys?.() ?? [] |
| | | grant([roleId.value], [ |
| | | ...menuList, |
| | | ...menuListApp, |
| | | ...menuListWebNew, |
| | | ...menuListDroneControl, |
| | | ...menuListWebOld, |
| | | ], [], []).then(() => { |
| | | visible.value = false |
| | | emit('success') |
| | | }) |
| | | } |
| | | |
| | | function handleClosed() { |
| | | resetState() |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| New file |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search"> |
| | | <el-form-item label="角色名称" prop="roleName"> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.roleName" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="角色别名" prop="roleAlias"> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.roleAlias" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item class="history-search-actions"> |
| | | <el-button :icon="RefreshRight" @click="resetForm"></el-button> |
| | | <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="ztzf-table-toolbar"> |
| | | <el-button :icon="Plus" color="#284FE3" type="primary" @click="handleAdd">新增</el-button> |
| | | <el-button :icon="Delete" color="#1A2652" type="primary" :disabled="!selectedIds.length" @click="handleDelete()"> |
| | | 删除 |
| | | </el-button> |
| | | <el-button |
| | | color="#1A2652" |
| | | type="primary" |
| | | :disabled="selectedIds.length !== 1" |
| | | v-if="userInfo.role_name?.includes('admin')" |
| | | @click="handleRole" |
| | | > |
| | | 权限设置 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)"> |
| | | <div class="ztzf-table-content ztzf-table-content-bg"> |
| | | <el-table |
| | | class="ztzf-data-cockpit-table" |
| | | :data="list" |
| | | row-key="id" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="46" /> |
| | | <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> |
| | | <el-table-column prop="roleName" show-overflow-tooltip label="角色名称" /> |
| | | <el-table-column prop="roleAlias" show-overflow-tooltip label="角色别名" /> |
| | | <el-table-column prop="sort" show-overflow-tooltip label="角色排序" /> |
| | | <el-table-column label="操作" class-name="operation-btns"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="handleView(row)">查看</el-link> |
| | | <el-link @click="handleEdit(row)">编辑</el-link> |
| | | <el-link v-if="userInfo.role_name?.includes('admin')" @click="handleRole(row)">权限设置</el-link> |
| | | <el-link type="danger" @click="handleDelete(row)">删除</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-pagination"> |
| | | <el-pagination |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" |
| | | :total="total" |
| | | @change="loadList" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <FormDiaLog ref="dialogRef" @success="loadList" /> |
| | | <RolePermissionDialog ref="roleDialogRef" @success="loadList" /> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Delete, Plus, RefreshRight, Search } from '@element-plus/icons-vue' |
| | | import { computed, onMounted, ref } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { getList as getRolePage, remove } from '@/api/system/role' |
| | | import { useStore } from 'vuex' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | import RolePermissionDialog from './RolePermissionDialog.vue' |
| | | |
| | | const initSearchParams = () => ({ |
| | | roleName: '', |
| | | roleAlias: '', |
| | | current: 1, |
| | | size: 10, |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) |
| | | const loading = ref(true) |
| | | const list = ref([]) |
| | | const total = ref(0) |
| | | const selectedIds = ref([]) |
| | | const selectedRows = ref([]) |
| | | const queryParamsRef = ref(null) |
| | | const dialogRef = ref(null) |
| | | const roleDialogRef = ref(null) |
| | | const store = useStore() |
| | | const userInfo = computed(() => store.getters.userInfo || {}) |
| | | |
| | | async function loadList() { |
| | | loading.value = true |
| | | try { |
| | | const res = await getRolePage(searchParams.value.current, searchParams.value.size, searchParams.value) |
| | | const records = res?.data?.data?.records ?? res?.data?.data ?? [] |
| | | list.value = records |
| | | total.value = res?.data?.data?.total ?? res?.data?.total ?? records.length |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | loadList() |
| | | } |
| | | |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value.current = 1 |
| | | loadList() |
| | | } |
| | | |
| | | function handleAdd() { |
| | | dialogRef.value?.open({ mode: 'add' }) |
| | | } |
| | | |
| | | function handleView(row) { |
| | | dialogRef.value?.open({ mode: 'view', row: { ...row } }) |
| | | } |
| | | |
| | | function handleEdit(row) { |
| | | dialogRef.value?.open({ mode: 'edit', row: { ...row } }) |
| | | } |
| | | |
| | | function handleRole(row) { |
| | | const roleId = row?.id ?? selectedRows.value[0]?.id |
| | | if (!roleId) { |
| | | ElMessage.warning('只能选择一条数据') |
| | | return |
| | | } |
| | | if (selectedRows.value.length !== 1 && !row) { |
| | | ElMessage.warning('只能选择一条数据') |
| | | return |
| | | } |
| | | roleDialogRef.value?.open({ roleId }) |
| | | } |
| | | |
| | | async function handleDelete(row) { |
| | | const tips = row ? '该条' : '选中的项' |
| | | await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { |
| | | type: 'warning', |
| | | customClass: 'ztzf-page-view-message-box', |
| | | confirmButtonClass: 'ztzf-message-box-confirm', |
| | | cancelButtonClass: 'ztzf-message-box-cancel', |
| | | }) |
| | | const ids = row ? row.id : selectedIds.value.join(',') |
| | | await remove(ids) |
| | | ElMessage.success('删除成功') |
| | | selectedIds.value = [] |
| | | loadList() |
| | | } |
| | | |
| | | function handleSelectionChange(rows) { |
| | | selectedIds.value = rows.map(item => item.id) |
| | | selectedRows.value = rows |
| | | } |
| | | |
| | | onMounted(() => { |
| | | loadList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| | |
| | | } |
| | | |
| | | if (level === 0) { |
| | | getLazyTree('000000000000').then(res => { |
| | | getLazyTree('00').then(res => { |
| | | list = res.data.data |
| | | callback() |
| | | }) |