Files
UserhomeFront/src/components/StatsBarModal.vue
T
chenxing 4279f99be1
deploy-userbase-front / build-and-deploy (push) Failing after 1m54s
build / build (push) Successful in 3m36s
feat: 接入 UserHome 前端业务代码(含真实 src/依赖,保留 projman 标准 CI)
2026-09-09 22:37:59 +08:00

302 lines
9.7 KiB
Vue

<template>
<Modal
v-model="isTableModalShow"
class-name="menuwapper-modal"
width="1160"
:mask="true"
title="统计模块设置"
:transfer="false"
>
<div class="fix mb-10">
<Button type="primary" size="small" class="fl ml-10 width-10" ghost @click="onEditFormShow()">
新建统计模块
</Button>
</div>
<Table
:columns="menuBarColumns"
:height="360"
:loading="tableLoading"
:data="tableList"
class="link-table"
no-data-text="暂无数据"
>
<template #icon="{ row }">
<img class="icon-box" v-if="!!row.icon" :src="$conf.serviceHost + row.icon" alt="" />
</template>
<template #isShow="{ row }">
<Switch :model-value="row.isShow" true-color="#5979ea" @on-change="onMenuBarShowChange(row.id)" />
</template>
<template #roleIds="{ row }">
<span>{{ row.roleIds.map((item: number) => RoleTypeDict.find(x => x.k == item)?.v).join(",") }}</span>
</template>
<!-- <template #orderNum="{ row }">
<InputNumber :model-value="row.orderNum" :min="1" />
</template> -->
</Table>
<template #footer>
<Button type="primary" ghost @click="isTableModalShow = false">关闭</Button>
</template>
</Modal>
<Modal
v-model="isEditModalShow"
scrollable
width="550"
:title="(!formData.id ? '添加' : '编辑') + '统计模块'"
:transfer="true"
>
<Form ref="refEditForm" class="mr-30" :model="formData" :rules="ruleValidate" :label-width="110">
<Form-Item label="权限角色:" class="fix" prop="roleIds">
<Checkbox
class="fl"
:indeterminate="indeterminate"
:model-value="compCheckAll"
@click.prevent="handleCheckAll"
>
全部
</Checkbox>
<CheckboxGroup v-model="formData.roleIds">
<Checkbox v-for="item in RoleTypeDict" :label="item.k">{{ item.v }}</Checkbox>
</CheckboxGroup>
</Form-Item>
<Form-Item label="名称:" prop="name">
<Input max="4" v-model="formData.name" maxlength="30" placeholder="请输入名称" />
</Form-Item>
<Form-Item label="网址:" prop="url">
<Input v-model="formData.url" placeholder="请输入链接" />
</Form-Item>
<Form-Item label="图标:" prop="icon">
<Upload
:on-success="uploadIconSuccess"
:show-upload-list="false"
:action="$conf.serviceHost + '/api/iconUpload'"
:format="['jpg', 'jpeg', 'png', 'gif']"
accept="image/gif,image/jpeg,image/jpg,image/png"
:with-credentials="true"
:headers="uploadHeaders"
>
<div v-if="!formData.icon" class="icon-upload-wrap">
<SvgIcon name="upload-add" color="#646566" style="width: 20px; height: 20px" />
</div>
<div class="icon-preview-wrap" v-else>
<SvgIcon
@click.stop="formData.icon = null"
class="cloase-btn"
name="widget-close"
size="18"
color="#fff"
/>
<img :src="$conf.serviceHost + formData.icon" alt="" />
</div>
</Upload>
</Form-Item>
<Form-Item label="排序号:" prop="orderNum">
<InputNumber style="width: 120px" v-model="formData.orderNum" :min="1" placeholder="请输入排序号" />
</Form-Item>
<Form-Item label="打开方式:" prop="linkOpenType">
<RadioGroup v-model="formData.linkOpenType" type="button" button-style="solid">
<Radio :label="item.k" v-for="item in linkOpenTypeDict">{{ item.v }}</Radio>
</RadioGroup>
</Form-Item>
</Form>
<template #footer>
<Button type="primary" :loading="editLoading" @click="onEditSave">保存</Button>
<Button @click="isEditModalShow = false">取消</Button>
</template>
</Modal>
</template>
<script lang="ts" setup>
import StatsBarApi from "@/api/StatsBarApi";
import { LinkOpenTypeDict, LinkOpenTypeEnum, RoleTypeEnum, RoleTypeDict } from "@/types";
import Utils from "@/utils";
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import { Message } from "view-ui-plus";
import { ref, reactive, computed } from "vue";
import SvgIcon from "@/components/SvgIcon.vue";
import MyConfirm from "@/components/MyConfirm";
import { BaseDict } from "@/types/Basics";
import { find } from "lodash";
interface FormData {
id: string | null;
roleIds: number[];
name: string | null;
url: string | null;
linkOpenType: number;
icon: string | null;
orderNum: number | null;
isShow: boolean;
isEdit: boolean;
}
// 初始化 formData 的默认值
const defaultFormData: FormData = {
id: null,
roleIds: [], // 添加 roleIds 属性
name: "",
url: "",
linkOpenType: 0,
icon: "",
orderNum: null,
isShow: true,
isEdit: true,
};
const { $conf } = useCurrentInstance();
const uploadHeaders = { yschapirequest: 1, yschreferer: Utils.strToHexCharCode(window.location.href) };
const refEditForm = ref<any>(null);
const isTableModalShow = ref(false),
isEditModalShow = ref(false),
tableLoading = ref(false),
editLoading = ref(false),
tableList = ref<any[]>([]),
formData = reactive(defaultFormData);
const ruleValidate = ref({
roleIds: { required: true, type: "array", message: "请选择权限角色", trigger: "change,submit" },
name: { required: true, message: "请输入名称", trigger: "blur" },
url: { required: true, message: "请输入网址", trigger: "blur" },
icon: { required: true, message: "请上传图标", trigger: "change,submit" },
});
const linkOpenTypeDict = computed(() => LinkOpenTypeDict.filter(x => x.k != LinkOpenTypeEnum.Modal));
const compCheckAll = computed(() => formData.roleIds.length == RoleTypeDict.length && RoleTypeDict.length > 0);
const indeterminate = computed(() => formData.roleIds.length > 0 && formData.roleIds.length < RoleTypeDict.length);
const menuBarColumns = ref([
{
title: "名称",
key: "name",
},
{
title: "图标",
slot: "icon",
},
{
title: "角色",
width: 150,
slot: "roleIds",
},
{
title: "地址",
key: "url",
width: 150,
tooltip: true,
},
{
title: "打开方式",
key: "linkType",
},
{
title: "是否显示",
width: 100,
align: "center",
slot: "isShow",
},
{
title: "排序号",
key: "orderNum",
align: "center",
},
{
title: "操作",
width: 120,
align: "center",
render: (h: any, params: any) => {
const disabled = !params.row.isEdit,
id = params.row.id;
return [
Utils.operatingTextHandle(h, "编辑", "mr-2", () => onEditFormShow(id), disabled),
Utils.operatingTextHandle(h, "删除", "text-error", () => onDeleteMenu(id), disabled),
];
},
},
]);
async function show() {
isTableModalShow.value = true;
await getMenuBarList();
console.log("show");
}
async function getMenuBarList() {
tableLoading.value = true;
const list = await StatsBarApi.getStatsBarSchList();
list.forEach(element => {
element.linkType = find(linkOpenTypeDict.value, { k: element.linkOpenType })?.v;
});
tableList.value = list;
tableLoading.value = false;
}
function handleCheckAll() {
formData.roleIds = !compCheckAll.value ? RoleTypeDict.map(item => item.k) : [];
}
function uploadIconSuccess(response: any, file: any, fileListt: any) {
if (response.code == 0) formData.icon = response.data.url;
else Message.error("上传错误!");
// console.log(response, file, fileListt);
}
async function onEditFormShow(id?: number) {
await refEditForm.value?.resetFields();
isEditModalShow.value = false;
if (!id) {
formData.id = null;
formData.linkOpenType = LinkOpenTypeEnum.Open;
} else {
let find = tableList.value.find(x => x.id == id);
Object.assign(formData, find);
}
isEditModalShow.value = true;
}
async function onDeleteMenu(id: number) {
await MyConfirm({
title: "删除",
msg: "确定删除该统计模块吗?",
info: "删除后无法恢复!",
async onOk() {
await StatsBarApi.deleteStatsBar(id);
},
});
await getMenuBarList();
}
async function onEditSave() {
let validate: boolean = await refEditForm.value?.validate();
if (!validate) return false;
editLoading.value = true;
try {
await StatsBarApi.saveStatsBar(formData);
Message.success("操作成功!");
await getMenuBarList();
isEditModalShow.value = false;
} catch (error) {
Message.success("操作失败!");
} finally {
editLoading.value = false;
}
}
function onMenuBarShowChange(id: number) {
StatsBarApi.toggleStatsBarShow(id);
}
defineExpose({
show,
});
</script>
<style scoped>
.icon-box {
width: 20px;
height: 20px;
}
</style>