初始版本提交

This commit is contained in:
yaoyn
2024-02-05 09:15:37 +08:00
parent b52d4414be
commit 445292105f
1848 changed files with 236859 additions and 75 deletions

View File

@ -0,0 +1,614 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
:title="getTitle"
width="50%"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
<BasicTable @register="registerTable" v-if="isCustom == 1" class="dataAuthDrag !mb-5">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> {{ t('添加过滤条件') }} </a-button>
</template>
<template #bodyCell="{ column, text, record }">
<template
v-if="
['drag', 'fieldName', 'fieldType', 'fieldValue', 'conditionType'].includes(
column.dataIndex,
)
"
>
<div>
<Icon class="mover" icon="ant-design:drag-outlined" v-if="column.dataIndex == 'drag'" />
<a-select
class="w-full"
:placeholder="t('请选择')"
v-else-if="column.dataIndex == 'conditionType'"
v-model:value="record[column.dataIndex]"
>
<a-select-option :value="0">{{ t('等于') }}</a-select-option>
<a-select-option :value="1">{{ t('大于') }}</a-select-option>
<a-select-option :value="2">{{ t('大于等于') }}</a-select-option>
<a-select-option :value="3">{{ t('小于') }}</a-select-option>
<a-select-option :value="4">{{ t('小于等于') }}</a-select-option>
<a-select-option :value="5">{{ t('包含') }}</a-select-option>
<a-select-option :value="6">{{ t('包含于') }}</a-select-option>
<a-select-option :value="7">{{ t('不等于') }}</a-select-option>
<a-select-option :value="8">{{ t('不包含') }}</a-select-option>
<a-select-option :value="9">{{ t('不包含于') }}</a-select-option>
</a-select>
<a-input
v-if="column.dataIndex == 'fieldName'"
v-model:value="record[column.dataIndex]"
:placeholder="t('请填写字段名')"
/>
<a-select
class="w-full"
:placeholder="t('请选择字段类型')"
v-else-if="column.dataIndex == 'fieldType'"
v-model:value="record[column.dataIndex]"
@change="(_, option) => changeFieldType(record, option)"
>
<a-select-option :value="0">{{ t('文本(String)') }}</a-select-option>
<a-select-option :value="1">{{ t('文本(Int)') }}</a-select-option>
<a-select-option :value="2" :label="t('登录人ID')">{{
t('登录人ID')
}}</a-select-option>
<a-select-option :value="3" :label="t('登录人组织架构')">{{
t('登录人组织架构')
}}</a-select-option>
<a-select-option :value="4" :label="t('登录人所属组织架构及下属组织架构')">{{
t('登录人所属组织架构及下属组织架构')
}}</a-select-option>
<a-select-option :value="5" :label="t('登录人账号')">{{
t('登录人账号')
}}</a-select-option>
<a-select-option :value="6" :label="t('登录人岗位')">{{
t('登录人岗位')
}}</a-select-option>
<a-select-option :value="7" :label="t('登录人角色')">{{
t('登录人角色')
}}</a-select-option>
</a-select>
<a-input
v-else-if="column.dataIndex == 'fieldValue'"
v-model:value="record[column.dataIndex]"
:placeholder="
record['fieldType'] === undefined ? t('请先选择字段类型') : t('请填写字段值')
"
:disabled="record['fieldType'] > 1"
:readonly="record['fieldType'] === undefined"
/>
</div>
</template>
<template v-else-if="column.dataIndex == 'action'">
<TableAction
:actions="[
{
icon: 'ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除'),
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
<template v-else> {{ text }} </template>
</template>
</BasicTable>
<a-form
:model="formState"
name="basic"
autocomplete="off"
:label-col="{ style: { width: '100px' } }"
>
<a-form-item name="authFormula" v-if="isCustom == 1">
<template #label>
<Tooltip color="rgba(0,0,0,0.9)" :overlayStyle="{ maxWidth: '448px' }">
<template #title>
<div class="tipdiv">
<p>{{ t('请按如下规则编辑条件组合') }}</p>
<p
>{{ t('正确示例: (1 and 2) or (3 and 4)') }}
<Icon icon="ant-design:check-circle-outlined" color="green"
/></p>
<p>{{ t('1.有and和or必须加括号') }}</p>
<p class="text-[pink]"
>{{ t('错误示例:1 and 2 or 3 and 4') }}
<Icon icon="ant-design:close-circle-outlined" color="pink"
/></p>
<p>{{ t('2.一个括号里不能同时出现and和or') }}</p>
<p class="text-[pink]"
>{{ t('错误示例: (1 and 2 or 3 )and 4') }}
<Icon icon="ant-design:close-circle-outlined" color="pink" />
</p>
<p>{{ t('3.不允许出现不存在的编号') }}</p>
<p class="text-[pink]"
>{{ t('错误示例: 1 and 2 and 3 and 4 and 5') }}
<Icon icon="ant-design:close-circle-outlined" color="pink"
/></p>
<p>{{ t('4.括号都是成对出现的') }}</p>
<p class="text-[pink]"
>{{ t('错误示例: (1 and 2 and 3 and 4') }}
<Icon icon="ant-design:close-circle-outlined" color="pink"
/></p>
</div>
</template>
<Icon icon="ant-design:question-circle-twotone" />
</Tooltip>
{{ t('组合公式') }}
</template>
<a-textarea
v-model:value="formState.authFormula"
:placeholder="
t(
'请填写组合公式,组合公式非必填如果不填写则按照已有条件并列执行例如1 and 2 and 3 and 4,填写后,按照填写的公式进行执行',
)
"
/>
</a-form-item>
<a-form-item :label="t('备注')" name="remark">
<a-textarea v-model:value="formState.remark" :placeholder="t('请输入备注')" />
</a-form-item>
</a-form>
</BasicDrawer>
</template>
<script lang="ts">
import { defineComponent, ref, computed, unref, reactive, h, watch, nextTick } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicTable, useTable, TableAction, BasicColumn } from '/@/components/Table';
import { Tooltip } from 'ant-design-vue';
import { useMessage } from '/@/hooks/web/useMessage';
// import { useI18n } from 'vue-i18n';
import Sortable from 'sortablejs';
import { getRoleAllList } from '/@/api/system/role';
import SelectUser from '/@/components/Form/src/components/SelectUser.vue';
import { Icon } from '/@/components/Icon';
import { isNullAndUnDef } from '/@/utils/is';
import { addAuth, updateAuth } from '/@/api/system/authorize';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
export const formSchema: FormSchema[] = [
{
field: 'code',
label: t('权限编码'),
component: 'Input',
required: true,
colProps: { lg: 24, md: 24 },
},
{
field: 'name',
label: t('名称'),
component: 'Input',
required: true,
colProps: { lg: 24, md: 24 },
},
{
field: 'authType',
label: t('对象类型'),
component: 'Select',
required: true,
defaultValue: 0,
colProps: { lg: 24, md: 24 },
componentProps: {
options: [
{
label: t('角色'),
value: 0,
},
{
label: t('用户'),
value: 1,
},
],
},
},
{
field: 'objectIdList',
label: t('授权对象'),
component: 'Input',
required: true,
colProps: { lg: 24, md: 24 },
render: ({ model, field }) => {
return h(SelectUser, {
placeholder: t('请选择授权对象'),
value: model[field],
suffix: 'ant-design:ellipsis-outlined',
onSelectedId: (v) => {
model[field] = v;
},
});
},
ifShow: ({ values }) => {
return values.authType == 1;
},
},
{
field: 'objectId',
label: t('授权对象'),
component: 'Select',
required: true,
colProps: { lg: 24, md: 24 },
componentProps: {
options: [],
'filter-option': null,
mode: 'multiple',
'show-search': true,
fieldNames: {
label: 'name',
value: 'id',
},
},
ifShow: ({ values }) => {
return values.authType != 1;
},
},
{
field: 'authMethod',
label: t('授权方式'),
component: 'Select',
defaultValue: 0,
required: true,
componentProps: {
options: [
{
label: t('简易模式'),
value: 0,
},
{
label: t('自定义配置'),
value: 1,
},
],
onChange: (v) => {
isCustom.value = v;
},
},
colProps: { lg: 24, md: 24 },
},
{
field: 'authScope',
label: t('实现范围'),
component: 'Select',
required: true,
componentProps: {
options: [
{
label: t('仅查看登录人数据'),
value: 0,
},
{
label: t('仅查看登录人同岗位数据'),
value: 1,
},
{
label: t('仅查看登录人及所有下属岗位数据'),
value: 2,
},
{
label: t('仅查看登录人同岗位及所有下属岗位数据'),
value: 3,
},
{
label: t('仅查看登录人同组织架构人员数据'),
value: 4,
},
{
label: t('仅查看登录人及所有下属组织架构人员数据'),
value: 5,
},
{
label: t('仅查看登录人同组织架构人员及所有下属组织架构人员数据'),
value: 6,
},
{
label: t('仅查看登录人同角色数据'),
value: 7,
},
],
},
colProps: { lg: 24, md: 24 },
ifShow: ({ values }) => {
return values.authMethod === 0;
},
},
];
export const columns: BasicColumn[] = [
{
title: '',
dataIndex: 'drag',
width: 50,
},
{
title: t('序号'),
dataIndex: 'orderNumber',
width: 50,
},
{
title: t('字段名'),
dataIndex: 'fieldName',
width: 100,
},
{
title: t('条件'),
dataIndex: 'conditionType',
width: 100,
},
{
title: t('字段类型'),
dataIndex: 'fieldType',
width: 200,
},
{
title: t('字段值'),
dataIndex: 'fieldValue',
width: 180,
},
];
interface FormState {
authFormula: string;
remark: string;
}
interface DataItem {
key?: string;
orderNumber: number;
fieldName: string;
conditionType: number;
fieldType?: number;
fieldValue: string;
}
const isCustom = ref<number>(0);
const editableData = ref<DataItem[]>([]);
const selectUser = ref<boolean>(false);
export default defineComponent({
name: 'MenuDrawer',
components: {
BasicDrawer,
BasicForm,
TableAction,
BasicTable,
Tooltip,
Icon,
},
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const { notification } = useMessage();
const rowId = ref('');
const formState = reactive<FormState>({
authFormula: '',
remark: '',
});
watch(
() => editableData.value,
(val) => {
if (val && val.length) {
nextTick(() => {
const tbody: any = document.querySelector('.dataAuthDrag .ant-table-tbody');
const tr: any = tbody.querySelector('tr.ant-table-row[draggable="false"]');
if (tr) tr.remove();
Sortable.create(tbody, {
handle: '.mover',
onEnd: (evt) => {
const { oldIndex, newIndex } = evt;
if (
isNullAndUnDef(oldIndex) ||
isNullAndUnDef(newIndex) ||
oldIndex === newIndex
) {
return;
}
let columns: DataItem[] = getDataSource();
setTableData([]);
editableData.value = [];
nextTick(() => {
let old = columns[oldIndex - 1];
columns.splice(oldIndex - 1, 1);
columns.splice(newIndex - 1, 0, old);
columns.forEach((o, i) => {
o.orderNumber = i + 1;
});
editableData.value = columns;
setTableData(editableData.value);
});
},
});
});
}
},
{
deep: true,
},
);
watch(isCustom, (val) => {
if (val === 1) {
//首次进入清除自定义表格内容
nextTick(() => {
setTableData(editableData.value);
});
}
});
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 12, md: 24 },
});
const [registerTable, { getDataSource, setTableData }] = useTable({
title: '',
dataSource: editableData.value,
columns,
pagination: false,
striped: false,
useSearchForm: false,
bordered: true,
showIndexColumn: false,
canResize: false,
rowKey: 'id',
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
editableData.value = [];
const treeData = await getRoleAllList();
const filterOption = (input: string, option: any) => {
return option.name.indexOf(input) >= 0;
};
updateSchema({
field: 'objectId',
componentProps: { options: treeData, 'filter-option': filterOption },
});
if (unref(isUpdate)) {
rowId.value = data.record.id;
let arrData: string[] = [];
data.record.authObjectList.forEach((o) => {
arrData.push(o.objectId);
});
if (data.record.authType == 1) {
data.record.objectIdList = arrData.join(',');
} else {
data.record.objectId = arrData;
}
setFieldsValue({
...data.record,
});
isCustom.value = data.record.authMethod;
formState.remark = data.record.remark;
if (isCustom.value == 1) {
formState.authFormula = data.record.authFormula;
editableData.value = data.record.authConfigList;
nextTick(() => {
setTableData(editableData.value);
});
}
} else {
isCustom.value = 0;
}
});
function handleCreate() {
let dataSource: DataItem[] = getDataSource();
let obj = {
orderNumber: dataSource.length + 1,
fieldName: '',
conditionType: 0,
fieldValue: '',
};
dataSource.push(obj);
editableData.value = dataSource;
setTableData(dataSource);
}
function changeFieldType(record: Recordable, option) {
record.fieldValue = record.fieldType > 1 ? option.label : '';
}
function handleDelete(record: Recordable) {
const dataSource: DataItem[] = getDataSource();
editableData.value = [];
dataSource.forEach((o) => {
if (o.orderNumber < record.orderNumber) {
editableData.value.push(o);
} else if (o.orderNumber > record.orderNumber) {
o.orderNumber -= 1;
editableData.value.push(o);
}
});
setTableData(editableData.value);
}
const getTitle = computed(() => (!unref(isUpdate) ? t('新增数据权限') : t('编辑数据权限')));
async function handleSubmit() {
try {
const values = await validate();
if (values.authType == 1) {
values.objectIdList = values.objectIdList.split(',');
} else {
values.objectIdList = values.objectId;
}
if (values.authMethod == 1) {
values.authConfigList = getDataSource();
Object.assign(values, formState);
} else {
values.remark = formState.remark;
}
setDrawerProps({ confirmLoading: true });
// TODO custom api
if (!unref(isUpdate)) {
//false 新增
await addAuth(values);
notification.success({
message: t('提示'),
description: t('新增成功'),
}); //提示消息
} else {
values.id = rowId.value;
await updateAuth(values);
notification.success({
message: t('提示'),
description: t('编辑成功'),
}); //提示消息
}
closeDrawer();
emit('success');
} catch (error) {
setDrawerProps({ confirmLoading: false });
}
}
return {
registerDrawer,
registerForm,
editableData,
formState,
getTitle,
isCustom,
selectUser,
handleSubmit,
registerTable,
handleCreate,
changeFieldType,
handleDelete,
t,
};
},
});
</script>
<style scoped>
.tipdiv p {
margin: 0;
}
</style>

View File

@ -0,0 +1,34 @@
<template>
<BasicModal
width="1000px"
v-bind="$attrs"
@register="registerModal"
:show-cancel-btn="false"
:show-ok-btn="false"
>
<div class="flex flex-wrap" v-if="datas.length > 0">
<UserCard v-for="(item, index) in datas" :key="index" :item="item" />
</div>
<div v-else><a-empty :image="simpleImage" /></div>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import UserCard from '/@/components/SelectOrganizational/src/card/UserCard.vue';
import { Empty } from 'ant-design-vue';
export default defineComponent({
name: 'AuthModal',
components: { BasicModal, UserCard },
emits: ['success', 'register'],
setup(_) {
const datas = ref<any>([]);
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
datas.value = data;
});
return { registerModal, datas, simpleImage: Empty.PRESENTED_IMAGE_SIMPLE };
},
});
</script>