feat: 设置模块系统配置数据字典的项目管理功能
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<a-card title="项目管理">
|
||||
<!-- <template #extra>
|
||||
<a-button type="primary" @click="handleSave">保存</a-button>
|
||||
</template> -->
|
||||
<a-spin style="display: block" :loading="loading">
|
||||
<div
|
||||
v-if="projectLabelList && projectLabelList.length"
|
||||
class="project_label_wrap"
|
||||
>
|
||||
<div class="flex_center_between">
|
||||
<div class="title_wrap">
|
||||
<h4>项目类型(标签类)</h4>
|
||||
<a-checkbox
|
||||
:model-value="
|
||||
checkedProjectLabelId.length === projectLabelList.length &&
|
||||
projectLabelList.length > 0
|
||||
"
|
||||
@change="onCheckAllLabelChange"
|
||||
>全选</a-checkbox
|
||||
>
|
||||
</div>
|
||||
<a-button type="text" @click="handleAddLabel"
|
||||
><icon-plus />新增</a-button
|
||||
>
|
||||
<projectLabelFormModal
|
||||
v-model:visible="showLabelModal"
|
||||
:record="currentLabelFormInfo"
|
||||
:is-edit="isEdit"
|
||||
@submitted="getAllProjectTypeListData"
|
||||
/>
|
||||
</div>
|
||||
<ul style="display: flex; align-items: center; margin-top: 10px">
|
||||
<li
|
||||
v-for="item in projectLabelList"
|
||||
:key="item.id"
|
||||
style="margin: 5px 30px 0 0"
|
||||
>
|
||||
<a-checkbox
|
||||
:model-value="checkedProjectLabelId.includes(item.id)"
|
||||
@change="(val) => onProjectTypeCheckChange(item, val)"
|
||||
>
|
||||
{{ item.name }}
|
||||
<span
|
||||
class="circle"
|
||||
:style="{
|
||||
borderColor: item.color,
|
||||
backgroundColor: item.color,
|
||||
}"
|
||||
></span>
|
||||
<icon-edit
|
||||
v-if="item.type === 2"
|
||||
class="edit_icon"
|
||||
@click.stop.prevent="handleEditLabel(item, $event)"
|
||||
/>
|
||||
</a-checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
<a-divider />
|
||||
<div class="title_wrap">
|
||||
<h4>项目地址(枚举类)</h4>
|
||||
<a-checkbox
|
||||
:model-value="
|
||||
checkedProjectProvinceId.length === provinceList?.length &&
|
||||
provinceList?.length > 0
|
||||
"
|
||||
@change="onCheckAllProvinceChange"
|
||||
>全选</a-checkbox
|
||||
>
|
||||
</div>
|
||||
<ul
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 10px;
|
||||
"
|
||||
>
|
||||
<li
|
||||
v-for="item in provinceList"
|
||||
:key="item.id"
|
||||
style="margin: 15px 30px 0 0"
|
||||
>
|
||||
<a-checkbox
|
||||
:model-value="checkedProjectProvinceId.includes(item.id)"
|
||||
@change="(val) => onProjectProvinceCheckChange(item, val)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</a-checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
// getProjectTypeById
|
||||
import {
|
||||
getAllProjectTypeList,
|
||||
projectTypeInfo,
|
||||
getProvinceList,
|
||||
ProvinceItem,
|
||||
checkProjectType,
|
||||
checkAllProjectType,
|
||||
projectTypeChecked,
|
||||
checkAllProvince,
|
||||
checkProvince,
|
||||
} from '@/api/setting';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import projectLabelFormModal from './project-label-form-modal.vue';
|
||||
|
||||
const projectLabelList = ref<projectTypeInfo[]>([]);
|
||||
const provinceList = ref<ProvinceItem[] | null>(null);
|
||||
const checkedProjectLabelId = ref<number[]>([]);
|
||||
const checkedProjectProvinceId = ref<number[]>([]);
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const showLabelModal = ref<boolean>(false);
|
||||
const isEdit = ref<boolean>(false);
|
||||
const currentLabelFormInfo = ref(null);
|
||||
|
||||
const checkAllProjectTypeData = async (checked: boolean) => {
|
||||
try {
|
||||
const params = { is_check: (checked ? 1 : 0) as projectTypeChecked };
|
||||
const { code, message } = await checkAllProjectType(params);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const checkProjectTypeData = async (params: {
|
||||
id: number;
|
||||
is_check: projectTypeChecked;
|
||||
}) => {
|
||||
try {
|
||||
const { code, message } = await checkProjectType(params);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const checkAllProvinceData = async (checked: boolean) => {
|
||||
try {
|
||||
const params = { is_check: (checked ? 1 : 0) as projectTypeChecked };
|
||||
const { code, message } = await checkAllProvince(params);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const checkProvinceData = async (params: {
|
||||
id: number;
|
||||
is_check: projectTypeChecked;
|
||||
}) => {
|
||||
try {
|
||||
const { code, message } = await checkProvince(params);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
const onCheckAllLabelChange = (checked: boolean) => {
|
||||
if (checked) {
|
||||
// 全选
|
||||
checkedProjectLabelId.value = projectLabelList.value.map(
|
||||
(item) => item.id
|
||||
);
|
||||
} else {
|
||||
// 取消全选
|
||||
checkedProjectLabelId.value = [];
|
||||
}
|
||||
checkAllProjectTypeData(checked);
|
||||
};
|
||||
const onProjectTypeCheckChange = (item, checked) => {
|
||||
if (checked) {
|
||||
if (!checkedProjectLabelId.value.includes(item.id)) {
|
||||
checkedProjectLabelId.value.push(item.id);
|
||||
}
|
||||
} else {
|
||||
checkedProjectLabelId.value = checkedProjectLabelId.value.filter(
|
||||
(id) => id !== item.id
|
||||
);
|
||||
}
|
||||
checkProjectTypeData({ id: item.id, is_check: checked ? 1 : 0 });
|
||||
};
|
||||
const onCheckAllProvinceChange = (checked: boolean) => {
|
||||
if (checked && provinceList.value) {
|
||||
checkedProjectProvinceId.value = provinceList.value.map(
|
||||
(item) => item.id
|
||||
);
|
||||
} else {
|
||||
checkedProjectProvinceId.value = [];
|
||||
}
|
||||
checkAllProvinceData(checked);
|
||||
};
|
||||
const onProjectProvinceCheckChange = (item, checked) => {
|
||||
if (checked) {
|
||||
if (!checkedProjectProvinceId.value.includes(item.id)) {
|
||||
checkedProjectProvinceId.value.push(item.id);
|
||||
}
|
||||
} else {
|
||||
checkedProjectProvinceId.value = checkedProjectProvinceId.value.filter(
|
||||
(id) => id !== item.id
|
||||
);
|
||||
}
|
||||
checkProvinceData({ id: item.id, is_check: checked ? 1 : 0 });
|
||||
};
|
||||
const getAllProjectTypeListData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { code, data } = await getAllProjectTypeList();
|
||||
if (code === 200 && data) {
|
||||
projectLabelList.value = data?.projectTypesList;
|
||||
if (projectLabelList.value?.length === 0) return;
|
||||
checkedProjectLabelId.value = projectLabelList.value
|
||||
.filter((i) => i.isCheck === 1)
|
||||
.map((i) => i.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const handleAddLabel = () => {
|
||||
showLabelModal.value = true;
|
||||
isEdit.value = false;
|
||||
currentLabelFormInfo.value = null;
|
||||
};
|
||||
const handleEditLabel = (item, event) => {
|
||||
if (event) event.preventDefault();
|
||||
showLabelModal.value = true;
|
||||
isEdit.value = true;
|
||||
currentLabelFormInfo.value = item;
|
||||
};
|
||||
const getProvinceListData = async () => {
|
||||
try {
|
||||
const { code, data } = await getProvinceList();
|
||||
if (code === 200 && data) {
|
||||
provinceList.value = data?.list;
|
||||
if (provinceList.value?.length === 0) return;
|
||||
checkedProjectProvinceId.value = provinceList.value
|
||||
.filter((i) => i.isCheck === 1)
|
||||
.map((i) => i.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getAllProjectTypeListData();
|
||||
await getProvinceListData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.project_label_wrap {
|
||||
.title_wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.circle {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 50%;
|
||||
margin-left: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.edit_icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
:title="isEdit ? '编辑项目标签字典' : '新增项目标签字典'"
|
||||
unmount-on-close
|
||||
>
|
||||
<template #footer>
|
||||
<div :class="{ flex_center_between: isEdit }">
|
||||
<template v-if="isEdit">
|
||||
<a-popconfirm
|
||||
:ok-text="$t('cancel')"
|
||||
:cancel-text="$t('delete')"
|
||||
:ok-button-props="{ type: 'outline' }"
|
||||
:cancel-button-props="{
|
||||
type: 'primary',
|
||||
status: 'danger',
|
||||
}"
|
||||
content="确定删除该项目类型?"
|
||||
type="error"
|
||||
@cancel="handleDelLabel"
|
||||
>
|
||||
<a-button type="primary" status="danger">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
<a-space>
|
||||
<a-button @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" @click="handleSubmit">确定</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
auto-label-width
|
||||
layout="vertical"
|
||||
>
|
||||
<!-- 名称 -->
|
||||
<a-form-item label="名称" field="name" required>
|
||||
<a-input
|
||||
v-model="form.name"
|
||||
:max-length="20"
|
||||
placeholder="请输入标签字典名"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 背景样式 -->
|
||||
<a-form-item label="背景样式" field="color" required>
|
||||
<ul class="color_list">
|
||||
<li
|
||||
v-for="item in colorList"
|
||||
:key="item.color"
|
||||
class="color_item"
|
||||
:style="{ backgroundColor: item.color }"
|
||||
@click="chooseLabelColor(item.color)"
|
||||
>
|
||||
<icon-check-circle-fill
|
||||
v-if="form.color === item.color"
|
||||
size="24px"
|
||||
:style="{ color: 'red' }"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import type { FormInstance } from '@arco-design/web-vue';
|
||||
import {
|
||||
LabelForm,
|
||||
createProjectType,
|
||||
updateProjectType,
|
||||
delProjectType,
|
||||
} from '@/api/setting';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const colorList = [
|
||||
{ color: '#ecfeec', border: '' },
|
||||
{ color: '#eaf3fe', border: '' },
|
||||
{ color: '#fef7ea', border: '' },
|
||||
{ color: '#fcede9', border: '' },
|
||||
{ color: '#e8dbfa', border: '' },
|
||||
{ color: '#efefef', border: '' },
|
||||
];
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
isEdit: boolean;
|
||||
record?: LabelForm | null;
|
||||
}>();
|
||||
const currentLabelColor = ref<string>('#ecfeec');
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void;
|
||||
(e: 'submitted'): void;
|
||||
}>();
|
||||
// 表单数据
|
||||
const formRef = ref<FormInstance>();
|
||||
const form = reactive<LabelForm>({
|
||||
name: '',
|
||||
color: '',
|
||||
id: undefined,
|
||||
});
|
||||
|
||||
// 校验规则
|
||||
const rules = {
|
||||
name: [{ required: true, message: '请输入名称' }],
|
||||
color: [{ required: true, message: '请选择背景样式' }],
|
||||
};
|
||||
|
||||
const chooseLabelColor = (color: string) => {
|
||||
if (color === currentLabelColor.value) return;
|
||||
form.color = color;
|
||||
};
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
if (props.record) {
|
||||
form.id = props.record?.id;
|
||||
form.name = props.record?.name;
|
||||
form.color = props.record?.color ?? '';
|
||||
} else {
|
||||
Object.assign(form, {
|
||||
id: null,
|
||||
name: '',
|
||||
color: '#ecfeec',
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 表单事件
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
};
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value?.validate();
|
||||
const { code, message } = props.isEdit
|
||||
? await updateProjectType(form)
|
||||
: await createProjectType(form);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
handleCancel();
|
||||
// 通知父组件更新部门列表数据
|
||||
emit('submitted');
|
||||
}
|
||||
};
|
||||
const handleDelLabel = async () => {
|
||||
try {
|
||||
const { id } = form;
|
||||
if (!id) return;
|
||||
const { code, message } = await delProjectType(id);
|
||||
if (code === 200) {
|
||||
Message.success(message);
|
||||
handleCancel();
|
||||
// 通知父组件更新部门列表数据
|
||||
emit('submitted');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.color_list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.color_item {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-right: 36px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user