init: UserBaseFront (frontend)

This commit is contained in:
chenxing
2026-08-10 14:41:13 +08:00
commit eea881b616
174 changed files with 32833 additions and 0 deletions
+253
View File
@@ -0,0 +1,253 @@
<template>
<div class="main-wrapper">
<div class="main-container">
<Alert show-icon>设置说明:拖动排序,被使用的分类不能删除</Alert>
<Button class="mb-5" type="primary" @click="addModuleShow">新增应用类型</Button>
<draggable class="type_set-wrap fix" tag="ul" v-model="typeList" :group="'appType'" @change="typeSortSave"
item-key="id">
<template #item="{ element }">
<li class="fl">
<div class="type_set-box">
<div class="type_name">
<span class="content">{{ element.name }}</span>
</div>
<div class="type_action flex">
<div class="action_edit" @click="showSetting(element)">
<span>编辑</span>
</div>
<div class="action_delete" @click="removeSave(element)">
<span>删除</span>
</div>
</div>
<div class="divider"></div>
</div>
</li>
</template>
</draggable>
</div>
<div class="modal-wrap">
<Modal v-model="editModal" :mask-closable="false" width="600"
:title="currentId == null ? '新增应用类型' : '编辑应用类型'">
<Form ref="formData" class="mt-8 mr-4 mb-12" :model="form" :rules="ruleValidate" :label-width="100">
<FormItem label="类型名称:" prop="name">
<Input placeholder="请输入应用类型名称" v-model="form.name" />
</FormItem>
</Form>
<template #footer>
<Button type="primary" :loading="submitting" @click="onEditSave">提交</Button>
<Button @click="onReset">取消</Button>
</template>
</Modal>
</div>
</div>
</template>
<script lang="ts" setup>
import draggable from 'vuedraggable'
import { debounce } from "lodash";
import MyConfirm from "@/components/MyConfirm";
const { data: typeList, send: sendTypeList } = useRequest(
Apis.AppSettings.appTypeList({
transform: (res: any) => {
return res ?? [];
},
cacheFor: null,
}),
{ initialData: [], immediate: true }
)
const refFormData = useTemplateRef('formData');
const editModal = ref(false);
const currentId = ref<number | null>(null);
const submitting = ref(false);
const form = ref<{ id: number | null; name: string }>({
id: null,
name: '',
});
const ruleValidate = ref({
name: [{ required: true, message: "请输入应用类型名称", trigger: "blur" }],
});
async function addModuleShow() {
currentId.value = null;
form.value = { id: null, name: '' };
await refFormData.value?.resetFields();
editModal.value = true;
}
//拖动排序:提交当前顺序的 id 数组
async function typeSortSave() {
const ids = (typeList.value ?? []).map((s: any) => s.id);
await Apis.AppSettings.appTypeSort({ data: ids });
}
async function showSetting(element: any) {
currentId.value = element.id;
form.value = {
id: element.id,
name: element.name,
};
editModal.value = true;
}
/**
* removeSave
*/
async function removeSave(element: any) {
await MyConfirm({
msg: "确定删除该应用类型吗?",
info: "删除后不可恢复!",
async onOk() {
try {
await Apis.AppSettings.deleteType({ pathParams: { id: element.id } });
Message.success("操作成功!");
await sendTypeList();
} catch (error) {
console.error(error);
}
},
});
}
const onEditSave = debounce(onRawEditSave, 500)
async function onRawEditSave() {
try {
const validate = await refFormData.value?.validate();
if (!validate) return false;
} catch {
return false
}
submitting.value = true;
try {
if (currentId.value == null) {
await Apis.AppSettings.addType({
data: {
name: form.value.name,
},
});
} else {
await Apis.AppSettings.editType({
pathParams: { id: currentId.value },
data: {
id: currentId.value,
name: form.value.name,
},
});
}
Message.success("操作成功!");
editModal.value = false;
await sendTypeList();
} catch (error) {
console.error(error);
} finally {
submitting.value = false;
}
}
function onReset() {
refFormData.value?.resetFields();
currentId.value = null;
editModal.value = false;
}
</script>
<style lang="scss" scoped>
.flex {
display: flex;
}
.type_set-wrap {
margin: 12px 0 16px;
}
.type_set-box {
width: 222px;
background: #ffffff;
margin-right: 15px;
margin-bottom: 15px;
.type_name {
height: 66px;
border: 1px solid #e9e9e9;
border-bottom: none;
padding-left: 15px;
padding-right: 15px;
line-height: 66px;
display: flex;
justify-content: center;
align-items: center;
cursor: move;
span.content {
height: 24px;
font-size: 15px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 500;
color: #272829;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 222px;
display: inline-block;
flex: 1 1 0;
}
.iconfont {
font-size: 26px;
}
}
.type_action {
flex-wrap: wrap;
justify-content: center;
align-items: center;
width: 222px;
height: 30px;
line-height: 30px;
background: #f7f7f7;
border-radius: 0px 0px 2px 2px;
border-top: none;
border: 1px solid #e9e9e9;
span {
font-size: 12px;
}
div {
cursor: pointer;
flex: 1;
text-align: center;
}
div.disabled {
color: #ccc;
cursor: not-allowed;
&:hover {
color: #ccc;
}
}
div:hover {
color: #6c91f0;
}
}
.divider {
height: 14px;
width: 1px;
background: #e8e8e8;
float: left;
margin-left: 111px;
margin-top: -22px;
}
}
</style>