init local code
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, watch } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import Utils from "@/utils/index";
|
||||
import MyConfirm from "@/components/MyConfirm";
|
||||
import { linkApi, uploadUrl } from "@/api/module/cms";
|
||||
import { useCmsStore } from "@/store";
|
||||
import { LinkVo } from "@/types/cms";
|
||||
|
||||
const store = useCmsStore();
|
||||
|
||||
const rows = ref<LinkVo[]>([]);
|
||||
const loading = ref(false);
|
||||
const tableHeight = Utils.useTableHeight({ isOperat: true });
|
||||
|
||||
const columns = [
|
||||
{ title: "分组", key: "groupName", width: 140 },
|
||||
{
|
||||
title: "Logo",
|
||||
key: "logoUrl",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
p.row.logoUrl
|
||||
? h("img", { src: p.row.logoUrl, style: { maxHeight: "36px", maxWidth: "72px" } })
|
||||
: h("span", { style: { color: "#999" } }, "-"),
|
||||
},
|
||||
{ title: "名称", key: "name", minWidth: 200, tooltip: true },
|
||||
{ title: "链接地址", key: "linkUrl", minWidth: 260, tooltip: true },
|
||||
{ title: "排序", key: "sortNo", width: 80, align: "center" },
|
||||
{
|
||||
title: "状态",
|
||||
key: "status",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
h(Tag, { color: p.row.status === 1 ? "success" : "default" }, () =>
|
||||
p.row.status === 1 ? "显示" : "隐藏"
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 120,
|
||||
fixed: "right",
|
||||
align: "center",
|
||||
render: (h: any, p: any) => [
|
||||
Utils.operatingHandle(h, "编辑", "icon-edit", () => openEdit(p.row)),
|
||||
Utils.operatingHandle(h, "删除", "icon-ashbin", () => doDelete(p.row)),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const modalVisible = ref(false);
|
||||
const saving = ref(false);
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
id: undefined as number | undefined,
|
||||
groupName: "default",
|
||||
name: "",
|
||||
logoUrl: "",
|
||||
linkUrl: "",
|
||||
sortNo: 0,
|
||||
status: 1,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: [{ required: true, message: "链接名称不得为空", trigger: "blur" }],
|
||||
linkUrl: [{ required: true, message: "链接地址不得为空", trigger: "blur" }],
|
||||
};
|
||||
|
||||
/** 分组 Tab(从数据聚合) */
|
||||
const groups = computed(() => {
|
||||
const set = new Set<string>();
|
||||
rows.value.forEach(r => set.add(r.groupName));
|
||||
return Array.from(set);
|
||||
});
|
||||
const activeGroup = ref<string>("");
|
||||
|
||||
const visibleRows = computed(() =>
|
||||
activeGroup.value ? rows.value.filter(r => r.groupName === activeGroup.value) : rows.value
|
||||
);
|
||||
|
||||
async function run() {
|
||||
if (!store.siteId) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
rows.value = (await linkApi.list(store.siteId).send()) || [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
Object.assign(form, {
|
||||
id: undefined,
|
||||
groupName: activeGroup.value || "default",
|
||||
name: "",
|
||||
logoUrl: "",
|
||||
linkUrl: "",
|
||||
sortNo: 0,
|
||||
status: 1,
|
||||
});
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function openEdit(row: LinkVo) {
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
groupName: row.groupName,
|
||||
name: row.name,
|
||||
logoUrl: row.logoUrl || "",
|
||||
linkUrl: row.linkUrl,
|
||||
sortNo: row.sortNo,
|
||||
status: row.status,
|
||||
});
|
||||
modalVisible.value = true;
|
||||
}
|
||||
|
||||
function logoUploaded(res: any) {
|
||||
if (res.code === 0 && res.data) {
|
||||
form.logoUrl = res.data.url;
|
||||
} else {
|
||||
Message.error(res.msg || "Logo 上传失败");
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
const valid = await formRef.value?.validate();
|
||||
if (!valid) return;
|
||||
saving.value = true;
|
||||
try {
|
||||
await linkApi
|
||||
.save({
|
||||
id: form.id,
|
||||
siteId: store.siteId!,
|
||||
groupName: form.groupName || "default",
|
||||
name: form.name,
|
||||
logoUrl: form.logoUrl || undefined,
|
||||
linkUrl: form.linkUrl,
|
||||
sortNo: form.sortNo,
|
||||
status: form.status,
|
||||
})
|
||||
.send();
|
||||
Message.success("保存成功!");
|
||||
modalVisible.value = false;
|
||||
run();
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function doDelete(row: LinkVo) {
|
||||
MyConfirm({
|
||||
title: "删除友链",
|
||||
msg: `确定删除「${row.name}」吗?`,
|
||||
async onOk() {
|
||||
await linkApi.delete({ id: row.id!, siteId: store.siteId! }).send();
|
||||
Message.success("操作成功!");
|
||||
run();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(run);
|
||||
|
||||
// 站点上下文切换即时重载(docs/09 §3.3)
|
||||
watch(() => store.siteId, () => run());
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<div class="main-container">
|
||||
<div class="fix">
|
||||
<Button class="fl" type="primary" size="large" @click="openCreate">
|
||||
<Icon type="ios-add" />
|
||||
新增友链
|
||||
</Button>
|
||||
<Tabs v-if="groups.length" class="fr" :value="activeGroup" @on-click="(g: string) => (activeGroup = g)">
|
||||
<TabPane v-for="g in groups" :key="g" :name="g" :label="`${g}(${rows.filter(r => r.groupName === g).length})`" />
|
||||
</Tabs>
|
||||
</div>
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="visibleRows"
|
||||
:height="tableHeight"
|
||||
:loading="loading"
|
||||
no-data-text="暂无友链"
|
||||
/>
|
||||
|
||||
<Modal v-model="modalVisible" :title="form.id ? '编辑友链' : '新增友链'" :mask-closable="false" width="520px">
|
||||
<Form ref="formRef" :model="form" :rules="rules" :label-width="100">
|
||||
<FormItem label="分组">
|
||||
<Input v-model="form.groupName" :maxlength="64" placeholder="上级部门/兄弟院校/合作单位…" />
|
||||
</FormItem>
|
||||
<FormItem label="名称" prop="name">
|
||||
<Input v-model="form.name" :maxlength="128" />
|
||||
</FormItem>
|
||||
<FormItem label="Logo(可选)">
|
||||
<Upload
|
||||
:action="uploadUrl() + '?siteId=' + store.siteId"
|
||||
with-credentials
|
||||
:show-upload-list="false"
|
||||
:format="['jpg', 'jpeg', 'png', 'gif', 'webp']"
|
||||
:on-success="logoUploaded"
|
||||
>
|
||||
<Button icon="ios-cloud-upload-outline">上传 Logo</Button>
|
||||
</Upload>
|
||||
<img v-if="form.logoUrl" :src="form.logoUrl" class="img-preview" />
|
||||
</FormItem>
|
||||
<FormItem label="链接地址" prop="linkUrl">
|
||||
<Input v-model="form.linkUrl" :maxlength="500" placeholder="http(s):// 开头" />
|
||||
</FormItem>
|
||||
<FormItem label="排序">
|
||||
<InputNumber v-model="form.sortNo" :min="0" />
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<RadioGroup v-model="form.status">
|
||||
<Radio :label="1">显示</Radio>
|
||||
<Radio :label="0">隐藏</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Button @click="modalVisible = false">取消</Button>
|
||||
<Button type="primary" :loading="saving" @click="save">保存</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.img-preview {
|
||||
display: block;
|
||||
max-width: 200px;
|
||||
max-height: 64px;
|
||||
margin-top: 8px;
|
||||
border: 1px solid #e5e6eb;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user