Merge remote-tracking branch 'origin/master'

This commit is contained in:
ahhui
2023-08-04 18:26:50 +08:00
8 changed files with 666 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
import { request } from '/@/utils/service';
import { PageQuery } from './types'
export function getRoleList(query: PageQuery) {
return request({
url: '/api/system/role/',
method: 'get',
params: query,
});
}
export function getModelList() {
return request({
url: '/api/system/column/get_models/',
method: 'get',
});
}

View File

@@ -0,0 +1,115 @@
<template>
<div class="columns-form-com">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
<el-form-item label="字段名" prop="field_name">
<el-input v-model="formData.field_name" placeholder="请输入字段名" />
</el-form-item>
<el-form-item label="列名" prop="title">
<el-input v-model="formData.title" placeholder="请输入列名" />
</el-form-item>
<el-form-item label="创建显示">
<el-switch v-model="formData.is_create" />
</el-form-item>
<el-form-item label="编辑显示">
<el-switch v-model="formData.is_update" />
</el-form-item>
<el-form-item label="查询显示">
<el-switch v-model="formData.is_query" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit" :loading="btnLoading"> 确定 </el-button>
<el-button @click="handleClose">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted } from 'vue';
import { addColumnsData, updateColumnsData } from '../ColumnsTableCom/api';
import { successNotification } from '/@/utils/message';
import { CurrentInfoType, ColumnsFormDataType } from '../../types';
import type { FormInstance } from 'element-plus';
const props = defineProps({
currentInfo: {
type: Object as () => CurrentInfoType,
required: true,
default: () => {},
},
initFormData: {
type: Object as () => Partial<ColumnsFormDataType>,
default: () => {},
},
});
const emit = defineEmits(['drawerClose']);
const formRef = ref<FormInstance>();
const formRules = reactive({
field_name: [{ required: true, message: '请输入字段名!', trigger: 'blur' }],
title: [{ required: true, message: '请输入列名!', trigger: 'blur' }],
});
let formData = reactive<ColumnsFormDataType>({
field_name: '',
title: '',
is_create: true,
is_update: true,
is_query: true,
});
let btnLoading = ref(false);
const setMenuFormData = () => {
if (props.initFormData?.id) {
formData.id = props.initFormData?.id || '';
formData.field_name = props.initFormData.field_name || '';
formData.title = props.initFormData.title || '';
formData.is_create = !!props.initFormData.is_create;
formData.is_update = !!props.initFormData.is_update;
formData.is_query = !!props.initFormData.is_query;
}
};
const handleSubmit = () => {
formRef.value?.validate(async (valid) => {
if (!valid) return;
try {
btnLoading.value = true;
let res;
if (formData.id) {
res = await updateColumnsData({ ...formData, ...props.currentInfo });
} else {
res = await addColumnsData({ ...formData, ...props.currentInfo });
}
if (res?.code === 2000) {
successNotification(res.msg as string);
handleClose('submit');
}
} finally {
btnLoading.value = false;
}
});
};
const handleClose = (type: string = '') => {
emit('drawerClose', type);
formRef.value?.resetFields();
};
onMounted(() => {
setMenuFormData();
});
</script>
<style lang="scss" scoped>
.columns-form-com {
height: 100%;
padding: 20px;
box-sizing: border-box;
}
</style>

View File

@@ -0,0 +1,41 @@
import { request } from '/@/utils/service';
import { CurrentInfoType, AddColumnsDataType } from '../../types'
export function getColumnsData(query: any) {
return request({
url: '/api/system/column/',
method: 'get',
params: query,
});
}
export function automatchColumnsData(data: CurrentInfoType) {
return request({
url: '/api/system/column/auto_match_fields/',
method: 'post',
data,
});
}
export function addColumnsData(data: AddColumnsDataType) {
return request({
url: '/api/system/column/',
method: 'post',
data
});
}
export function deleteColumnsData(id: number) {
return request({
url: `/api/system/column/${id}/`,
method: 'delete',
});
}
export function updateColumnsData(data: AddColumnsDataType) {
return request({
url: `/api/system/column/${data.id}/`,
method: 'put',
data
});
}

View File

@@ -0,0 +1,192 @@
<template>
<div class="columns-table-com">
<p class="ctc-title">字段权限</p>
<div class="ctc-head">
<el-button type="primary" @click="handleUpdateColumn('create')">新增</el-button>
<el-button type="primary" @click="handleAutomatch">自动匹配</el-button>
</div>
<el-table :data="state.data" border v-loading="state.loading" class="ctc-table">
<el-table-column prop="field_name" label="字段名" />
<el-table-column prop="title" label="列名" />
<el-table-column prop="is_create" label="创建显示">
<template #default="scope">
<el-switch v-model="scope.row.is_create" @change="handleChange(scope.row)" />
</template>
</el-table-column>
<el-table-column prop="is_update" label="编辑显示">
<template #default="scope">
<el-switch v-model="scope.row.is_update" @change="handleChange(scope.row)" />
</template>
</el-table-column>
<el-table-column prop="is_query" label="查询显示">
<template #default="scope">
<el-switch v-model="scope.row.is_query" @change="handleChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template #default="scope">
<el-button type="primary" @click="handleUpdateColumn('update', scope.row)">编辑</el-button>
<el-button type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="ctc-pagination">
<el-pagination
v-model:current-page="searchParams.page"
v-model:page-size="searchParams.limit"
:page-sizes="[5, 10, 20, 50]"
:total="state.total"
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<el-drawer v-model="drawerVisible" title="字段权限" direction="rtl" size="500px" :close-on-click-modal="false" :before-close="handleDrawerClose">
<ColumnsFormCom v-if="drawerVisible" :currentInfo="props.currentInfo" :initFormData="drawerFormData" @drawerClose="handleDrawerClose" />
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import { ElMessageBox } from 'element-plus';
import ColumnsFormCom from '../ColumnsFormCom/index.vue';
import { getColumnsData, automatchColumnsData, deleteColumnsData, updateColumnsData } from './api';
import { successNotification, warningNotification } from '/@/utils/message';
import { CurrentInfoType, ColumnsFormDataType, AddColumnsDataType } from '../../types';
const props = defineProps({
currentInfo: {
type: Object as () => CurrentInfoType,
required: true,
default: () => {},
},
});
let searchParams = reactive({
page: 1,
limit: 20,
});
let state = reactive({
loading: false,
data: [],
total: 0,
});
let drawerVisible = ref(false);
let drawerFormData = ref<Partial<ColumnsFormDataType>>({});
const fetchData = async (query: CurrentInfoType = props.currentInfo) => {
try {
state.loading = true;
const res = await getColumnsData({ ...searchParams, ...query });
if (res?.code === 2000) {
state.data = res.data;
state.total = res.total;
}
} finally {
state.loading = false;
}
};
/**
* 自动匹配列
*/
const handleAutomatch = async () => {
if (props.currentInfo?.role && props.currentInfo?.model && props.currentInfo?.app) {
const res = await automatchColumnsData(props.currentInfo);
if (res?.code === 2000) {
successNotification('匹配成功');
fetchData();
}
return;
}
warningNotification('请选择角色和模型表!');
};
/**
* 新增 or 编辑
*/
const handleUpdateColumn = (type: string, record?: ColumnsFormDataType) => {
if (props.currentInfo?.role && props.currentInfo?.model && props.currentInfo?.app) {
if (type === 'update' && record) {
drawerFormData.value = record;
}
drawerVisible.value = true;
return;
}
warningNotification('请选择角色和模型表!');
};
const handleDrawerClose = (type?: string) => {
if (type === 'submit') {
fetchData();
}
drawerVisible.value = false;
drawerFormData.value = {};
};
/**
* 删除 deleteColumnsData
*/
const handleDelete = ({ id }: { id: number }) => {
ElMessageBox.confirm('确定删除该字段吗?', '提示', {
type: 'error',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
.then(async () => {
const res = await deleteColumnsData(id);
if (res?.code === 2000) {
successNotification('删除成功');
fetchData();
}
})
.catch(() => {});
};
const handleChange = (record: AddColumnsDataType) => {
updateColumnsData(record);
};
/**
* 分页
*/
const handleSizeChange = (limit: number) => {
searchParams.limit = limit;
fetchData();
};
const handleCurrentChange = (page: number) => {
searchParams.page = page;
fetchData();
};
defineExpose({ fetchData });
</script>
<style lang="scss" scoped>
.columns-table-com {
height: 100%;
.ctc-title {
font-size: 16px;
font-weight: 900;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
}
.ctc-head {
height: 35px;
margin-top: 10px;
}
.ctc-table {
width: 100%;
height: calc(100% - 135px);
margin: 10px 0;
}
.ctc-pagination {
height: 35px;
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<div class="item-com">
<p class="item-com-title">{{ props.title }}</p>
<ul class="item-com-list" :style="{ height: showPagination ? 'calc(100% - 75px)' : 'calc(100% - 45px)' }">
<li
v-for="item in state.data"
:key="item[props.value]"
@click="handleClick(item)"
:class="state.current === item[props.value] ? 'item-com-item active' : 'item-com-item'"
>
{{ item[props.label] }}
</li>
</ul>
<div v-if="showPagination" class="item-com-pagination">
<el-pagination
background
small
hide-on-single-page
v-model:current-page="state.page"
v-model:page-size="state.limit"
layout="prev, pager, next"
:pager-count="5"
:total="state.total"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, onMounted } from 'vue';
import { RoleInfoStateType } from './types';
const props = defineProps({
type: {
type: String,
default: 'role',
},
title: {
type: String,
default: '标题',
},
label: {
type: String,
default: 'name',
},
value: {
type: String,
default: 'id',
},
showPagination: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['fetchData', 'itemClick']);
const state = reactive<RoleInfoStateType>({
current: '',
page: 1,
limit: 20,
data: [],
total: 10,
});
const fetchData = () => {
emit(
'fetchData',
{
page: state.page,
limit: state.limit,
},
(res: { code: number; data: any[]; total: number }) => {
if (res?.code === 2000) {
state.data = res.data;
state.total = res?.total || 10;
}
}
);
};
const handleClick = (record: any) => {
state.current = record[props.value];
emit('itemClick', props.type, record);
};
const handleCurrentChange = (page: number) => {
state.page = page;
fetchData();
};
onMounted(() => {
fetchData();
});
</script>
<style lang="scss" scoped>
.item-com {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.item-com-title {
font-size: 16px;
font-weight: 900;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
}
.item-com-list {
width: 100%;
white-space: nowrap;
overflow: auto;
.item-com-item {
padding: 10px 16px;
border-radius: 8px;
cursor: pointer;
transition: all 500ms;
}
.active {
color: var(--el-color-primary);
background-color: var(--el-color-primary-light-8);
transition: all 500ms;
}
.item-com-item:hover {
color: var(--el-color-primary);
transition: all 500ms;
}
}
.item-com-pagination {
width: 100%;
height: 25px;
position: absolute;
bottom: 0;
}
}
</style>

View File

@@ -0,0 +1,29 @@
export interface PageQuery {
page: number;
limit: number;
}
export interface RoleItemType {
id: number | string;
modifier_name: string;
creator_name: string;
create_datetime: string;
update_datetime: string;
description: string;
modifier: string;
dept_belong_id: number | string | null,
name: string;
key: string;
sort: number;
status: boolean;
admin: boolean;
creator: string;
}
export interface RoleInfoStateType {
current: string;
page: number;
limit: number;
data: any[],
total: number;
}

View File

@@ -0,0 +1,99 @@
<template>
<fs-page class="columns">
<el-row class="columns-el-row">
<el-col :span="4">
<div class="columns-box columns-left">
<ItemCom title="角色" type="role" showPagination @fetchData="fetchRoleData" @itemClick="handleClick" />
</div>
</el-col>
<el-col :span="6">
<div class="columns-box columns-center">
<ItemCom title="模型表" type="model" label="showText" value="key" @fetchData="fetchModelData" @itemClick="handleClick" />
</div>
</el-col>
<el-col :span="14">
<div class="columns-box columns-right">
<ColumnsTableCom ref="columnsTableRef" :currentInfo="currentInfo" />
</div>
</el-col>
</el-row>
</fs-page>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import ItemCom from './components/ItemCom/index.vue';
import ColumnsTableCom from './components/ColumnsTableCom/index.vue';
import { getRoleList, getModelList } from './api';
import { PageQuery, CurrentInfoType, ModelItemType } from './types';
const columnsTableRef = ref<InstanceType<typeof ColumnsTableCom> | null>(null);
let currentInfo = reactive<CurrentInfoType>({
role: '',
model: '',
app: '',
});
const fetchRoleData = async (query: PageQuery, callback: Function) => {
const res = await getRoleList(query);
callback(res);
};
const fetchModelData = async (query: PageQuery, callback: Function) => {
const res = await getModelList();
res.data.forEach((item: ModelItemType) => {
item.showText = `${item.app}-${item.title}(${item.key})`;
});
callback(res);
};
const fetchTableData = () => {
if (currentInfo.role && currentInfo.model && currentInfo.app) {
columnsTableRef.value?.fetchData(currentInfo);
return;
}
};
const handleClick = (type: string, record: any) => {
if (type === 'role') {
currentInfo.role = record.id;
}
if (type === 'model') {
currentInfo.model = record.key;
currentInfo.app = record.app;
}
fetchTableData();
};
</script>
<style lang="scss" scoped>
.columns {
.columns-el-row {
height: 100%;
overflow: hidden;
.el-col {
height: 100%;
padding: 10px 0;
box-sizing: border-box;
}
}
.columns-box {
height: 100%;
padding: 10px;
background-color: #fff;
box-sizing: border-box;
}
.columns-left {
border-radius: 0 8px 8px 0;
}
.columns-center {
margin: 0 10px;
border-radius: 8px;
}
.columns-right {
position: relative;
border-radius: 8px 0 0 8px;
}
}
</style>

View File

@@ -0,0 +1,35 @@
export interface PageQuery {
page: number;
limit: number;
}
export interface CurrentInfoType {
role: string;
model: string;
app: string;
}
export interface ModelItemType {
app: string;
key: string;
title: string;
showText?: string;
}
export interface AddColumnsDataType extends CurrentInfoType {
id?: number | string;
field_name: string;
title: string;
is_query: boolean;
is_create: boolean;
is_update: boolean;
}
export interface ColumnsFormDataType {
id?: number | string;
field_name: string;
title: string;
is_create: boolean;
is_update: boolean;
is_query: boolean;
}