This commit is contained in:
owenchen committed 2026-09-04 14:19:18 +08:00
1 parent b485837fc8
commit 24816ba81b
6 files changed
+802 -7

No files matched your search

+5 -6
View File
@@ -9,7 +9,7 @@ const JWT_STORAGE_ID = "x-jwt-storage-id";
const JWT_REFRESHKEY_STORAGE_ID = "x-jwt-refresh-key-storage-id";
const LOGIN_PROFILE_STORAGE_ID = "x-login-profile-storage-id";
const LOCALE_ID = "x-locale-id";
const ROUTES = "x-routes";
export const useLoginProfileStore = defineStore("loginProfile", {
state: (): {
loginProfile: LoginProfile;
@@ -96,11 +96,10 @@ export const useLoginProfileStore = defineStore("loginProfile", {
return (JSON.parse(str) as LoginProfile).PermissionInfo;
},
clearStorage() {
storage.set(JWT_STORAGE_ID, null);
storage.set(JWT_REFRESHKEY_STORAGE_ID, null);
storage.set(LOGIN_PROFILE_STORAGE_ID, null);
storage.remove(JWT_STORAGE_ID);
storage.remove(JWT_REFRESHKEY_STORAGE_ID);
storage.remove(LOGIN_PROFILE_STORAGE_ID);
storage.remove(ROUTES);
},
},
});
@@ -0,0 +1,796 @@
<template>
<a-spin size="large" :spinning="loading">
<div class="page-container">
<div class="page-header">
<a-row :gutter="[16, 8]">
<a-col :lg="8" :sm="24">
<a-row :wrap="false">
<a-col flex="none">
<div style="padding: 0">
<a-input
flex="none"
readonly
value="相册编号"
class="site-input-split"
style="
width: 160px;
border-radius: 0;
border-top-left-radius: 5pt 5pt;
border-bottom-left-radius: 5pt 5pt;
pointer-events: none;
"
/>
</div>
</a-col>
<a-col flex="auto">
<a-input-search
:disabled="isEdit"
v-model:value="publishName"
flex="auto"
@search="onModalSearch"
/>
</a-col>
</a-row>
</a-col>
<a-col :lg="12" :sm="24">
<a-space>
<a-button
type="primary"
:disabled="isEdit"
:icon="h(FileSearchOutlined)"
@click.prevent="onSearch"
>查询</a-button
>
<a-button
type="primary"
:disabled="isEdit"
:icon="h(ClearOutlined)"
@click.prevent="onReset"
>重置</a-button
>
<a-button
type="primary"
:disabled="isEdit"
:icon="h(FileAddOutlined)"
@click.prevent="onCreate"
>新增</a-button
>
</a-space>
</a-col>
</a-row>
</div>
<div class="page-main" :style="{ height: resultH }">
<a-row :gutter="[16, 8]">
<a-col :lg="24" :sm="24">
<a-row :wrap="true" align="middle">
<a-col :lg="3" :sm="12">
<span style="min-width: 60px; width: 60px">相册编号:</span>
</a-col>
<a-col :lg="3" :sm="12" style="min-width: 300px">
<a-input
:readonly="true"
v-model:value="data.PublishPhoto.PublishName"
/>
</a-col>
</a-row>
</a-col>
</a-row>
<a-row :gutter="[16, 8]" style="margin-top: 8px">
<a-col :lg="24" :sm="24">
<a-row :wrap="true" align="middle">
<a-col :lg="3" :sm="12">
<span style="min-width: 60px; width: 60px">相册名称:</span>
</a-col>
<a-col :lg="18" :sm="12" style="min-width: 300px">
<a-input
:maxlength="50"
:readonly="!isEdit"
v-model:value="data.PublishPhoto.PublishLocalName"
/>
</a-col>
</a-row>
</a-col>
</a-row>
<a-row :gutter="[16, 8]" style="margin-top: 8px">
<a-col :lg="24" :sm="24">
<a-row :wrap="true" align="middle">
<a-col :lg="3" :sm="12">
<span style="min-width: 60px; width: 60px">相册描述:</span>
</a-col>
<a-col :lg="18" :sm="12" style="min-width: 300px">
<a-textarea
:auto-size="{ minRows: 3, maxRows: 5 }"
:maxlength="500"
:readonly="!isEdit"
v-model:value="data.PublishPhoto.Notice"
/>
</a-col>
</a-row>
</a-col>
</a-row>
<a-row :gutter="[16, 8]" style="margin-top: 8px">
<a-col :lg="24" :sm="24">
<a-row :wrap="true" align="middle">
<a-col :lg="3" :sm="12"> </a-col>
<a-col :lg="3" :sm="12" style="min-width: 300px">
<Checkbox
v-model:value="data.PublishPhoto.OpenIndc"
true-value="Y"
false-value="N"
:disabled="!isEdit"
><span
:style="{
color:
data.PublishPhoto.OpenIndc == 'Y' ? 'red' : 'black',
}"
>
对所有人公开?
</span>
</Checkbox>
</a-col>
</a-row>
</a-col>
<a-col :lg="24" :sm="24">
<a-row :wrap="true" align="middle">
<a-col :lg="3" :sm="3"> </a-col>
<a-col :lg="3" :sm="18" style="min-width: 300px">
<Checkbox
v-model:value="data.PublishPhoto.DefaultIndc"
true-value="Y"
false-value="N"
:disabled="!isEdit"
>默认相册展览?
</Checkbox>
</a-col>
</a-row>
</a-col>
</a-row>
<a-divider
orientation="left"
orientation-margin="0px"
dashed
style="background-color: silver"
>
</a-divider>
<a-collapse v-model:activeKey="activeKey">
<a-collapse-panel key="2" header="相册明细">
<a-table
bordered
:data-source="data.Details"
:columns="columnDtls"
:pagination="false"
:scroll="{ x: 360, y: 600 }"
>
<template #bodyCell="datas">
<a-card hoverable style="width: 300px">
<template #cover>
<a-image
style="height: 466px"
:src="datas.record.FileName"
/>
</template>
<a-card-meta>
<template #description>
<a-textarea
v-if="isEdit"
:rows="4"
:readonly="!isEdit"
v-model:value="datas.record.Notice"
/>
<span v-if="!isEdit">{{ datas.record.Notice }}</span>
</template>
</a-card-meta>
<template #actions>
<span v-if="isEdit">
<UpSquareTwoTone
:style="{ fontSize: '24px', color: '#08c' }"
@click="upSon(datas.index)"
/>上移
</span>
<span v-if="isEdit">
<DownSquareTwoTone
:style="{
fontSize: '24px',
color: '#08c',
marginLeft: '20px',
marginRight: '20px',
}"
@click="downSon(datas.index)"
/>下移
</span>
<span v-if="isEdit">
<DeleteOutlined
:style="{ fontSize: '24px', color: 'red' }"
@click="deleteSon(datas.record.DetailId)"
/>删除
</span>
</template>
</a-card>
</template>
</a-table>
</a-collapse-panel>
</a-collapse>
<a-divider
orientation="left"
orientation-margin="0px"
dashed
style="background-color: silver"
>
</a-divider>
<a-collapse v-model:activeKey="activeKey" v-if="canAmend">
<a-collapse-panel key="3" header="公开群组明细">
<a-table
bordered
:data-source="data.FamilyGroups"
:columns="columnFamilyGroups"
:pagination="false"
:scroll="{ x: 520, y: 600 }"
>
<template #bodyCell="datas">
<template v-if="datas.column.dataIndex === 'index'">
<span>{{ datas.index + 1 }}</span>
</template>
<template
v-else-if="datas.column.dataIndex === 'operation' && isEdit"
>
<DeleteOutlined
:style="{ fontSize: '24px', color: 'red' }"
@click="deleteFamilyGroup(datas.record.FamilyName)"
/>
</template>
<template
v-else-if="
datas.column.dataIndex === FamilyGroupEntity.FAMILY_NAME &&
!isEdit
"
>
<span
style="color: blue; font-size: 18px; cursor: pointer"
@click="onViewActorOperation(datas.record.FamilyName)"
>
{{ datas.record.FamilyName }}</span
>
</template>
</template>
</a-table>
<template #extra v-if="isEdit">
<PlusSquareTwoTone
:style="{ fontSize: '24px', color: '#08c' }"
@click="addFamilyGroup"
/>
</template>
</a-collapse-panel>
</a-collapse>
</div>
<div class="page-footer">
<div style="">
<a-row :gutter="24">
<a-col :lg="24" :sm="24">
<div>
<a-row v-if="isEdit" :gutter="[16, 8]">
<a-space>
<a-popconfirm
v-if="data.PublishPhoto.CreatedBy"
title="确定是否取消修改?"
ok-text="是"
cancel-text="否"
@confirm="onCancel"
>
<a-button type="primary" ghost :icon="h(UndoOutlined)"
>取消</a-button
>
</a-popconfirm>
<a-button
v-if="!data.PublishPhoto.CreatedBy"
type="primary"
ghost
:icon="h(UndoOutlined)"
@click.prevent="onCancel"
>取消</a-button
>
<a-button
type="primary"
ghost
:icon="h(SaveOutlined)"
@click.prevent="onSave"
>保存</a-button
>
</a-space>
</a-row>
<a-row v-else :gutter="[16, 8]">
<a-space>
<a-button
type="primary"
v-if="canAmend"
:icon="h(EditOutlined)"
:disabled="!hasData"
@click.prevent="onAmend"
>修改</a-button
>
<a-popconfirm
:disabled="!hasData"
title="确定是否删除这条记录?"
ok-text="是"
cancel-text="否"
@confirm="onDelete"
>
<a-button
type="primary"
danger
:icon="h(DeleteOutlined)"
:disabled="!hasData"
v-if="canDelete"
>删除</a-button
>
</a-popconfirm>
<a-button
type="primary"
v-if="canAmend"
:icon="h(EditOutlined)"
:disabled="!hasData"
@click.prevent="onViewPreview"
>作品展览</a-button
>
</a-space>
</a-row>
</div>
</a-col>
</a-row>
</div>
</div>
</div>
<dragModal
v-model:open="showModal"
width="80%"
title="作品发布查询"
@cancel="handleCance"
:mask-closable="false"
:fullscreen="width < 640"
@ok="handleSelect"
>
<publishPhotoEnquiry
ref="enquiry"
@on-row-dblclick="handleSelect"
></publishPhotoEnquiry>
</dragModal>
<dragModal
v-model:open="showModalFamilyGroup"
width="60%"
title="群组查询"
:mask-closable="false"
:fullscreen="width < 640"
@ok="handleSelectFamilyGroup"
>
<familyGroupEnquiry
ref="groupEnquiry"
@on-row-dblclick="handleSelectFamilyGroup"
>
</familyGroupEnquiry>
</dragModal>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, unref, onBeforeMount, inject, provide, h, onMounted } from "vue";
import { notification } from "ant-design-vue";
import { useRoute, useRouter } from "vue-router";
import {
DeleteOutlined,
EditOutlined,
ClearOutlined,
FileSearchOutlined,
FileAddOutlined,
UndoOutlined,
SaveOutlined,
PlusSquareTwoTone,
DownSquareTwoTone,
UpSquareTwoTone,
} from "@ant-design/icons-vue";
import {
PermissionContext,
usePermissionContext,
} from "@/hooks/PermissionContext";
import dragModal from "@/components/basic/DragModal.vue";
import Checkbox from "@/components/basic/check-box/index.vue";
import { PublishPhotoData } from "@/data/auto/publishPhotoData";
import publishPhotoEnquiry from "./PublishPhotoEnquiry.vue";
import publishPhotoService from "@/service/master/publishPhotoService";
import { SelectOption } from "@/data/auto/selectOption";
import { useWindowSize } from "@vueuse/core";
import { PublishPhotoEntity } from "@/data/auto/publishPhotoEntity";
import { PublishPhotoDetailEntity } from "@/data/auto/publishPhotoDetailEntity";
import { BindOption } from "@/data/custom/bindOption";
import { nextTick } from "process";
import IconsSelect from "@/components/basic/icons-select/index.vue";
import { PublishPhotoFamilyGroupEntity } from "@/data/auto/publishPhotoFamilyGroupEntity";
import { FamilyGroupEntity } from "@/data/auto/familyGroupEntity";
import familyGroupEnquiry from "./FamilyGroupEnquiry.vue";
import { PublishPhotoFamilyGroupDisplayData } from "@/data/auto/publishPhotoFamilyGroupDisplayData";
import { useLoginProfileStore } from "@/store/modules/loginProfile";
//================inject================
const loading = ref<boolean>(false);
//================inject================
const { width, height } = useWindowSize();
const route = useRoute();
const router = useRouter();
const publishName = ref<string>(route.params.id as string);
const mode = ref<string>(route.params.mode as string);
const isEdit = ref<boolean>(false);
const canAmend = ref<boolean>(false);
const canDelete = ref<boolean>(false);
const canCreate = ref<boolean>(false);
const showModal = ref<boolean>(false);
const showModalFamilyGroup = ref<boolean>(false);
const showModalPermission = ref<boolean>(false);
const rowSelectionType = ref<string>("radio");
const showModalType = ref<number>(0);
const data = ref<PublishPhotoData>(new PublishPhotoData());
const hasData = ref<boolean>(false);
const resultH = ref("");
const oldPublishName = ref<string>(publishName.value);
const initBindOptions = ref<BindOption[]>([]);
interface PublishPhotoEnquiry {
keys: PublishPhotoEntity[];
setBindOptionValue(
bindValue: string,
value: string,
value1: string,
values: string[],
): void;
}
const enquiry = ref<PublishPhotoEnquiry | null>(null);
interface FamilyGroupEnquiry {
keys: FamilyGroupEntity[];
setBindOptionValue(
bindValue: string,
value: string,
value1: string,
values: string[],
): void;
}
const groupEnquiry = ref<FamilyGroupEnquiry | null>(null);
const activeKey = ref(["1", "2"]);
const columnDtls = ref([
{
title: "图片",
dataIndex: PublishPhotoDetailEntity.FILE_NAME,
width: "45%",
sequence: 1,
hidden: "N",
},
]);
//================provide================
//弹出(Function Modal)
provide("isModalPublishPhoto", showModal);
//记录单选还是多选(Modal)
provide("selectionTypePublishPhoto", rowSelectionType);
//初始化查询条件的值(Modal)
provide("initBindOptionsPublishPhoto", initBindOptions);
provide("isModalFamilyGroup", showModalFamilyGroup);
provide("selectionTypeFamilyGroup", "checkbox");
//================provide================
onBeforeMount(async () => {});
onMounted(() => {
let pContext: PermissionContext = usePermissionContext();
canAmend.value = pContext.canAmend(route.meta.permission as string);
canDelete.value = pContext.canDelete(route.meta.permission as string);
canCreate.value = pContext.canCreate(route.meta.permission as string);
computResultTableHeight();
if (publishName.value && publishName.value.trim().length > 0) {
onSearch();
}
if (mode.value && mode.value == "create") {
onCreate();
isEdit.value = true;
} else if (mode.value && mode.value == "amend") {
isEdit.value = true;
}
});
const computResultTableHeight = () => {
if (width.value > 640) {
resultH.value = "calc(100vh - 220px )";
} else {
resultH.value = "calc(100vh - 250px )";
}
};
const onModalSearch = () => {
showModal.value = true;
rowSelectionType.value = "radio";
showModalType.value = 0;
};
const onSearch = async () => {
if (!publishName.value || publishName.value.trim().length == 0) {
notification.info({
message: "系统提示:",
description: "请输入发布编号",
placement: "topRight",
});
hasData.value = false;
return;
}
await publishPhotoService.FindByKey(publishName.value.trim()).then((res) => {
data.value = res;
});
if (data.value.PublishPhoto == null) {
notification.info({
message: "系统提示:",
description: "记录不存在",
placement: "topRight",
});
data.value = new PublishPhotoData();
hasData.value = false;
return;
}
let userLoginProfile = useLoginProfileStore();
if (data.value.PublishPhoto.OwnerName != userLoginProfile.getUsername()) {
canAmend.value = false;
canDelete.value = false;
}
hasData.value = true;
};
const onReset = () => {
data.value = new PublishPhotoData();
data.value.Details = [];
publishName.value = "";
hasData.value = false;
};
const onViewPreview = async () => {
router.push({
name: "Previews",
params: { id: data.value.PublishPhoto.PublishName, mode: "view" },
});
};
const onCreate = () => {
onReset();
isEdit.value = true;
};
const onAmend = () => {
isEdit.value = true;
oldPublishName.value = unref(data.value.PublishPhoto.PublishName);
};
const onSave = async () => {
try {
loading.value = true;
if (!data.value.Details) data.value.Details = [];
if (!data.value.FamilyGroups) data.value.FamilyGroups = [];
if (data.value.PublishPhoto?.CreatedBy)
data.value = await publishPhotoService.Update(data.value);
else {
data.value = await publishPhotoService.Insert(data.value);
}
publishName.value = data.value.PublishPhoto.PublishName;
loading.value = false;
hasData.value = true;
isEdit.value = false;
} catch (error) {
loading.value = false;
console.log(error);
}
};
const onCancel = () => {
onReset();
if (oldPublishName.value && oldPublishName.value.length > 0) {
publishName.value = oldPublishName.value;
onSearch();
}
isEdit.value = false;
};
const onDelete = async () => {
try {
loading.value = true;
await publishPhotoService.Delete(data.value.PublishPhoto.PublishName);
onReset();
loading.value = false;
} catch (error) {
loading.value = false;
console.log(error);
}
};
const handleCance = async () => {};
const upSon = (index: number) => {
if (index > 0) {
const item = data.value.Details.splice(index, 1)[0];
data.value.Details.splice(index - 1, 0, item);
}
};
const downSon = (index: number) => {
if (index < data.value.Details.length) {
const item = data.value.Details.splice(index, 1)[0];
data.value.Details.splice(index + 1, 0, item);
}
};
const deleteSon = (key: number) => {
data.value.Details = data.value.Details.filter(
(item) => item.DetailId !== key,
);
};
const handleSelect = async () => {
if (enquiry.value) {
if (enquiry.value.keys.length > 0) {
//查询弹出
if (showModalType.value == 0) {
publishName.value = enquiry.value.keys[0].PublishName;
onSearch();
}
showModal.value = false;
} else {
notification.info({
message: "系统提示:",
description: "请选择一条记录",
placement: "topRight",
});
}
}
};
const handleSelectFamilyGroup = async () => {
if (groupEnquiry.value) {
if (groupEnquiry.value.keys.length > 0) {
//查询弹出
if (!data.value.FamilyGroups) data.value.FamilyGroups = [];
groupEnquiry.value.keys.forEach((element: FamilyGroupEntity) => {
if (
data.value.FamilyGroups.filter(
(item) => item.FamilyName == element.FamilyName,
).length == 0
) {
let ent: PublishPhotoFamilyGroupDisplayData =
new PublishPhotoFamilyGroupDisplayData();
ent.FamilyName = element.FamilyName;
ent.FamilyLocalName = element.FamilyLocalName;
ent.Notice = element.Notice;
data.value.FamilyGroups.push(ent);
}
});
showModalFamilyGroup.value = false;
} else {
notification.info({
message: "系统提示:",
description: "请选择一条记录",
placement: "topRight",
});
}
}
};
const addFamilyGroup = (event: MouseEvent) => {
showModalFamilyGroup.value = true;
// If you don't want click extra trigger collapse, you can prevent this:
event.stopPropagation();
};
const deleteFamilyGroup = (key: string) => {
data.value.FamilyGroups = data.value.FamilyGroups.filter(
(item) => item.FamilyName !== key,
);
};
const onViewActorOperation = (familyName: string) => {
router.push({
name: "FamilyGroupOperation",
params: { id: familyName, mode: "view" },
});
};
const columnFamilyGroups = ref([
{
title: "序号",
dataIndex: "index",
width: "10%",
align: "center",
fixed: "left",
sequence: 0,
hidden: "N",
format: "",
},
{
title: "群组代碼",
dataIndex: FamilyGroupEntity.FAMILY_NAME,
width: "30%",
sequence: 1,
hidden: "N",
},
{
title: "群组名称",
dataIndex: FamilyGroupEntity.FAMILY_LOCAL_NAME,
width: "30%",
sequence: 2,
hidden: "N",
},
{
title: "群组描述",
dataIndex: FamilyGroupEntity.NOTICE,
width: "30%",
sequence: 2,
hidden: "N",
},
{
title: "",
dataIndex: "operation",
width: "5%",
sequence: 2,
hidden: "N",
},
]);
</script>
<style lang="less">
.page-container {
margin-right: 0px;
}
.page-header {
padding-top: 4px;
padding-bottom: 8px;
padding-right: 12px;
border-bottom: 1px solid silver;
}
.page-header .ant-input-search .ant-input {
border-radius: 0;
border-left: 0;
text-align: left;
}
.page-main {
overflow-y: auto;
padding-top: 24px;
padding-bottom: 4px;
padding-right: 32px;
padding-left: 12px;
}
.page-footer {
z-index: 999;
padding-left: 8px;
padding-right: 18px;
padding-top: 8px;
width: 100%;
position: fixed;
bottom: 8px;
border-top: 1px solid silver;
}
</style>