Compare commits
4 Commits
main_beta
...
e69cffbdb6
| Author | SHA1 | Date | |
|---|---|---|---|
| e69cffbdb6 | |||
|
|
bcac3326a3 | ||
| f9393dfca8 | |||
| 67fe2e22fc |
@@ -17,21 +17,6 @@ export interface UpdateStatusReqVO {
|
||||
status: number
|
||||
}
|
||||
|
||||
// 获取登陆用户的应用
|
||||
export const getMyPage = async (params: PageParam) => {
|
||||
return await request.get({ url: '/system/oauth2-client/myPage', params })
|
||||
}
|
||||
|
||||
// 获取角色下的应用id
|
||||
export const getRoleAppIds = async (roleId: number) => {
|
||||
return await request.get({ url: '/system/permission/list-role-clients?roleId=' + roleId })
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export const saveApp = async (data: any) => {
|
||||
return await request.post({ url: '/system/permission/assign-role-client', data })
|
||||
}
|
||||
|
||||
// 查询角色列表
|
||||
export const getRolePage = async (params: PageParam) => {
|
||||
return await request.get({ url: '/system/role/page', params })
|
||||
|
||||
@@ -136,6 +136,7 @@ const crudRef = ref()
|
||||
const dimensionFields=ref<any>({})
|
||||
const exportLoading = ref(false)
|
||||
const fieldList = ref<any[]>([]) // 添加fieldList引用
|
||||
const hideFeilds= ref<any>({})
|
||||
const permissions =
|
||||
wsCache.get(CACHE_KEY.USER).lideeYunjipermissions?.[route.meta.menuDataId as string] || false
|
||||
const selectIds = computed(() => {
|
||||
@@ -258,6 +259,8 @@ const initTable = async () => {
|
||||
}
|
||||
if(item.isDimension=='Y'){
|
||||
dimensionFields.value[config.prop]=config
|
||||
hideFeilds.value[config.prop]=item.isHideDimension
|
||||
|
||||
}
|
||||
|
||||
if (item.queryMode == 'RANGE') config.searchRange = true
|
||||
@@ -301,6 +304,7 @@ const initTable = async () => {
|
||||
initTableLayout()
|
||||
}
|
||||
const searchDimension=()=>{
|
||||
|
||||
searchChange()
|
||||
}
|
||||
const initTableLayout = () => {
|
||||
@@ -467,6 +471,15 @@ const clearSearch = () => {
|
||||
const searchChange = (params?, done?) => {
|
||||
if (tablePage.value) tablePage.value['currentPage'] = 1
|
||||
getTableData().finally(() => {
|
||||
let field=tableSearch.value['Group by']
|
||||
let hides=[]
|
||||
if(field.length){
|
||||
hides=Object.keys(hideFeilds.value).length?hideFeilds.value[field].split(','):[]
|
||||
}
|
||||
Object.keys(tableOption.value.column).forEach(key=>{
|
||||
let item=tableOption.value.column[key]
|
||||
item.hide=hides.includes(item.prop)
|
||||
})
|
||||
if (done) done()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
noPermission: `抱歉,您无权访问此页面。`,
|
||||
pageError: '抱歉,您访问的页面不存在。',
|
||||
networkError: '抱歉,服务器报告错误。',
|
||||
returnToHome: '返回首页'
|
||||
returnToHome: '返回工作台'
|
||||
},
|
||||
permission: {
|
||||
hasPermission: `请设置操作权限标签值`,
|
||||
@@ -157,7 +157,7 @@ export default {
|
||||
router: {
|
||||
login: '登录',
|
||||
socialLogin: '社交登录',
|
||||
home: '首页',
|
||||
home: '工作台',
|
||||
analysis: '分析页',
|
||||
workplace: '工作台'
|
||||
},
|
||||
@@ -275,7 +275,7 @@ export default {
|
||||
},
|
||||
exception: {
|
||||
backLogin: '返回登录',
|
||||
backHome: '返回首页',
|
||||
backHome: '返回工作台',
|
||||
subTitle403: '抱歉,您无权访问此页面。',
|
||||
subTitle404: '抱歉,您访问的页面不存在。',
|
||||
subTitle500: '抱歉,服务器报告错误。',
|
||||
|
||||
@@ -40,7 +40,7 @@ v-for="(category, categoryName) in filteredCategories"
|
||||
|
||||
<div class="apps-grid">
|
||||
<div
|
||||
v-for="app in category.apps"
|
||||
v-for="app in category.apps"
|
||||
:key="app.id"
|
||||
class="app-card"
|
||||
@click="handleAppClick(app)">
|
||||
@@ -77,7 +77,7 @@ v-for="(category, categoryName) in filteredCategories"
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as RoleApi from '@/api/system/role'
|
||||
import * as ClientApi from '@/api/system/oauth2/client'
|
||||
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||
export default {
|
||||
name: 'AppManager',
|
||||
@@ -138,7 +138,7 @@ export default {
|
||||
methods: {
|
||||
async fetchApps() {
|
||||
try {
|
||||
const data = await RoleApi.getMyPage({ pageNo: 1, pageSize: 1000 })
|
||||
const data = await ClientApi.getOAuth2ClientPage({ pageNo: 1, pageSize: 1000 })
|
||||
const list = data?.list || []
|
||||
this.appsData = list.map(item => ({
|
||||
id: item.id,
|
||||
|
||||
@@ -183,6 +183,43 @@ export const useRenderVxeColumn = (useType = 'table') => {
|
||||
)
|
||||
}
|
||||
},
|
||||
LowSelectMultiple: {
|
||||
default: (renderOpts, { row, column }, isStop = false) => {
|
||||
const { dicData } = renderOpts
|
||||
const value = row[column.field]
|
||||
const valStr=dicData.filter(item=>value.includes(item.value)).map(item=>item.label).join(',')
|
||||
return <span>{valStr}</span>
|
||||
},
|
||||
edit: (renderOpts, { row, rowIndex, column }) => {
|
||||
const { multiple, filterable, allowCreate, typeKey ,dicData} = renderOpts
|
||||
interface DictItem {
|
||||
label: string;
|
||||
value: string | number;
|
||||
[key: string]: any; // 兼容其他可能的字段
|
||||
}
|
||||
return (
|
||||
<el-select
|
||||
popper-class="vxe-table--ignore-clear"
|
||||
v-model={row[column.field]}
|
||||
placeholder={'请选择 ' + column.title}
|
||||
multiple={multiple}
|
||||
filterable={filterable}
|
||||
collapseTags={true}
|
||||
collapseTagsTooltip={true}
|
||||
allowCreate={allowCreate}
|
||||
clearable={true}
|
||||
>
|
||||
{dicData.map((item: DictItem, index: number) => (
|
||||
<el-option
|
||||
key={index} // 建议用 item.value 作为 key,更稳定
|
||||
label={item.label}
|
||||
value={item.value}
|
||||
/>
|
||||
))}
|
||||
</el-select>
|
||||
)
|
||||
}
|
||||
},
|
||||
LowSummaryBottomSql: {
|
||||
default: (renderOpts, { row, column }, isStop = false) => {
|
||||
const { dicObj } = renderOpts
|
||||
|
||||
@@ -89,6 +89,7 @@ const parentFieldMap = ref(new Map())
|
||||
const fieldList = computed(() => {
|
||||
let dicData: Array<{ label: string; value: string; type: string }> = []
|
||||
infoData.value.basics.forEach((item) => {
|
||||
|
||||
if (item.fieldCode && item.isDb == 'Y')
|
||||
dicData.push({
|
||||
label: `${item.fieldCode}${item.fieldName ? '(' + item.fieldName + ')' : ''}`,
|
||||
@@ -257,7 +258,9 @@ const initEditInfoData = () => {
|
||||
if (fieldItem.hasChildren === 'Y') {
|
||||
fieldItem.hasChildren = 'Y'
|
||||
}
|
||||
|
||||
if (!!fieldItem.isHideDimension&&Object.prototype.toString.call(fieldItem.isHideDimension) == '[object String]') {
|
||||
fieldItem.isHideDimension=fieldItem.isHideDimension.split(',')
|
||||
}
|
||||
fieldList.push(fieldItem)
|
||||
})
|
||||
|
||||
@@ -282,7 +285,9 @@ onMounted(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
tableInfoOption.infoColumn.fieldColumn.isHideDimension.editRender.dicData = infoData.value.basics.map(({fieldCode,fieldName})=>{
|
||||
return {label:fieldName,value:fieldCode}
|
||||
})
|
||||
// 设置父字段下拉选项
|
||||
const updateParentFieldOptions = () => {
|
||||
// 获取所有parentFieldCode为空的字段作为可选父字段
|
||||
|
||||
@@ -160,6 +160,7 @@ const infoColumn = {
|
||||
isAmount: { title: '是否合计', width: 75, align: "center", editRender: { name: 'LowCheckboxSum' } },
|
||||
isDimension: { title: '是否维度', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||
|
||||
isHideDimension: { title: '维度隐藏列', width: 180, editRender: { name: 'LowSelectMultiple', verifyEdit: true, filterable: true, multiple:true,dicData: [] } },
|
||||
isShowSort: { title: '是否排序', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||
hasChildren: { title: '子字段', width: 90, align: "center", editRender: { name: 'LowButton', disabled: (row) => row.isSubField === true, buttonText: '添加子字段', buttonType: 'primary', buttonSize: 'small' } },
|
||||
},
|
||||
@@ -187,7 +188,7 @@ for (const key in infoColumn) {
|
||||
//默认值
|
||||
const infoDefaultData = {
|
||||
basics: {
|
||||
fieldCode: '', fieldName: '', parentFieldName: '', labelI18n: '', fieldType: 'String', queryIsDb: 'N', queryIsWeb: 'N', queryMode: 'LIKE', dictCode: '', isExport: 'Y', isShowSort: 'N', isAmount: '', isDimension: '', hasChildren: 'N', isSubField: false, parentFieldId: '', parentFieldCode: '',
|
||||
fieldCode: '', fieldName: '', parentFieldName: '', labelI18n: '', fieldType: 'String', queryIsDb: 'N', queryIsWeb: 'N', queryMode: 'LIKE', dictCode: '', isExport: 'Y', isShowSort: 'N', isAmount: '', isDimension: '',isHideDimension:'', hasChildren: 'N', isSubField: false, parentFieldId: '', parentFieldCode: '',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ const tableFormVerify = (type) => {
|
||||
const index = Number(i)
|
||||
const item = filedData[index]
|
||||
item.sortNum = index + 1
|
||||
|
||||
item.isHideDimension?item.isHideDimension=item.isHideDimension.join(','):''
|
||||
let messageText = ''
|
||||
let tabKey = 'mysql'
|
||||
// 子字段不能再包含子字段
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
<template>
|
||||
<DesignPopup v-model="dialogVisible" title="应用权限" :is-footer="true" width="40%">
|
||||
<div class="p-20px">
|
||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
|
||||
<el-form-item label="角色名称">
|
||||
<el-tag>{{ formData.name }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色标识">
|
||||
<el-tag>{{ formData.code }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="应用权限">
|
||||
<el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
|
||||
<template #header>
|
||||
全选/全不选:
|
||||
<el-switch
|
||||
v-model="treeNodeAll"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
inline-prompt
|
||||
@change="handleCheckedTreeNodeAll"
|
||||
/>
|
||||
</template>
|
||||
<!-- 修复:移除未使用的node变量,优化无子集Tree展示 -->
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
:data="appOptions"
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
empty-text="暂无应用数据"
|
||||
node-key="id"
|
||||
show-checkbox
|
||||
check-strictly
|
||||
v-loading="tableLoading"
|
||||
class="app-tree-list"
|
||||
:indent="0"
|
||||
>
|
||||
<!-- 修复:只解构使用到的data,删除未使用的node -->
|
||||
<template #default="{ data }">
|
||||
<div class="app-tree-node">
|
||||
<span class="node-name">{{ data.name }}</span>
|
||||
<span class="node-clientId">客户端ID:{{ data.clientId }}</span>
|
||||
<span class="node-status">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="data.status" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</DesignPopup>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import * as RoleApi from '@/api/system/role'
|
||||
|
||||
defineOptions({ name: 'SystemRoleAssignAppForm' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const formLoading = ref(false)
|
||||
const tableLoading = ref(false)
|
||||
const formData = ref({
|
||||
id: 0,
|
||||
name: '',
|
||||
code: '',
|
||||
clientIds: [] as number[]
|
||||
})
|
||||
const formRef = ref()
|
||||
const treeRef = ref()
|
||||
const appOptions = ref<any[]>([])
|
||||
const treeNodeAll = ref(false)
|
||||
|
||||
// 优化Tree配置:明确指定无children,纯列表展示
|
||||
const treeProps = {
|
||||
label: 'name',
|
||||
children: () => [] // 强制返回空数组,彻底避免树形层级
|
||||
}
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (row: RoleApi.RoleVO) => {
|
||||
dialogVisible.value = true
|
||||
formLoading.value = true
|
||||
resetForm()
|
||||
// 设置角色信息
|
||||
formData.value.id = row.id
|
||||
formData.value.name = row.name
|
||||
formData.value.code = row.code
|
||||
try {
|
||||
// 加载应用列表(pageSize=99,模拟不分页)
|
||||
await getAppList()
|
||||
// 获取当前角色已有的应用ID
|
||||
const roleAppIds = await RoleApi.getRoleAppIds(row.id)
|
||||
formData.value.clientIds = roleAppIds
|
||||
// 设置Tree选中状态
|
||||
await nextTick()
|
||||
treeRef.value?.setCheckedNodes([])
|
||||
formData.value.clientIds.forEach(id => {
|
||||
treeRef.value?.setChecked(id, true, false)
|
||||
})
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
defineExpose({ open })
|
||||
|
||||
/** 获取应用列表(固定pageSize=99,不分页) */
|
||||
const getAppList = async () => {
|
||||
tableLoading.value = true
|
||||
try {
|
||||
const data = await RoleApi.getMyPage({
|
||||
pageNo: 1,
|
||||
pageSize: 99 // 设为99,覆盖大部分场景的数量,模拟不分页
|
||||
})
|
||||
// 优化:确保返回数据绝对没有children字段,避免树形展示
|
||||
appOptions.value = data.list.map(item => {
|
||||
const { children, ...rest } = item // 移除可能存在的children字段
|
||||
return { ...rest, children: [] } // 强制设置空children
|
||||
})
|
||||
} finally {
|
||||
tableLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 全选/全不选(适配Tree组件) */
|
||||
const handleCheckedTreeNodeAll = () => {
|
||||
if (treeNodeAll.value) {
|
||||
// 全选:选中所有节点
|
||||
treeRef.value?.setCheckedNodes(appOptions.value)
|
||||
formData.value.clientIds = appOptions.value.map(item => item.id)
|
||||
} else {
|
||||
// 全不选:清空选中
|
||||
treeRef.value?.setCheckedNodes([])
|
||||
formData.value.clientIds = []
|
||||
}
|
||||
}
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success'])
|
||||
const submitForm = async () => {
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
formLoading.value = true
|
||||
try {
|
||||
// 获取Tree选中的节点ID
|
||||
formData.value.clientIds = treeRef.value?.getCheckedKeys(false) as number[]
|
||||
const data = {
|
||||
roleId: formData.value.id,
|
||||
clientIds: formData.value.clientIds
|
||||
}
|
||||
await RoleApi.saveApp(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
treeNodeAll.value = false
|
||||
formData.value = {
|
||||
id: 0,
|
||||
name: '',
|
||||
code: '',
|
||||
clientIds: []
|
||||
}
|
||||
appOptions.value = []
|
||||
treeRef.value?.setCheckedNodes([])
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 自定义Tree节点样式,模拟表格列布局
|
||||
.app-tree-list {
|
||||
::v-deep(.el-tree-node) {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
}
|
||||
|
||||
::v-deep(.el-tree-node__content) {
|
||||
padding: 0 10px;
|
||||
height: 40px !important;
|
||||
// 移除树形节点的默认图标
|
||||
.el-tree-node__expand-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-tree-node__children) {
|
||||
padding-left: 0 !important; // 彻底去掉子节点缩进
|
||||
}
|
||||
}
|
||||
|
||||
// 节点内容布局
|
||||
.app-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
.node-name {
|
||||
flex: 0 0 120px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.node-clientId {
|
||||
flex: 0 0 150px;
|
||||
color: #666;
|
||||
}
|
||||
.node-status {
|
||||
flex: 0 0 80px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// 卡片样式优化
|
||||
::v-deep(.el-card__header) {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
::v-deep(.el-card__body) {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -58,15 +58,6 @@
|
||||
<span>菜单权限</span>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:command="{ type: 'app', row }"
|
||||
v-if="checkPermi(['system:permission:assign-role-app'])"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<Icon icon="ep:menu" />
|
||||
<span>应用权限</span>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:command="{ type: 'data', row }"
|
||||
v-if="checkPermi(['system:permission:assign-role-data-scope'])"
|
||||
@@ -95,8 +86,6 @@
|
||||
<RoleAssignMenuForm ref="assignMenuFormRef" @success="getTableData" />
|
||||
<!-- 表单弹窗:数据权限 -->
|
||||
<RoleDataPermissionForm ref="dataPermissionFormRef" @success="getTableData" />
|
||||
<!-- 表单弹窗:应用权限 -->
|
||||
<RoleAssignAppForm ref="assignAppFormRef" @success="getTableData" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
@@ -107,7 +96,6 @@ import * as RoleApi from '@/api/system/role'
|
||||
import { CommonStatusEnum } from '@/utils/constants'
|
||||
import RoleAssignMenuForm from './RoleAssignMenuForm.vue'
|
||||
import RoleDataPermissionForm from './RoleDataPermissionForm.vue'
|
||||
import RoleAssignAppForm from './RoleAssignAppForm.vue'
|
||||
|
||||
defineOptions({ name: 'SystemRole' })
|
||||
|
||||
@@ -198,7 +186,7 @@ const tablePage = ref({
|
||||
total: 0
|
||||
})
|
||||
const permission = getCurrPermi(['system:role'])
|
||||
const assignAppFormRef = ref()
|
||||
|
||||
const crudRef = ref()
|
||||
|
||||
useCrudHeight(crudRef)
|
||||
@@ -209,11 +197,6 @@ const menuHandle = ({ row, type }) => {
|
||||
if (type == 'menu') openAssignMenuForm(row)
|
||||
else if (type == 'data') openDataPermissionForm(row)
|
||||
else if (type == 'del') rowDel(row)
|
||||
else if (type == 'app') openAssignAppForm(row)
|
||||
}
|
||||
|
||||
const openAssignAppForm = (row) => {
|
||||
assignAppFormRef.value.open(row)
|
||||
}
|
||||
|
||||
/** 查询列表 */
|
||||
|
||||
Reference in New Issue
Block a user