新增:并入shop、cms、oa三大模块代码

This commit is contained in:
2024-09-13 00:10:29 +08:00
parent 0068553e35
commit ea5a48fa29
424 changed files with 64497 additions and 67 deletions

View File

@@ -0,0 +1,276 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑广告位' : '添加广告位'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="页面ID" name="designId">
<a-input
allow-clear
placeholder="请输入页面ID"
v-model:value="form.designId"
/>
</a-form-item>
<a-form-item label="广告类型" name="adType">
<a-input
allow-clear
placeholder="请输入广告类型"
v-model:value="form.adType"
/>
</a-form-item>
<a-form-item label="广告位名称" name="name">
<a-input
allow-clear
placeholder="请输入广告位名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="宽" name="width">
<a-input
allow-clear
placeholder="请输入宽"
v-model:value="form.width"
/>
</a-form-item>
<a-form-item label="高" name="height">
<a-input
allow-clear
placeholder="请输入高"
v-model:value="form.height"
/>
</a-form-item>
<a-form-item label="广告图片" name="images">
<a-input
allow-clear
placeholder="请输入广告图片"
v-model:value="form.images"
/>
</a-form-item>
<a-form-item label="路由/链接地址" name="path">
<a-input
allow-clear
placeholder="请输入路由/链接地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="页面ID" name="pageId">
<a-input
allow-clear
placeholder="请输入页面ID"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="页面名称" name="pageName">
<a-input
allow-clear
placeholder="请输入页面名称"
v-model:value="form.pageName"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsAd, updateCmsAd } from '@/api/cms/cmsAd';
import { CmsAd } from '@/api/cms/cmsAd/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsAd | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsAd>({
adId: undefined,
designId: undefined,
adType: undefined,
name: undefined,
width: undefined,
height: undefined,
images: undefined,
path: undefined,
userId: undefined,
pageId: undefined,
pageName: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsAdId: undefined,
cmsAdName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsAdName: [
{
required: true,
type: 'string',
message: '请填写广告位名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsAd : addCmsAd;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,299 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsAdId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsAdEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsAdEdit from './components/cmsAdEdit.vue';
import { pageCmsAd, removeCmsAd, removeBatchCmsAd } from '@/api/cms/cmsAd';
import type { CmsAd, CmsAdParam } from '@/api/cms/cmsAd/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsAd[]>([]);
// 当前编辑数据
const current = ref<CmsAd | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsAd({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'adId',
key: 'adId',
align: 'center',
width: 90,
},
{
title: '页面ID',
dataIndex: 'designId',
key: 'designId',
align: 'center',
},
{
title: '广告类型',
dataIndex: 'adType',
key: 'adType',
align: 'center',
},
{
title: '广告位名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '宽',
dataIndex: 'width',
key: 'width',
align: 'center',
},
{
title: '高',
dataIndex: 'height',
key: 'height',
align: 'center',
},
{
title: '广告图片',
dataIndex: 'images',
key: 'images',
align: 'center',
},
{
title: '路由/链接地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '页面ID',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '页面名称',
dataIndex: 'pageName',
key: 'pageName',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsAdParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsAd) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsAd) => {
const hide = message.loading('请求中..', 0);
removeCmsAd(row.cmsAdId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsAd(selection.value.map((d) => d.cmsAdId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsAd) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsAd'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,220 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑广告图片' : '添加广告图片'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="广告标题" name="title">
<a-input
allow-clear
placeholder="请输入广告标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="图片地址" name="path">
<a-input
allow-clear
placeholder="请输入图片地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="链接地址" name="url">
<a-input
allow-clear
placeholder="请输入链接地址"
v-model:value="form.url"
/>
</a-form-item>
<a-form-item label="广告位ID" name="adId">
<a-input
allow-clear
placeholder="请输入广告位ID"
v-model:value="form.adId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsAdRecord, updateCmsAdRecord } from '@/api/cms/cmsAdRecord';
import { CmsAdRecord } from '@/api/cms/cmsAdRecord/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsAdRecord | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsAdRecord>({
adRecordId: undefined,
title: undefined,
path: undefined,
url: undefined,
adId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsAdRecordId: undefined,
cmsAdRecordName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsAdRecordName: [
{
required: true,
type: 'string',
message: '请填写广告图片名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsAdRecord : addCmsAdRecord;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,257 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsAdRecordId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsAdRecordEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsAdRecordEdit from './components/cmsAdRecordEdit.vue';
import { pageCmsAdRecord, removeCmsAdRecord, removeBatchCmsAdRecord } from '@/api/cms/cmsAdRecord';
import type { CmsAdRecord, CmsAdRecordParam } from '@/api/cms/cmsAdRecord/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsAdRecord[]>([]);
// 当前编辑数据
const current = ref<CmsAdRecord | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsAdRecord({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'adRecordId',
key: 'adRecordId',
align: 'center',
width: 90,
},
{
title: '广告标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '图片地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '链接地址',
dataIndex: 'url',
key: 'url',
align: 'center',
},
{
title: '广告位ID',
dataIndex: 'adId',
key: 'adId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsAdRecordParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsAdRecord) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsAdRecord) => {
const hide = message.loading('请求中..', 0);
removeCmsAdRecord(row.cmsAdRecordId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsAdRecord(selection.value.map((d) => d.cmsAdRecordId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsAdRecord) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsAdRecord'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,400 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文章' : '添加文章'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文章标题" name="title">
<a-input
allow-clear
placeholder="请输入文章标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="文章类型 0常规 1视频" name="type">
<a-input
allow-clear
placeholder="请输入文章类型 0常规 1视频"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="文章模型" name="model">
<a-input
allow-clear
placeholder="请输入文章模型"
v-model:value="form.model"
/>
</a-form-item>
<a-form-item label="列表显示方式(10小图展示 20大图展示)" name="showType">
<a-input
allow-clear
placeholder="请输入列表显示方式(10小图展示 20大图展示)"
v-model:value="form.showType"
/>
</a-form-item>
<a-form-item label="话题" name="topic">
<a-input
allow-clear
placeholder="请输入话题"
v-model:value="form.topic"
/>
</a-form-item>
<a-form-item label="文章分类ID" name="categoryId">
<a-input
allow-clear
placeholder="请输入文章分类ID"
v-model:value="form.categoryId"
/>
</a-form-item>
<a-form-item
label="封面图"
name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="来源" name="source">
<a-input
allow-clear
placeholder="请输入来源"
v-model:value="form.source"
/>
</a-form-item>
<a-form-item label="虚拟阅读量(仅用作展示)" name="virtualViews">
<a-input
allow-clear
placeholder="请输入虚拟阅读量(仅用作展示)"
v-model:value="form.virtualViews"
/>
</a-form-item>
<a-form-item label="实际阅读量" name="actualViews">
<a-input
allow-clear
placeholder="请输入实际阅读量"
v-model:value="form.actualViews"
/>
</a-form-item>
<a-form-item label="发布来源客户端 (APP、H5、小程序等)" name="platform">
<a-input
allow-clear
placeholder="请输入发布来源客户端 (APP、H5、小程序等)"
v-model:value="form.platform"
/>
</a-form-item>
<a-form-item label="文章附件" name="files">
<a-input
allow-clear
placeholder="请输入文章附件"
v-model:value="form.files"
/>
</a-form-item>
<a-form-item label="视频地址" name="video">
<a-input
allow-clear
placeholder="请输入视频地址"
v-model:value="form.video"
/>
</a-form-item>
<a-form-item label="接受的文件类型" name="accept">
<a-input
allow-clear
placeholder="请输入接受的文件类型"
v-model:value="form.accept"
/>
</a-form-item>
<a-form-item label="经度" name="longitude">
<a-input
allow-clear
placeholder="请输入经度"
v-model:value="form.longitude"
/>
</a-form-item>
<a-form-item label="纬度" name="latitude">
<a-input
allow-clear
placeholder="请输入纬度"
v-model:value="form.latitude"
/>
</a-form-item>
<a-form-item label="所在省份" name="province">
<a-input
allow-clear
placeholder="请输入所在省份"
v-model:value="form.province"
/>
</a-form-item>
<a-form-item label="所在城市" name="city">
<a-input
allow-clear
placeholder="请输入所在城市"
v-model:value="form.city"
/>
</a-form-item>
<a-form-item label="所在辖区" name="region">
<a-input
allow-clear
placeholder="请输入所在辖区"
v-model:value="form.region"
/>
</a-form-item>
<a-form-item label="街道地址" name="address">
<a-input
allow-clear
placeholder="请输入街道地址"
v-model:value="form.address"
/>
</a-form-item>
<a-form-item label="点赞数" name="likes">
<a-input
allow-clear
placeholder="请输入点赞数"
v-model:value="form.likes"
/>
</a-form-item>
<a-form-item label="评论数" name="commentNumbers">
<a-input
allow-clear
placeholder="请输入评论数"
v-model:value="form.commentNumbers"
/>
</a-form-item>
<a-form-item label="提醒谁看" name="toUsers">
<a-input
allow-clear
placeholder="请输入提醒谁看"
v-model:value="form.toUsers"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0已发布, 1待审核 2已驳回 3违规内容" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticle, updateCmsArticle } from '@/api/cms/cmsArticle';
import { CmsArticle } from '@/api/cms/cmsArticle/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticle | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticle>({
articleId: undefined,
title: undefined,
type: undefined,
model: undefined,
showType: undefined,
topic: undefined,
categoryId: undefined,
image: undefined,
source: undefined,
virtualViews: undefined,
actualViews: undefined,
platform: undefined,
files: undefined,
video: undefined,
accept: undefined,
longitude: undefined,
latitude: undefined,
province: undefined,
city: undefined,
region: undefined,
address: undefined,
likes: undefined,
commentNumbers: undefined,
toUsers: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
cmsArticleId: undefined,
cmsArticleName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleName: [
{
required: true,
type: 'string',
message: '请填写文章名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticle : addCmsArticle;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,389 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleEdit from './components/cmsArticleEdit.vue';
import { pageCmsArticle, removeCmsArticle, removeBatchCmsArticle } from '@/api/cms/cmsArticle';
import type { CmsArticle, CmsArticleParam } from '@/api/cms/cmsArticle/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticle[]>([]);
// 当前编辑数据
const current = ref<CmsArticle | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticle({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
width: 90,
},
{
title: '文章标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '文章类型 0常规 1视频',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '文章模型',
dataIndex: 'model',
key: 'model',
align: 'center',
},
{
title: '列表显示方式(10小图展示 20大图展示)',
dataIndex: 'showType',
key: 'showType',
align: 'center',
},
{
title: '话题',
dataIndex: 'topic',
key: 'topic',
align: 'center',
},
{
title: '文章分类ID',
dataIndex: 'categoryId',
key: 'categoryId',
align: 'center',
},
{
title: '封面图',
dataIndex: 'image',
key: 'image',
align: 'center',
},
{
title: '来源',
dataIndex: 'source',
key: 'source',
align: 'center',
},
{
title: '虚拟阅读量(仅用作展示)',
dataIndex: 'virtualViews',
key: 'virtualViews',
align: 'center',
},
{
title: '实际阅读量',
dataIndex: 'actualViews',
key: 'actualViews',
align: 'center',
},
{
title: '发布来源客户端 (APP、H5、小程序等)',
dataIndex: 'platform',
key: 'platform',
align: 'center',
},
{
title: '文章附件',
dataIndex: 'files',
key: 'files',
align: 'center',
},
{
title: '视频地址',
dataIndex: 'video',
key: 'video',
align: 'center',
},
{
title: '接受的文件类型',
dataIndex: 'accept',
key: 'accept',
align: 'center',
},
{
title: '经度',
dataIndex: 'longitude',
key: 'longitude',
align: 'center',
},
{
title: '纬度',
dataIndex: 'latitude',
key: 'latitude',
align: 'center',
},
{
title: '所在省份',
dataIndex: 'province',
key: 'province',
align: 'center',
},
{
title: '所在城市',
dataIndex: 'city',
key: 'city',
align: 'center',
},
{
title: '所在辖区',
dataIndex: 'region',
key: 'region',
align: 'center',
},
{
title: '街道地址',
dataIndex: 'address',
key: 'address',
align: 'center',
},
{
title: '点赞数',
dataIndex: 'likes',
key: 'likes',
align: 'center',
},
{
title: '评论数',
dataIndex: 'commentNumbers',
key: 'commentNumbers',
align: 'center',
},
{
title: '提醒谁看',
dataIndex: 'toUsers',
key: 'toUsers',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0已发布, 1待审核 2已驳回 3违规内容',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticle) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticle) => {
const hide = message.loading('请求中..', 0);
removeCmsArticle(row.cmsArticleId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticle(selection.value.map((d) => d.cmsArticleId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticle) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticle'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,312 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文章分类表' : '添加文章分类表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="分类标识" name="categoryCode">
<a-input
allow-clear
placeholder="请输入分类标识"
v-model:value="form.categoryCode"
/>
</a-form-item>
<a-form-item label="分类名称" name="title">
<a-input
allow-clear
placeholder="请输入分类名称"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="类型 0列表 1单页 2外链" name="type">
<a-input
allow-clear
placeholder="请输入类型 0列表 1单页 2外链"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item
label="分类图片"
name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="上级分类ID" name="parentId">
<a-input
allow-clear
placeholder="请输入上级分类ID"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="路由/链接地址" name="path">
<a-input
allow-clear
placeholder="请输入路由/链接地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="组件路径" name="component">
<a-input
allow-clear
placeholder="请输入组件路径"
v-model:value="form.component"
/>
</a-form-item>
<a-form-item label="绑定的页面" name="pageId">
<a-input
allow-clear
placeholder="请输入绑定的页面"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="文章数量" name="count">
<a-input
allow-clear
placeholder="请输入文章数量"
v-model:value="form.count"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)" name="hide">
<a-input
allow-clear
placeholder="请输入是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)"
v-model:value="form.hide"
/>
</a-form-item>
<a-form-item label="是否推荐" name="recommend">
<a-input
allow-clear
placeholder="请输入是否推荐"
v-model:value="form.recommend"
/>
</a-form-item>
<a-form-item label="是否显示在首页" name="showIndex">
<a-input
allow-clear
placeholder="请输入是否显示在首页"
v-model:value="form.showIndex"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1禁用" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticleCategory, updateCmsArticleCategory } from '@/api/cms/cmsArticleCategory';
import { CmsArticleCategory } from '@/api/cms/cmsArticleCategory/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticleCategory | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticleCategory>({
categoryId: undefined,
categoryCode: undefined,
title: undefined,
type: undefined,
image: undefined,
parentId: undefined,
path: undefined,
component: undefined,
pageId: undefined,
userId: undefined,
count: undefined,
sortNumber: undefined,
comments: undefined,
hide: undefined,
recommend: undefined,
showIndex: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
cmsArticleCategoryId: undefined,
cmsArticleCategoryName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleCategoryName: [
{
required: true,
type: 'string',
message: '请填写文章分类表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticleCategory : addCmsArticleCategory;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,323 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleCategoryId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleCategoryEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleCategoryEdit from './components/cmsArticleCategoryEdit.vue';
import { pageCmsArticleCategory, removeCmsArticleCategory, removeBatchCmsArticleCategory } from '@/api/cms/cmsArticleCategory';
import type { CmsArticleCategory, CmsArticleCategoryParam } from '@/api/cms/cmsArticleCategory/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticleCategory[]>([]);
// 当前编辑数据
const current = ref<CmsArticleCategory | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticleCategory({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '文章分类ID',
dataIndex: 'categoryId',
key: 'categoryId',
align: 'center',
width: 90,
},
{
title: '分类标识',
dataIndex: 'categoryCode',
key: 'categoryCode',
align: 'center',
},
{
title: '分类名称',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '类型 0列表 1单页 2外链',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '分类图片',
dataIndex: 'image',
key: 'image',
align: 'center',
},
{
title: '上级分类ID',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '路由/链接地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '组件路径',
dataIndex: 'component',
key: 'component',
align: 'center',
},
{
title: '绑定的页面',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '文章数量',
dataIndex: 'count',
key: 'count',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)',
dataIndex: 'hide',
key: 'hide',
align: 'center',
},
{
title: '是否推荐',
dataIndex: 'recommend',
key: 'recommend',
align: 'center',
},
{
title: '是否显示在首页',
dataIndex: 'showIndex',
key: 'showIndex',
align: 'center',
},
{
title: '状态, 0正常, 1禁用',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleCategoryParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticleCategory) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticleCategory) => {
const hide = message.loading('请求中..', 0);
removeCmsArticleCategory(row.cmsArticleCategoryId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticleCategory(selection.value.map((d) => d.cmsArticleCategoryId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticleCategory) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticleCategory'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,268 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文章评论表' : '添加文章评论表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文章ID" name="articleId">
<a-input
allow-clear
placeholder="请输入文章ID"
v-model:value="form.articleId"
/>
</a-form-item>
<a-form-item label="评分 (10好评 20中评 30差评)" name="score">
<a-input
allow-clear
placeholder="请输入评分 (10好评 20中评 30差评)"
v-model:value="form.score"
/>
</a-form-item>
<a-form-item label="评价内容" name="content">
<a-input
allow-clear
placeholder="请输入评价内容"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="是否为图片评价" name="isPicture">
<a-input
allow-clear
placeholder="请输入是否为图片评价"
v-model:value="form.isPicture"
/>
</a-form-item>
<a-form-item label="评论者ID" name="userId">
<a-input
allow-clear
placeholder="请输入评论者ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="被评价者ID" name="toUserId">
<a-input
allow-clear
placeholder="请输入被评价者ID"
v-model:value="form.toUserId"
/>
</a-form-item>
<a-form-item label="回复的评论ID" name="replyCommentId">
<a-input
allow-clear
placeholder="请输入回复的评论ID"
v-model:value="form.replyCommentId"
/>
</a-form-item>
<a-form-item label="回复者ID" name="replyUserId">
<a-input
allow-clear
placeholder="请输入回复者ID"
v-model:value="form.replyUserId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0未读, 1已读" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticleComment, updateCmsArticleComment } from '@/api/cms/cmsArticleComment';
import { CmsArticleComment } from '@/api/cms/cmsArticleComment/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticleComment | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticleComment>({
commentId: undefined,
articleId: undefined,
score: undefined,
content: undefined,
isPicture: undefined,
userId: undefined,
toUserId: undefined,
replyCommentId: undefined,
replyUserId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
cmsArticleCommentId: undefined,
cmsArticleCommentName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleCommentName: [
{
required: true,
type: 'string',
message: '请填写文章评论表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticleComment : addCmsArticleComment;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,293 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleCommentId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleCommentEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleCommentEdit from './components/cmsArticleCommentEdit.vue';
import { pageCmsArticleComment, removeCmsArticleComment, removeBatchCmsArticleComment } from '@/api/cms/cmsArticleComment';
import type { CmsArticleComment, CmsArticleCommentParam } from '@/api/cms/cmsArticleComment/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticleComment[]>([]);
// 当前编辑数据
const current = ref<CmsArticleComment | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticleComment({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '评价ID',
dataIndex: 'commentId',
key: 'commentId',
align: 'center',
width: 90,
},
{
title: '文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
},
{
title: '评分 (10好评 20中评 30差评)',
dataIndex: 'score',
key: 'score',
align: 'center',
},
{
title: '评价内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '是否为图片评价',
dataIndex: 'isPicture',
key: 'isPicture',
align: 'center',
},
{
title: '评论者ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '被评价者ID',
dataIndex: 'toUserId',
key: 'toUserId',
align: 'center',
},
{
title: '回复的评论ID',
dataIndex: 'replyCommentId',
key: 'replyCommentId',
align: 'center',
},
{
title: '回复者ID',
dataIndex: 'replyUserId',
key: 'replyUserId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0未读, 1已读',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleCommentParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticleComment) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticleComment) => {
const hide = message.loading('请求中..', 0);
removeCmsArticleComment(row.cmsArticleCommentId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticleComment(selection.value.map((d) => d.cmsArticleCommentId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticleComment) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticleComment'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,178 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文章记录表' : '添加文章记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文章ID" name="articleId">
<a-input
allow-clear
placeholder="请输入文章ID"
v-model:value="form.articleId"
/>
</a-form-item>
<a-form-item label="文章内容" name="content">
<a-input
allow-clear
placeholder="请输入文章内容"
v-model:value="form.content"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticleContent, updateCmsArticleContent } from '@/api/cms/cmsArticleContent';
import { CmsArticleContent } from '@/api/cms/cmsArticleContent/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticleContent | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticleContent>({
id: undefined,
articleId: undefined,
content: undefined,
tenantId: undefined,
createTime: undefined,
cmsArticleContentId: undefined,
cmsArticleContentName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleContentName: [
{
required: true,
type: 'string',
message: '请填写文章记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticleContent : addCmsArticleContent;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,227 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleContentId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleContentEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleContentEdit from './components/cmsArticleContentEdit.vue';
import { pageCmsArticleContent, removeCmsArticleContent, removeBatchCmsArticleContent } from '@/api/cms/cmsArticleContent';
import type { CmsArticleContent, CmsArticleContentParam } from '@/api/cms/cmsArticleContent/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticleContent[]>([]);
// 当前编辑数据
const current = ref<CmsArticleContent | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticleContent({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
},
{
title: '文章内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleContentParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticleContent) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticleContent) => {
const hide = message.loading('请求中..', 0);
removeCmsArticleContent(row.cmsArticleContentId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticleContent(selection.value.map((d) => d.cmsArticleContentId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticleContent) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticleContent'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,178 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑点赞文章' : '添加点赞文章'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文章ID" name="articleId">
<a-input
allow-clear
placeholder="请输入文章ID"
v-model:value="form.articleId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticleCount, updateCmsArticleCount } from '@/api/cms/cmsArticleCount';
import { CmsArticleCount } from '@/api/cms/cmsArticleCount/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticleCount | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticleCount>({
id: undefined,
articleId: undefined,
userId: undefined,
tenantId: undefined,
createTime: undefined,
cmsArticleCountId: undefined,
cmsArticleCountName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleCountName: [
{
required: true,
type: 'string',
message: '请填写点赞文章名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticleCount : addCmsArticleCount;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,227 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleCountId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleCountEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleCountEdit from './components/cmsArticleCountEdit.vue';
import { pageCmsArticleCount, removeCmsArticleCount, removeBatchCmsArticleCount } from '@/api/cms/cmsArticleCount';
import type { CmsArticleCount, CmsArticleCountParam } from '@/api/cms/cmsArticleCount/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticleCount[]>([]);
// 当前编辑数据
const current = ref<CmsArticleCount | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticleCount({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '主键ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleCountParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticleCount) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticleCount) => {
const hide = message.loading('请求中..', 0);
removeCmsArticleCount(row.cmsArticleCountId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticleCount(selection.value.map((d) => d.cmsArticleCountId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticleCount) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticleCount'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,178 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑点赞文章' : '添加点赞文章'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文章ID" name="articleId">
<a-input
allow-clear
placeholder="请输入文章ID"
v-model:value="form.articleId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsArticleLike, updateCmsArticleLike } from '@/api/cms/cmsArticleLike';
import { CmsArticleLike } from '@/api/cms/cmsArticleLike/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsArticleLike | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsArticleLike>({
id: undefined,
articleId: undefined,
userId: undefined,
tenantId: undefined,
createTime: undefined,
cmsArticleLikeId: undefined,
cmsArticleLikeName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsArticleLikeName: [
{
required: true,
type: 'string',
message: '请填写点赞文章名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsArticleLike : addCmsArticleLike;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,227 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsArticleLikeId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsArticleLikeEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsArticleLikeEdit from './components/cmsArticleLikeEdit.vue';
import { pageCmsArticleLike, removeCmsArticleLike, removeBatchCmsArticleLike } from '@/api/cms/cmsArticleLike';
import type { CmsArticleLike, CmsArticleLikeParam } from '@/api/cms/cmsArticleLike/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsArticleLike[]>([]);
// 当前编辑数据
const current = ref<CmsArticleLike | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsArticleLike({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '主键ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsArticleLikeParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsArticleLike) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsArticleLike) => {
const hide = message.loading('请求中..', 0);
removeCmsArticleLike(row.cmsArticleLikeId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsArticleLike(selection.value.map((d) => d.cmsArticleLikeId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsArticleLike) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsArticleLike'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,252 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑组件' : '添加组件'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="组件标题" name="title">
<a-input
allow-clear
placeholder="请输入组件标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="关联导航ID" name="navigationId">
<a-input
allow-clear
placeholder="请输入关联导航ID"
v-model:value="form.navigationId"
/>
</a-form-item>
<a-form-item label="组件类型" name="type">
<a-input
allow-clear
placeholder="请输入组件类型"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="页面关键词" name="keywords">
<a-input
allow-clear
placeholder="请输入页面关键词"
v-model:value="form.keywords"
/>
</a-form-item>
<a-form-item label="页面描述" name="description">
<a-input
allow-clear
placeholder="请输入页面描述"
v-model:value="form.description"
/>
</a-form-item>
<a-form-item label="组件路径" name="path">
<a-input
allow-clear
placeholder="请输入组件路径"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="组件图标" name="icon">
<a-input
allow-clear
placeholder="请输入组件图标"
v-model:value="form.icon"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsComponents, updateCmsComponents } from '@/api/cms/cmsComponents';
import { CmsComponents } from '@/api/cms/cmsComponents/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsComponents | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsComponents>({
id: undefined,
title: undefined,
navigationId: undefined,
type: undefined,
keywords: undefined,
description: undefined,
path: undefined,
icon: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsComponentsId: undefined,
cmsComponentsName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsComponentsName: [
{
required: true,
type: 'string',
message: '请填写组件名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsComponents : addCmsComponents;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,281 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsComponentsId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsComponentsEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsComponentsEdit from './components/cmsComponentsEdit.vue';
import { pageCmsComponents, removeCmsComponents, removeBatchCmsComponents } from '@/api/cms/cmsComponents';
import type { CmsComponents, CmsComponentsParam } from '@/api/cms/cmsComponents/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsComponents[]>([]);
// 当前编辑数据
const current = ref<CmsComponents | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsComponents({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '组件标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '关联导航ID',
dataIndex: 'navigationId',
key: 'navigationId',
align: 'center',
},
{
title: '组件类型',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '页面关键词',
dataIndex: 'keywords',
key: 'keywords',
align: 'center',
},
{
title: '页面描述',
dataIndex: 'description',
key: 'description',
align: 'center',
},
{
title: '组件路径',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '组件图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsComponentsParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsComponents) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsComponents) => {
const hide = message.loading('请求中..', 0);
removeCmsComponents(row.cmsComponentsId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsComponents(selection.value.map((d) => d.cmsComponentsId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsComponents) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsComponents'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,300 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑页面管理记录表' : '添加页面管理记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="页面标题" name="name">
<a-input
allow-clear
placeholder="请输入页面标题"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="所属栏目ID" name="categoryId">
<a-input
allow-clear
placeholder="请输入所属栏目ID"
v-model:value="form.categoryId"
/>
</a-form-item>
<a-form-item label="页面关键词" name="keywords">
<a-input
allow-clear
placeholder="请输入页面关键词"
v-model:value="form.keywords"
/>
</a-form-item>
<a-form-item label="页面描述" name="description">
<a-input
allow-clear
placeholder="请输入页面描述"
v-model:value="form.description"
/>
</a-form-item>
<a-form-item label="缩列图" name="photo">
<a-input
allow-clear
placeholder="请输入缩列图"
v-model:value="form.photo"
/>
</a-form-item>
<a-form-item label="购买链接" name="buyUrl">
<a-input
allow-clear
placeholder="请输入购买链接"
v-model:value="form.buyUrl"
/>
</a-form-item>
<a-form-item label="页面样式" name="style">
<a-input
allow-clear
placeholder="请输入页面样式"
v-model:value="form.style"
/>
</a-form-item>
<a-form-item label="页面内容" name="content">
<a-input
allow-clear
placeholder="请输入页面内容"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="是否开启布局" name="showLayout">
<a-input
allow-clear
placeholder="请输入是否开启布局"
v-model:value="form.showLayout"
/>
</a-form-item>
<a-form-item label="页面布局" name="layout">
<a-input
allow-clear
placeholder="请输入页面布局"
v-model:value="form.layout"
/>
</a-form-item>
<a-form-item label="上级id, 0是顶级" name="parentId">
<a-input
allow-clear
placeholder="请输入上级id, 0是顶级"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="设为首页" name="home">
<a-input
allow-clear
placeholder="请输入设为首页"
v-model:value="form.home"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDesign, updateCmsDesign } from '@/api/cms/cmsDesign';
import { CmsDesign } from '@/api/cms/cmsDesign/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDesign | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDesign>({
pageId: undefined,
name: undefined,
categoryId: undefined,
keywords: undefined,
description: undefined,
photo: undefined,
buyUrl: undefined,
style: undefined,
content: undefined,
showLayout: undefined,
layout: undefined,
parentId: undefined,
userId: undefined,
home: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsDesignId: undefined,
cmsDesignName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDesignName: [
{
required: true,
type: 'string',
message: '请填写页面管理记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDesign : addCmsDesign;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,317 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDesignId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDesignEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDesignEdit from './components/cmsDesignEdit.vue';
import { pageCmsDesign, removeCmsDesign, removeBatchCmsDesign } from '@/api/cms/cmsDesign';
import type { CmsDesign, CmsDesignParam } from '@/api/cms/cmsDesign/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDesign[]>([]);
// 当前编辑数据
const current = ref<CmsDesign | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDesign({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
width: 90,
},
{
title: '页面标题',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '所属栏目ID',
dataIndex: 'categoryId',
key: 'categoryId',
align: 'center',
},
{
title: '页面关键词',
dataIndex: 'keywords',
key: 'keywords',
align: 'center',
},
{
title: '页面描述',
dataIndex: 'description',
key: 'description',
align: 'center',
},
{
title: '缩列图',
dataIndex: 'photo',
key: 'photo',
align: 'center',
},
{
title: '购买链接',
dataIndex: 'buyUrl',
key: 'buyUrl',
align: 'center',
},
{
title: '页面样式',
dataIndex: 'style',
key: 'style',
align: 'center',
},
{
title: '页面内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '是否开启布局',
dataIndex: 'showLayout',
key: 'showLayout',
align: 'center',
},
{
title: '页面布局',
dataIndex: 'layout',
key: 'layout',
align: 'center',
},
{
title: '上级id, 0是顶级',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '设为首页',
dataIndex: 'home',
key: 'home',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDesignParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDesign) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDesign) => {
const hide = message.loading('请求中..', 0);
removeCmsDesign(row.cmsDesignId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDesign(selection.value.map((d) => d.cmsDesignId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDesign) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDesign'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,268 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑页面组件表' : '添加页面组件表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="关联导航ID" name="navigationId">
<a-input
allow-clear
placeholder="请输入关联导航ID"
v-model:value="form.navigationId"
/>
</a-form-item>
<a-form-item label="组件" name="title">
<a-input
allow-clear
placeholder="请输入组件"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="组件标识" name="dictCode">
<a-input
allow-clear
placeholder="请输入组件标识"
v-model:value="form.dictCode"
/>
</a-form-item>
<a-form-item label="组件样式" name="styles">
<a-input
allow-clear
placeholder="请输入组件样式"
v-model:value="form.styles"
/>
</a-form-item>
<a-form-item label="卡片阴影显示时机" name="shadow">
<a-input
allow-clear
placeholder="请输入卡片阴影显示时机"
v-model:value="form.shadow"
/>
</a-form-item>
<a-form-item label="页面关键词" name="keywords">
<a-input
allow-clear
placeholder="请输入页面关键词"
v-model:value="form.keywords"
/>
</a-form-item>
<a-form-item label="页面描述" name="description">
<a-input
allow-clear
placeholder="请输入页面描述"
v-model:value="form.description"
/>
</a-form-item>
<a-form-item label="页面路由地址" name="path">
<a-input
allow-clear
placeholder="请输入页面路由地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="缩列图" name="photo">
<a-input
allow-clear
placeholder="请输入缩列图"
v-model:value="form.photo"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDesignRecord, updateCmsDesignRecord } from '@/api/cms/cmsDesignRecord';
import { CmsDesignRecord } from '@/api/cms/cmsDesignRecord/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDesignRecord | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDesignRecord>({
id: undefined,
navigationId: undefined,
title: undefined,
dictCode: undefined,
styles: undefined,
shadow: undefined,
keywords: undefined,
description: undefined,
path: undefined,
photo: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsDesignRecordId: undefined,
cmsDesignRecordName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDesignRecordName: [
{
required: true,
type: 'string',
message: '请填写页面组件表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDesignRecord : addCmsDesignRecord;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,293 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDesignRecordId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDesignRecordEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDesignRecordEdit from './components/cmsDesignRecordEdit.vue';
import { pageCmsDesignRecord, removeCmsDesignRecord, removeBatchCmsDesignRecord } from '@/api/cms/cmsDesignRecord';
import type { CmsDesignRecord, CmsDesignRecordParam } from '@/api/cms/cmsDesignRecord/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDesignRecord[]>([]);
// 当前编辑数据
const current = ref<CmsDesignRecord | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDesignRecord({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '关联导航ID',
dataIndex: 'navigationId',
key: 'navigationId',
align: 'center',
},
{
title: '组件',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '组件标识',
dataIndex: 'dictCode',
key: 'dictCode',
align: 'center',
},
{
title: '组件样式',
dataIndex: 'styles',
key: 'styles',
align: 'center',
},
{
title: '卡片阴影显示时机',
dataIndex: 'shadow',
key: 'shadow',
align: 'center',
},
{
title: '页面关键词',
dataIndex: 'keywords',
key: 'keywords',
align: 'center',
},
{
title: '页面描述',
dataIndex: 'description',
key: 'description',
align: 'center',
},
{
title: '页面路由地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '缩列图',
dataIndex: 'photo',
key: 'photo',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDesignRecordParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDesignRecord) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDesignRecord) => {
const hide = message.loading('请求中..', 0);
removeCmsDesignRecord(row.cmsDesignRecordId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDesignRecord(selection.value.map((d) => d.cmsDesignRecordId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDesignRecord) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDesignRecord'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,260 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文档管理记录表' : '添加文档管理记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文档标题" name="title">
<a-input
allow-clear
placeholder="请输入文档标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="上级目录" name="parentId">
<a-input
allow-clear
placeholder="请输入上级目录"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="书籍ID" name="bookId">
<a-input
allow-clear
placeholder="请输入书籍ID"
v-model:value="form.bookId"
/>
</a-form-item>
<a-form-item label="可见性(public,private,protected)" name="visibility">
<a-input
allow-clear
placeholder="请输入可见性(public,private,protected)"
v-model:value="form.visibility"
/>
</a-form-item>
<a-form-item label="虚拟阅读量(仅用作展示)" name="virtualViews">
<a-input
allow-clear
placeholder="请输入虚拟阅读量(仅用作展示)"
v-model:value="form.virtualViews"
/>
</a-form-item>
<a-form-item label="实际阅读量" name="actualViews">
<a-input
allow-clear
placeholder="请输入实际阅读量"
v-model:value="form.actualViews"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDocs, updateCmsDocs } from '@/api/cms/cmsDocs';
import { CmsDocs } from '@/api/cms/cmsDocs/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDocs | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDocs>({
docsId: undefined,
title: undefined,
parentId: undefined,
bookId: undefined,
visibility: undefined,
virtualViews: undefined,
actualViews: undefined,
userId: undefined,
comments: undefined,
sortNumber: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
cmsDocsId: undefined,
cmsDocsName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDocsName: [
{
required: true,
type: 'string',
message: '请填写文档管理记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDocs : addCmsDocs;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,287 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDocsId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDocsEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDocsEdit from './components/cmsDocsEdit.vue';
import { pageCmsDocs, removeCmsDocs, removeBatchCmsDocs } from '@/api/cms/cmsDocs';
import type { CmsDocs, CmsDocsParam } from '@/api/cms/cmsDocs/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDocs[]>([]);
// 当前编辑数据
const current = ref<CmsDocs | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDocs({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '文档ID',
dataIndex: 'docsId',
key: 'docsId',
align: 'center',
width: 90,
},
{
title: '文档标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '上级目录',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '书籍ID',
dataIndex: 'bookId',
key: 'bookId',
align: 'center',
},
{
title: '可见性(public,private,protected)',
dataIndex: 'visibility',
key: 'visibility',
align: 'center',
},
{
title: '虚拟阅读量(仅用作展示)',
dataIndex: 'virtualViews',
key: 'virtualViews',
align: 'center',
},
{
title: '实际阅读量',
dataIndex: 'actualViews',
key: 'actualViews',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDocsParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDocs) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDocs) => {
const hide = message.loading('请求中..', 0);
removeCmsDocs(row.cmsDocsId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDocs(selection.value.map((d) => d.cmsDocsId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDocs) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDocs'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,228 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑书籍记录表' : '添加书籍记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="书籍名称" name="name">
<a-input
allow-clear
placeholder="请输入书籍名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="书籍标识" name="code">
<a-input
allow-clear
placeholder="请输入书籍标识"
v-model:value="form.code"
/>
</a-form-item>
<a-form-item label="封面图" name="photo">
<a-input
allow-clear
placeholder="请输入封面图"
v-model:value="form.photo"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="文档内容" name="content">
<a-input
allow-clear
placeholder="请输入文档内容"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDocsBook, updateCmsDocsBook } from '@/api/cms/cmsDocsBook';
import { CmsDocsBook } from '@/api/cms/cmsDocsBook/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDocsBook | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDocsBook>({
bookId: undefined,
name: undefined,
code: undefined,
photo: undefined,
comments: undefined,
content: undefined,
sortNumber: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsDocsBookId: undefined,
cmsDocsBookName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDocsBookName: [
{
required: true,
type: 'string',
message: '请填写书籍记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDocsBook : addCmsDocsBook;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,263 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDocsBookId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDocsBookEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDocsBookEdit from './components/cmsDocsBookEdit.vue';
import { pageCmsDocsBook, removeCmsDocsBook, removeBatchCmsDocsBook } from '@/api/cms/cmsDocsBook';
import type { CmsDocsBook, CmsDocsBookParam } from '@/api/cms/cmsDocsBook/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDocsBook[]>([]);
// 当前编辑数据
const current = ref<CmsDocsBook | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDocsBook({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'bookId',
key: 'bookId',
align: 'center',
width: 90,
},
{
title: '书籍名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '书籍标识',
dataIndex: 'code',
key: 'code',
align: 'center',
},
{
title: '封面图',
dataIndex: 'photo',
key: 'photo',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '文档内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDocsBookParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDocsBook) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDocsBook) => {
const hide = message.loading('请求中..', 0);
removeCmsDocsBook(row.cmsDocsBookId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDocsBook(selection.value.map((d) => d.cmsDocsBookId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDocsBook) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDocsBook'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,178 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑文档内容记录表' : '添加文档内容记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="文档ID" name="docsId">
<a-input
allow-clear
placeholder="请输入文档ID"
v-model:value="form.docsId"
/>
</a-form-item>
<a-form-item label="文档内容" name="content">
<a-input
allow-clear
placeholder="请输入文档内容"
v-model:value="form.content"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDocsContent, updateCmsDocsContent } from '@/api/cms/cmsDocsContent';
import { CmsDocsContent } from '@/api/cms/cmsDocsContent/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDocsContent | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDocsContent>({
id: undefined,
docsId: undefined,
content: undefined,
tenantId: undefined,
createTime: undefined,
cmsDocsContentId: undefined,
cmsDocsContentName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDocsContentName: [
{
required: true,
type: 'string',
message: '请填写文档内容记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDocsContent : addCmsDocsContent;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,227 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDocsContentId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDocsContentEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDocsContentEdit from './components/cmsDocsContentEdit.vue';
import { pageCmsDocsContent, removeCmsDocsContent, removeBatchCmsDocsContent } from '@/api/cms/cmsDocsContent';
import type { CmsDocsContent, CmsDocsContentParam } from '@/api/cms/cmsDocsContent/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDocsContent[]>([]);
// 当前编辑数据
const current = ref<CmsDocsContent | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDocsContent({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '文档ID',
dataIndex: 'docsId',
key: 'docsId',
align: 'center',
},
{
title: '文档内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDocsContentParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDocsContent) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDocsContent) => {
const hide = message.loading('请求中..', 0);
removeCmsDocsContent(row.cmsDocsContentId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDocsContent(selection.value.map((d) => d.cmsDocsContentId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDocsContent) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDocsContent'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,251 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑网站域名记录表' : '添加网站域名记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="类型 0赠送域名 1绑定域名 " name="type">
<a-input
allow-clear
placeholder="请输入类型 0赠送域名 1绑定域名 "
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="域名" name="domain">
<a-input
allow-clear
placeholder="请输入域名"
v-model:value="form.domain"
/>
</a-form-item>
<a-form-item label="主机记录" name="hostName">
<a-input
allow-clear
placeholder="请输入主机记录"
v-model:value="form.hostName"
/>
</a-form-item>
<a-form-item label="记录值" name="hostValue">
<a-input
allow-clear
placeholder="请输入记录值"
v-model:value="form.hostValue"
/>
</a-form-item>
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="网站ID" name="websiteId">
<a-input
allow-clear
placeholder="请输入网站ID"
v-model:value="form.websiteId"
/>
</a-form-item>
<a-form-item label="租户ID" name="appId">
<a-input
allow-clear
placeholder="请输入租户ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsDomain, updateCmsDomain } from '@/api/cms/cmsDomain';
import { CmsDomain } from '@/api/cms/cmsDomain/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsDomain | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsDomain>({
id: undefined,
type: undefined,
domain: undefined,
hostName: undefined,
hostValue: undefined,
status: undefined,
sortNumber: undefined,
websiteId: undefined,
appId: undefined,
userId: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
cmsDomainId: undefined,
cmsDomainName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsDomainName: [
{
required: true,
type: 'string',
message: '请填写网站域名记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsDomain : addCmsDomain;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,281 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsDomainId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsDomainEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsDomainEdit from './components/cmsDomainEdit.vue';
import { pageCmsDomain, removeCmsDomain, removeBatchCmsDomain } from '@/api/cms/cmsDomain';
import type { CmsDomain, CmsDomainParam } from '@/api/cms/cmsDomain/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsDomain[]>([]);
// 当前编辑数据
const current = ref<CmsDomain | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsDomain({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '类型 0赠送域名 1绑定域名 ',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '域名',
dataIndex: 'domain',
key: 'domain',
align: 'center',
},
{
title: '主机记录',
dataIndex: 'hostName',
key: 'hostName',
align: 'center',
},
{
title: '记录值',
dataIndex: 'hostValue',
key: 'hostValue',
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '排序号',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '网站ID',
dataIndex: 'websiteId',
key: 'websiteId',
align: 'center',
},
{
title: '租户ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsDomainParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsDomain) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsDomain) => {
const hide = message.loading('请求中..', 0);
removeCmsDomain(row.cmsDomainId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsDomain(selection.value.map((d) => d.cmsDomainId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsDomain) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsDomain'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,292 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑表单设计表' : '添加表单设计表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="表单标题" name="name">
<a-input
allow-clear
placeholder="请输入表单标题"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="顶部图片" name="photo">
<a-input
allow-clear
placeholder="请输入顶部图片"
v-model:value="form.photo"
/>
</a-form-item>
<a-form-item label="背景图片" name="background">
<a-input
allow-clear
placeholder="请输入背景图片"
v-model:value="form.background"
/>
</a-form-item>
<a-form-item label="视频文件" name="video">
<a-input
allow-clear
placeholder="请输入视频文件"
v-model:value="form.video"
/>
</a-form-item>
<a-form-item label="提交次数" name="submitNumber">
<a-input
allow-clear
placeholder="请输入提交次数"
v-model:value="form.submitNumber"
/>
</a-form-item>
<a-form-item label="页面布局" name="layout">
<a-input
allow-clear
placeholder="请输入页面布局"
v-model:value="form.layout"
/>
</a-form-item>
<a-form-item label="是否隐藏顶部图片" name="hidePhoto">
<a-input
allow-clear
placeholder="请输入是否隐藏顶部图片"
v-model:value="form.hidePhoto"
/>
</a-form-item>
<a-form-item label="是否隐藏背景图片" name="hideBackground">
<a-input
allow-clear
placeholder="请输入是否隐藏背景图片"
v-model:value="form.hideBackground"
/>
</a-form-item>
<a-form-item label="是否隐藏视频" name="hideVideo">
<a-input
allow-clear
placeholder="请输入是否隐藏视频"
v-model:value="form.hideVideo"
/>
</a-form-item>
<a-form-item label="背景图片透明度" name="opacity">
<a-input
allow-clear
placeholder="请输入背景图片透明度"
v-model:value="form.opacity"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="商户ID" name="merchantId">
<a-input
allow-clear
placeholder="请输入商户ID"
v-model:value="form.merchantId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsForm, updateCmsForm } from '@/api/cms/cmsForm';
import { CmsForm } from '@/api/cms/cmsForm/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsForm | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsForm>({
formId: undefined,
name: undefined,
photo: undefined,
background: undefined,
video: undefined,
submitNumber: undefined,
layout: undefined,
hidePhoto: undefined,
hideBackground: undefined,
hideVideo: undefined,
opacity: undefined,
userId: undefined,
merchantId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsFormId: undefined,
cmsFormName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsFormName: [
{
required: true,
type: 'string',
message: '请填写表单设计表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsForm : addCmsForm;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,311 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsFormId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsFormEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsFormEdit from './components/cmsFormEdit.vue';
import { pageCmsForm, removeCmsForm, removeBatchCmsForm } from '@/api/cms/cmsForm';
import type { CmsForm, CmsFormParam } from '@/api/cms/cmsForm/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsForm[]>([]);
// 当前编辑数据
const current = ref<CmsForm | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsForm({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'formId',
key: 'formId',
align: 'center',
width: 90,
},
{
title: '表单标题',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '顶部图片',
dataIndex: 'photo',
key: 'photo',
align: 'center',
},
{
title: '背景图片',
dataIndex: 'background',
key: 'background',
align: 'center',
},
{
title: '视频文件',
dataIndex: 'video',
key: 'video',
align: 'center',
},
{
title: '提交次数',
dataIndex: 'submitNumber',
key: 'submitNumber',
align: 'center',
},
{
title: '页面布局',
dataIndex: 'layout',
key: 'layout',
align: 'center',
},
{
title: '是否隐藏顶部图片',
dataIndex: 'hidePhoto',
key: 'hidePhoto',
align: 'center',
},
{
title: '是否隐藏背景图片',
dataIndex: 'hideBackground',
key: 'hideBackground',
align: 'center',
},
{
title: '是否隐藏视频',
dataIndex: 'hideVideo',
key: 'hideVideo',
align: 'center',
},
{
title: '背景图片透明度',
dataIndex: 'opacity',
key: 'opacity',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '商户ID',
dataIndex: 'merchantId',
key: 'merchantId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsFormParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsForm) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsForm) => {
const hide = message.loading('请求中..', 0);
removeCmsForm(row.cmsFormId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsForm(selection.value.map((d) => d.cmsFormId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsForm) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsForm'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,244 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑表单数据记录表' : '添加表单数据记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="手机号" name="phone">
<a-input
allow-clear
placeholder="请输入手机号"
v-model:value="form.phone"
/>
</a-form-item>
<a-form-item label="表单数据" name="formData">
<a-input
allow-clear
placeholder="请输入表单数据"
v-model:value="form.formData"
/>
</a-form-item>
<a-form-item label="表单ID" name="formId">
<a-input
allow-clear
placeholder="请输入表单ID"
v-model:value="form.formId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="商户ID" name="merchantId">
<a-input
allow-clear
placeholder="请输入商户ID"
v-model:value="form.merchantId"
/>
</a-form-item>
<a-form-item label="姓名" name="name">
<a-input
allow-clear
placeholder="请输入姓名"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsFormRecord, updateCmsFormRecord } from '@/api/cms/cmsFormRecord';
import { CmsFormRecord } from '@/api/cms/cmsFormRecord/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsFormRecord | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsFormRecord>({
formRecordId: undefined,
phone: undefined,
formData: undefined,
formId: undefined,
userId: undefined,
merchantId: undefined,
name: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsFormRecordId: undefined,
cmsFormRecordName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsFormRecordName: [
{
required: true,
type: 'string',
message: '请填写表单数据记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsFormRecord : addCmsFormRecord;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,275 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsFormRecordId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsFormRecordEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsFormRecordEdit from './components/cmsFormRecordEdit.vue';
import { pageCmsFormRecord, removeCmsFormRecord, removeBatchCmsFormRecord } from '@/api/cms/cmsFormRecord';
import type { CmsFormRecord, CmsFormRecordParam } from '@/api/cms/cmsFormRecord/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsFormRecord[]>([]);
// 当前编辑数据
const current = ref<CmsFormRecord | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsFormRecord({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'formRecordId',
key: 'formRecordId',
align: 'center',
width: 90,
},
{
title: '手机号',
dataIndex: 'phone',
key: 'phone',
align: 'center',
},
{
title: '表单数据',
dataIndex: 'formData',
key: 'formData',
align: 'center',
},
{
title: '表单ID',
dataIndex: 'formId',
key: 'formId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '商户ID',
dataIndex: 'merchantId',
key: 'merchantId',
align: 'center',
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsFormRecordParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsFormRecord) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsFormRecord) => {
const hide = message.loading('请求中..', 0);
removeCmsFormRecord(row.cmsFormRecordId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsFormRecord(selection.value.map((d) => d.cmsFormRecordId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsFormRecord) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsFormRecord'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,252 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑常用链接' : '添加常用链接'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="链接名称" name="name">
<a-input
allow-clear
placeholder="请输入链接名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="图标" name="icon">
<a-input
allow-clear
placeholder="请输入图标"
v-model:value="form.icon"
/>
</a-form-item>
<a-form-item label="链接地址" name="url">
<a-input
allow-clear
placeholder="请输入链接地址"
v-model:value="form.url"
/>
</a-form-item>
<a-form-item label="链接分类" name="linkType">
<a-input
allow-clear
placeholder="请输入链接分类"
v-model:value="form.linkType"
/>
</a-form-item>
<a-form-item label="应用ID" name="appId">
<a-input
allow-clear
placeholder="请输入应用ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="是否推荐" name="recommend">
<a-input
allow-clear
placeholder="请输入是否推荐"
v-model:value="form.recommend"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1待确认" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsLink, updateCmsLink } from '@/api/cms/cmsLink';
import { CmsLink } from '@/api/cms/cmsLink/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsLink | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsLink>({
id: undefined,
name: undefined,
icon: undefined,
url: undefined,
linkType: undefined,
appId: undefined,
userId: undefined,
recommend: undefined,
comments: undefined,
sortNumber: undefined,
deleted: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsLinkId: undefined,
cmsLinkName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsLinkName: [
{
required: true,
type: 'string',
message: '请填写常用链接名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsLink : addCmsLink;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,281 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsLinkId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsLinkEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsLinkEdit from './components/cmsLinkEdit.vue';
import { pageCmsLink, removeCmsLink, removeBatchCmsLink } from '@/api/cms/cmsLink';
import type { CmsLink, CmsLinkParam } from '@/api/cms/cmsLink/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsLink[]>([]);
// 当前编辑数据
const current = ref<CmsLink | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsLink({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '链接名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
},
{
title: '链接地址',
dataIndex: 'url',
key: 'url',
align: 'center',
},
{
title: '链接分类',
dataIndex: 'linkType',
key: 'linkType',
align: 'center',
},
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '是否推荐',
dataIndex: 'recommend',
key: 'recommend',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '状态, 0正常, 1待确认',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsLinkParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsLink) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsLink) => {
const hide = message.loading('请求中..', 0);
removeCmsLink(row.cmsLinkId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsLink(selection.value.map((d) => d.cmsLinkId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsLink) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsLink'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,324 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑小程序信息' : '添加小程序信息'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="是否主账号" name="type">
<a-input
allow-clear
placeholder="请输入是否主账号"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="小程序ID" name="appId">
<a-input
allow-clear
placeholder="请输入小程序ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="小程序密钥" name="appSecret">
<a-input
allow-clear
placeholder="请输入小程序密钥"
v-model:value="form.appSecret"
/>
</a-form-item>
<a-form-item label="小程序名称" name="mpName">
<a-input
allow-clear
placeholder="请输入小程序名称"
v-model:value="form.mpName"
/>
</a-form-item>
<a-form-item label="小程序简称" name="shortName">
<a-input
allow-clear
placeholder="请输入小程序简称"
v-model:value="form.shortName"
/>
</a-form-item>
<a-form-item label="头像" name="avatar">
<a-input
allow-clear
placeholder="请输入头像"
v-model:value="form.avatar"
/>
</a-form-item>
<a-form-item label="小程序码" name="mpQrcode">
<a-input
allow-clear
placeholder="请输入小程序码"
v-model:value="form.mpQrcode"
/>
</a-form-item>
<a-form-item label="微信认证" name="authentication">
<a-input
allow-clear
placeholder="请输入微信认证"
v-model:value="form.authentication"
/>
</a-form-item>
<a-form-item label="主体信息" name="companyName">
<a-input
allow-clear
placeholder="请输入主体信息"
v-model:value="form.companyName"
/>
</a-form-item>
<a-form-item label="小程序备案" name="icpNo">
<a-input
allow-clear
placeholder="请输入小程序备案"
v-model:value="form.icpNo"
/>
</a-form-item>
<a-form-item label="登录邮箱" name="email">
<a-input
allow-clear
placeholder="请输入登录邮箱"
v-model:value="form.email"
/>
</a-form-item>
<a-form-item label="登录密码" name="password">
<a-input
allow-clear
placeholder="请输入登录密码"
v-model:value="form.password"
/>
</a-form-item>
<a-form-item label="原始ID" name="ghId">
<a-input
allow-clear
placeholder="请输入原始ID"
v-model:value="form.ghId"
/>
</a-form-item>
<a-form-item label="入口页面" name="mainPath">
<a-input
allow-clear
placeholder="请输入入口页面"
v-model:value="form.mainPath"
/>
</a-form-item>
<a-form-item label="过期时间" name="expirationTime">
<a-input
allow-clear
placeholder="请输入过期时间"
v-model:value="form.expirationTime"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="介绍" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsMp, updateCmsMp } from '@/api/cms/cmsMp';
import { CmsMp } from '@/api/cms/cmsMp/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsMp | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsMp>({
mpId: undefined,
type: undefined,
appId: undefined,
appSecret: undefined,
mpName: undefined,
shortName: undefined,
avatar: undefined,
mpQrcode: undefined,
authentication: undefined,
companyName: undefined,
icpNo: undefined,
email: undefined,
password: undefined,
ghId: undefined,
mainPath: undefined,
expirationTime: undefined,
sortNumber: undefined,
comments: undefined,
userId: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsMpId: undefined,
cmsMpName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsMpName: [
{
required: true,
type: 'string',
message: '请填写小程序信息名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsMp : addCmsMp;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,335 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsMpId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsMpEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsMpEdit from './components/cmsMpEdit.vue';
import { pageCmsMp, removeCmsMp, removeBatchCmsMp } from '@/api/cms/cmsMp';
import type { CmsMp, CmsMpParam } from '@/api/cms/cmsMp/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsMp[]>([]);
// 当前编辑数据
const current = ref<CmsMp | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsMp({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'mpId',
key: 'mpId',
align: 'center',
width: 90,
},
{
title: '是否主账号',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '小程序ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '小程序密钥',
dataIndex: 'appSecret',
key: 'appSecret',
align: 'center',
},
{
title: '小程序名称',
dataIndex: 'mpName',
key: 'mpName',
align: 'center',
},
{
title: '小程序简称',
dataIndex: 'shortName',
key: 'shortName',
align: 'center',
},
{
title: '头像',
dataIndex: 'avatar',
key: 'avatar',
align: 'center',
},
{
title: '小程序码',
dataIndex: 'mpQrcode',
key: 'mpQrcode',
align: 'center',
},
{
title: '微信认证',
dataIndex: 'authentication',
key: 'authentication',
align: 'center',
},
{
title: '主体信息',
dataIndex: 'companyName',
key: 'companyName',
align: 'center',
},
{
title: '小程序备案',
dataIndex: 'icpNo',
key: 'icpNo',
align: 'center',
},
{
title: '登录邮箱',
dataIndex: 'email',
key: 'email',
align: 'center',
},
{
title: '登录密码',
dataIndex: 'password',
key: 'password',
align: 'center',
},
{
title: '原始ID',
dataIndex: 'ghId',
key: 'ghId',
align: 'center',
},
{
title: '入口页面',
dataIndex: 'mainPath',
key: 'mainPath',
align: 'center',
},
{
title: '过期时间',
dataIndex: 'expirationTime',
key: 'expirationTime',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '介绍',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsMpParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsMp) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsMp) => {
const hide = message.loading('请求中..', 0);
removeCmsMp(row.cmsMpId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsMp(selection.value.map((d) => d.cmsMpId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsMp) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsMp'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,268 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑小程序广告位' : '添加小程序广告位'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="页面ID" name="pageId">
<a-input
allow-clear
placeholder="请输入页面ID"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="广告类型" name="adType">
<a-input
allow-clear
placeholder="请输入广告类型"
v-model:value="form.adType"
/>
</a-form-item>
<a-form-item label="广告位名称" name="name">
<a-input
allow-clear
placeholder="请输入广告位名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="宽" name="width">
<a-input
allow-clear
placeholder="请输入宽"
v-model:value="form.width"
/>
</a-form-item>
<a-form-item label="高" name="height">
<a-input
allow-clear
placeholder="请输入高"
v-model:value="form.height"
/>
</a-form-item>
<a-form-item label="广告图片" name="images">
<a-input
allow-clear
placeholder="请输入广告图片"
v-model:value="form.images"
/>
</a-form-item>
<a-form-item label="路由/链接地址" name="path">
<a-input
allow-clear
placeholder="请输入路由/链接地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="页面名称" name="pageName">
<a-input
allow-clear
placeholder="请输入页面名称"
v-model:value="form.pageName"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsMpAd, updateCmsMpAd } from '@/api/cms/cmsMpAd';
import { CmsMpAd } from '@/api/cms/cmsMpAd/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsMpAd | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsMpAd>({
adId: undefined,
pageId: undefined,
adType: undefined,
name: undefined,
width: undefined,
height: undefined,
images: undefined,
path: undefined,
pageName: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsMpAdId: undefined,
cmsMpAdName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsMpAdName: [
{
required: true,
type: 'string',
message: '请填写小程序广告位名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsMpAd : addCmsMpAd;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,293 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsMpAdId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsMpAdEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsMpAdEdit from './components/cmsMpAdEdit.vue';
import { pageCmsMpAd, removeCmsMpAd, removeBatchCmsMpAd } from '@/api/cms/cmsMpAd';
import type { CmsMpAd, CmsMpAdParam } from '@/api/cms/cmsMpAd/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsMpAd[]>([]);
// 当前编辑数据
const current = ref<CmsMpAd | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsMpAd({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'adId',
key: 'adId',
align: 'center',
width: 90,
},
{
title: '页面ID',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '广告类型',
dataIndex: 'adType',
key: 'adType',
align: 'center',
},
{
title: '广告位名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '宽',
dataIndex: 'width',
key: 'width',
align: 'center',
},
{
title: '高',
dataIndex: 'height',
key: 'height',
align: 'center',
},
{
title: '广告图片',
dataIndex: 'images',
key: 'images',
align: 'center',
},
{
title: '路由/链接地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '页面名称',
dataIndex: 'pageName',
key: 'pageName',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsMpAdParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsMpAd) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsMpAd) => {
const hide = message.loading('请求中..', 0);
removeCmsMpAd(row.cmsMpAdId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsMpAd(selection.value.map((d) => d.cmsMpAdId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsMpAd) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsMpAd'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,221 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑小程序配置' : '添加小程序配置'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="类型0文本 1图片 2其他" name="type">
<a-input
allow-clear
placeholder="请输入类型0文本 1图片 2其他"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="名称" name="name">
<a-input
allow-clear
placeholder="请输入名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="名称" name="value">
<a-input
allow-clear
placeholder="请输入名称"
v-model:value="form.value"
/>
</a-form-item>
<a-form-item label="页面ID" name="pageId">
<a-input
allow-clear
placeholder="请输入页面ID"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsMpField, updateCmsMpField } from '@/api/cms/cmsMpField';
import { CmsMpField } from '@/api/cms/cmsMpField/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsMpField | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsMpField>({
id: undefined,
type: undefined,
name: undefined,
comments: undefined,
value: undefined,
pageId: undefined,
sortNumber: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsMpFieldId: undefined,
cmsMpFieldName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsMpFieldName: [
{
required: true,
type: 'string',
message: '请填写小程序配置名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsMpField : addCmsMpField;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,257 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsMpFieldId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsMpFieldEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsMpFieldEdit from './components/cmsMpFieldEdit.vue';
import { pageCmsMpField, removeCmsMpField, removeBatchCmsMpField } from '@/api/cms/cmsMpField';
import type { CmsMpField, CmsMpFieldParam } from '@/api/cms/cmsMpField/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsMpField[]>([]);
// 当前编辑数据
const current = ref<CmsMpField | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsMpField({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '类型0文本 1图片 2其他',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '名称',
dataIndex: 'value',
key: 'value',
align: 'center',
},
{
title: '页面ID',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsMpFieldParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsMpField) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsMpField) => {
const hide = message.loading('请求中..', 0);
removeCmsMpField(row.cmsMpFieldId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsMpField(selection.value.map((d) => d.cmsMpFieldId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsMpField) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsMpField'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,396 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑小程序端菜单' : '添加小程序端菜单'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="上级id, 0是顶级" name="parentId">
<a-input
allow-clear
placeholder="请输入上级id, 0是顶级"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="菜单名称" name="title">
<a-input
allow-clear
placeholder="请输入菜单名称"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="类型 0功能图标 1订单状态图标 2首页导航图标 3 商城导航图标 4管理人员功能图标" name="type">
<a-input
allow-clear
placeholder="请输入类型 0功能图标 1订单状态图标 2首页导航图标 3 商城导航图标 4管理人员功能图标"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="是否微信小程序菜单" name="isMpWeixin">
<a-input
allow-clear
placeholder="请输入是否微信小程序菜单"
v-model:value="form.isMpWeixin"
/>
</a-form-item>
<a-form-item label="菜单路由地址" name="path">
<a-input
allow-clear
placeholder="请输入菜单路由地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="菜单组件地址, 目录可为空" name="component">
<a-input
allow-clear
placeholder="请输入菜单组件地址, 目录可为空"
v-model:value="form.component"
/>
</a-form-item>
<a-form-item label="打开位置" name="target">
<a-input
allow-clear
placeholder="请输入打开位置"
v-model:value="form.target"
/>
</a-form-item>
<a-form-item label="菜单图标" name="avatar">
<a-input
allow-clear
placeholder="请输入菜单图标"
v-model:value="form.avatar"
/>
</a-form-item>
<a-form-item label="图标颜色" name="color">
<a-input
allow-clear
placeholder="请输入图标颜色"
v-model:value="form.color"
/>
</a-form-item>
<a-form-item label="上传图标" name="icon">
<a-input
allow-clear
placeholder="请输入上传图标"
v-model:value="form.icon"
/>
</a-form-item>
<a-form-item label="是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)" name="hide">
<a-input
allow-clear
placeholder="请输入是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)"
v-model:value="form.hide"
/>
</a-form-item>
<a-form-item label="位置 0不限 1顶部 2底部" name="position">
<a-input
allow-clear
placeholder="请输入位置 0不限 1顶部 2底部"
v-model:value="form.position"
/>
</a-form-item>
<a-form-item label="0 第一行 1第二行" name="rows">
<a-input
allow-clear
placeholder="请输入0 第一行 1第二行"
v-model:value="form.rows"
/>
</a-form-item>
<a-form-item label="菜单侧栏选中的path" name="active">
<a-input
allow-clear
placeholder="请输入菜单侧栏选中的path"
v-model:value="form.active"
/>
</a-form-item>
<a-form-item label="其它路由元信息" name="meta">
<a-input
allow-clear
placeholder="请输入其它路由元信息"
v-model:value="form.meta"
/>
</a-form-item>
<a-form-item label="绑定的页面" name="pageId">
<a-input
allow-clear
placeholder="请输入绑定的页面"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="绑定的文章分类ID" name="articleCategoryId">
<a-input
allow-clear
placeholder="请输入绑定的文章分类ID"
v-model:value="form.articleCategoryId"
/>
</a-form-item>
<a-form-item label="绑定的文章ID" name="articleId">
<a-input
allow-clear
placeholder="请输入绑定的文章ID"
v-model:value="form.articleId"
/>
</a-form-item>
<a-form-item label="绑定的表单ID" name="formId">
<a-input
allow-clear
placeholder="请输入绑定的表单ID"
v-model:value="form.formId"
/>
</a-form-item>
<a-form-item label="绑定的书籍标识" name="bookCode">
<a-input
allow-clear
placeholder="请输入绑定的书籍标识"
v-model:value="form.bookCode"
/>
</a-form-item>
<a-form-item label="绑定的商品分类ID" name="goodsCategoryId">
<a-input
allow-clear
placeholder="请输入绑定的商品分类ID"
v-model:value="form.goodsCategoryId"
/>
</a-form-item>
<a-form-item label="绑定的商品ID" name="goodsId">
<a-input
allow-clear
placeholder="请输入绑定的商品ID"
v-model:value="form.goodsId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="是否管理人员可见" name="adminShow">
<a-input
allow-clear
placeholder="请输入是否管理人员可见"
v-model:value="form.adminShow"
/>
</a-form-item>
<a-form-item label="设为首页" name="home">
<a-input
allow-clear
placeholder="请输入设为首页"
v-model:value="form.home"
/>
</a-form-item>
<a-form-item label="分组名称" name="groupName">
<a-input
allow-clear
placeholder="请输入分组名称"
v-model:value="form.groupName"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsMpMenu, updateCmsMpMenu } from '@/api/cms/cmsMpMenu';
import { CmsMpMenu } from '@/api/cms/cmsMpMenu/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsMpMenu | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsMpMenu>({
menuId: undefined,
parentId: undefined,
title: undefined,
type: undefined,
isMpWeixin: undefined,
path: undefined,
component: undefined,
target: undefined,
avatar: undefined,
color: undefined,
icon: undefined,
hide: undefined,
position: undefined,
rows: undefined,
active: undefined,
meta: undefined,
pageId: undefined,
articleCategoryId: undefined,
articleId: undefined,
formId: undefined,
bookCode: undefined,
goodsCategoryId: undefined,
goodsId: undefined,
userId: undefined,
adminShow: undefined,
home: undefined,
groupName: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsMpMenuId: undefined,
cmsMpMenuName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsMpMenuName: [
{
required: true,
type: 'string',
message: '请填写小程序端菜单名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsMpMenu : addCmsMpMenu;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,389 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsMpMenuId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsMpMenuEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsMpMenuEdit from './components/cmsMpMenuEdit.vue';
import { pageCmsMpMenu, removeCmsMpMenu, removeBatchCmsMpMenu } from '@/api/cms/cmsMpMenu';
import type { CmsMpMenu, CmsMpMenuParam } from '@/api/cms/cmsMpMenu/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsMpMenu[]>([]);
// 当前编辑数据
const current = ref<CmsMpMenu | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsMpMenu({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'menuId',
key: 'menuId',
align: 'center',
width: 90,
},
{
title: '上级id, 0是顶级',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '菜单名称',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '类型 0功能图标 1订单状态图标 2首页导航图标 3 商城导航图标 4管理人员功能图标',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '是否微信小程序菜单',
dataIndex: 'isMpWeixin',
key: 'isMpWeixin',
align: 'center',
},
{
title: '菜单路由地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '菜单组件地址, 目录可为空',
dataIndex: 'component',
key: 'component',
align: 'center',
},
{
title: '打开位置',
dataIndex: 'target',
key: 'target',
align: 'center',
},
{
title: '菜单图标',
dataIndex: 'avatar',
key: 'avatar',
align: 'center',
},
{
title: '图标颜色',
dataIndex: 'color',
key: 'color',
align: 'center',
},
{
title: '上传图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
},
{
title: '是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)',
dataIndex: 'hide',
key: 'hide',
align: 'center',
},
{
title: '位置 0不限 1顶部 2底部',
dataIndex: 'position',
key: 'position',
align: 'center',
},
{
title: '0 第一行 1第二行',
dataIndex: 'rows',
key: 'rows',
align: 'center',
},
{
title: '菜单侧栏选中的path',
dataIndex: 'active',
key: 'active',
align: 'center',
},
{
title: '其它路由元信息',
dataIndex: 'meta',
key: 'meta',
align: 'center',
},
{
title: '绑定的页面',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '绑定的文章分类ID',
dataIndex: 'articleCategoryId',
key: 'articleCategoryId',
align: 'center',
},
{
title: '绑定的文章ID',
dataIndex: 'articleId',
key: 'articleId',
align: 'center',
},
{
title: '绑定的表单ID',
dataIndex: 'formId',
key: 'formId',
align: 'center',
},
{
title: '绑定的书籍标识',
dataIndex: 'bookCode',
key: 'bookCode',
align: 'center',
},
{
title: '绑定的商品分类ID',
dataIndex: 'goodsCategoryId',
key: 'goodsCategoryId',
align: 'center',
},
{
title: '绑定的商品ID',
dataIndex: 'goodsId',
key: 'goodsId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '是否管理人员可见',
dataIndex: 'adminShow',
key: 'adminShow',
align: 'center',
},
{
title: '设为首页',
dataIndex: 'home',
key: 'home',
align: 'center',
},
{
title: '分组名称',
dataIndex: 'groupName',
key: 'groupName',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsMpMenuParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsMpMenu) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsMpMenu) => {
const hide = message.loading('请求中..', 0);
removeCmsMpMenu(row.cmsMpMenuId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsMpMenu(selection.value.map((d) => d.cmsMpMenuId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsMpMenu) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsMpMenu'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,268 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑小程序页面' : '添加小程序页面'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="上级id, 0是顶级" name="parentId">
<a-input
allow-clear
placeholder="请输入上级id, 0是顶级"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="页面名称" name="title">
<a-input
allow-clear
placeholder="请输入页面名称"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="页面路径" name="path">
<a-input
allow-clear
placeholder="请输入页面路径"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="设为首页" name="home">
<a-input
allow-clear
placeholder="请输入设为首页"
v-model:value="form.home"
/>
</a-form-item>
<a-form-item label="分包" name="subpackage">
<a-input
allow-clear
placeholder="请输入分包"
v-model:value="form.subpackage"
/>
</a-form-item>
<a-form-item label="图标" name="icon">
<a-input
allow-clear
placeholder="请输入图标"
v-model:value="form.icon"
/>
</a-form-item>
<a-form-item label="未选中图标" name="iconPath">
<a-input
allow-clear
placeholder="请输入未选中图标"
v-model:value="form.iconPath"
/>
</a-form-item>
<a-form-item label="选中的图标" name="selectedIconPath">
<a-input
allow-clear
placeholder="请输入选中的图标"
v-model:value="form.selectedIconPath"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsMpPages, updateCmsMpPages } from '@/api/cms/cmsMpPages';
import { CmsMpPages } from '@/api/cms/cmsMpPages/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsMpPages | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsMpPages>({
id: undefined,
parentId: undefined,
title: undefined,
path: undefined,
home: undefined,
subpackage: undefined,
icon: undefined,
iconPath: undefined,
selectedIconPath: undefined,
sortNumber: undefined,
comments: undefined,
userId: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
cmsMpPagesId: undefined,
cmsMpPagesName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsMpPagesName: [
{
required: true,
type: 'string',
message: '请填写小程序页面名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsMpPages : addCmsMpPages;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,293 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsMpPagesId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsMpPagesEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsMpPagesEdit from './components/cmsMpPagesEdit.vue';
import { pageCmsMpPages, removeCmsMpPages, removeBatchCmsMpPages } from '@/api/cms/cmsMpPages';
import type { CmsMpPages, CmsMpPagesParam } from '@/api/cms/cmsMpPages/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsMpPages[]>([]);
// 当前编辑数据
const current = ref<CmsMpPages | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsMpPages({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '上级id, 0是顶级',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '页面名称',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '页面路径',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '设为首页',
dataIndex: 'home',
key: 'home',
align: 'center',
},
{
title: '分包',
dataIndex: 'subpackage',
key: 'subpackage',
align: 'center',
},
{
title: '图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
},
{
title: '未选中图标',
dataIndex: 'iconPath',
key: 'iconPath',
align: 'center',
},
{
title: '选中的图标',
dataIndex: 'selectedIconPath',
key: 'selectedIconPath',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsMpPagesParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsMpPages) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsMpPages) => {
const hide = message.loading('请求中..', 0);
removeCmsMpPages(row.cmsMpPagesId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsMpPages(selection.value.map((d) => d.cmsMpPagesId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsMpPages) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsMpPages'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,404 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑网站导航记录表' : '添加网站导航记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="上级id, 0是顶级" name="parentId">
<a-input
allow-clear
placeholder="请输入上级id, 0是顶级"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="菜单名称" name="title">
<a-input
allow-clear
placeholder="请输入菜单名称"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="模型" name="model">
<a-input
allow-clear
placeholder="请输入模型"
v-model:value="form.model"
/>
</a-form-item>
<a-form-item label="标识" name="code">
<a-input
allow-clear
placeholder="请输入标识"
v-model:value="form.code"
/>
</a-form-item>
<a-form-item label="菜单路由地址" name="path">
<a-input
allow-clear
placeholder="请输入菜单路由地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="菜单组件地址, 目录可为空" name="component">
<a-input
allow-clear
placeholder="请输入菜单组件地址, 目录可为空"
v-model:value="form.component"
/>
</a-form-item>
<a-form-item label="打开位置" name="target">
<a-input
allow-clear
placeholder="请输入打开位置"
v-model:value="form.target"
/>
</a-form-item>
<a-form-item label="菜单图标" name="icon">
<a-input
allow-clear
placeholder="请输入菜单图标"
v-model:value="form.icon"
/>
</a-form-item>
<a-form-item label="图标颜色" name="color">
<a-input
allow-clear
placeholder="请输入图标颜色"
v-model:value="form.color"
/>
</a-form-item>
<a-form-item label="是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)" name="hide">
<a-input
allow-clear
placeholder="请输入是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)"
v-model:value="form.hide"
/>
</a-form-item>
<a-form-item label="可见类型 0所有人 1登录可见 2密码可见" name="permission">
<a-input
allow-clear
placeholder="请输入可见类型 0所有人 1登录可见 2密码可见"
v-model:value="form.permission"
/>
</a-form-item>
<a-form-item label="访问密码" name="password">
<a-input
allow-clear
placeholder="请输入访问密码"
v-model:value="form.password"
/>
</a-form-item>
<a-form-item label="位置 0不限 1顶部 2底部" name="position">
<a-input
allow-clear
placeholder="请输入位置 0不限 1顶部 2底部"
v-model:value="form.position"
/>
</a-form-item>
<a-form-item label="仅在顶部显示" name="top">
<a-input
allow-clear
placeholder="请输入仅在顶部显示"
v-model:value="form.top"
/>
</a-form-item>
<a-form-item label="仅在底部显示" name="bottom">
<a-input
allow-clear
placeholder="请输入仅在底部显示"
v-model:value="form.bottom"
/>
</a-form-item>
<a-form-item label="菜单侧栏选中的path" name="active">
<a-input
allow-clear
placeholder="请输入菜单侧栏选中的path"
v-model:value="form.active"
/>
</a-form-item>
<a-form-item label="其它路由元信息" name="meta">
<a-input
allow-clear
placeholder="请输入其它路由元信息"
v-model:value="form.meta"
/>
</a-form-item>
<a-form-item label="css样式" name="style">
<a-input
allow-clear
placeholder="请输入css样式"
v-model:value="form.style"
/>
</a-form-item>
<a-form-item label="父级栏目路由" name="parentPath">
<a-input
allow-clear
placeholder="请输入父级栏目路由"
v-model:value="form.parentPath"
/>
</a-form-item>
<a-form-item label="父级栏目名称" name="parentName">
<a-input
allow-clear
placeholder="请输入父级栏目名称"
v-model:value="form.parentName"
/>
</a-form-item>
<a-form-item label="模型名称" name="modelName">
<a-input
allow-clear
placeholder="请输入模型名称"
v-model:value="form.modelName"
/>
</a-form-item>
<a-form-item label="类型(已废弃)" name="type">
<a-input
allow-clear
placeholder="请输入类型(已废弃)"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="绑定的页面(已废弃)" name="pageId">
<a-input
allow-clear
placeholder="请输入绑定的页面(已废弃)"
v-model:value="form.pageId"
/>
</a-form-item>
<a-form-item label="是否微信小程序菜单" name="isMpWeixin">
<a-input
allow-clear
placeholder="请输入是否微信小程序菜单"
v-model:value="form.isMpWeixin"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="设为首页" name="home">
<a-input
allow-clear
placeholder="请输入设为首页"
v-model:value="form.home"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addCmsNavigation, updateCmsNavigation } from '@/api/cms/cmsNavigation';
import { CmsNavigation } from '@/api/cms/cmsNavigation/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsNavigation | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<CmsNavigation>({
navigationId: undefined,
parentId: undefined,
title: undefined,
model: undefined,
code: undefined,
path: undefined,
component: undefined,
target: undefined,
icon: undefined,
color: undefined,
hide: undefined,
permission: undefined,
password: undefined,
position: undefined,
top: undefined,
bottom: undefined,
active: undefined,
meta: undefined,
style: undefined,
parentPath: undefined,
parentName: undefined,
modelName: undefined,
type: undefined,
pageId: undefined,
isMpWeixin: undefined,
userId: undefined,
home: undefined,
sortNumber: undefined,
comments: undefined,
deleted: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
cmsNavigationId: undefined,
cmsNavigationName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
cmsNavigationName: [
{
required: true,
type: 'string',
message: '请填写网站导航记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateCmsNavigation : addCmsNavigation;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,395 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="cmsNavigationId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<CmsNavigationEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import CmsNavigationEdit from './components/cmsNavigationEdit.vue';
import { pageCmsNavigation, removeCmsNavigation, removeBatchCmsNavigation } from '@/api/cms/cmsNavigation';
import type { CmsNavigation, CmsNavigationParam } from '@/api/cms/cmsNavigation/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsNavigation[]>([]);
// 当前编辑数据
const current = ref<CmsNavigation | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsNavigation({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'navigationId',
key: 'navigationId',
align: 'center',
width: 90,
},
{
title: '上级id, 0是顶级',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '菜单名称',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '模型',
dataIndex: 'model',
key: 'model',
align: 'center',
},
{
title: '标识',
dataIndex: 'code',
key: 'code',
align: 'center',
},
{
title: '菜单路由地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '菜单组件地址, 目录可为空',
dataIndex: 'component',
key: 'component',
align: 'center',
},
{
title: '打开位置',
dataIndex: 'target',
key: 'target',
align: 'center',
},
{
title: '菜单图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
},
{
title: '图标颜色',
dataIndex: 'color',
key: 'color',
align: 'center',
},
{
title: '是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)',
dataIndex: 'hide',
key: 'hide',
align: 'center',
},
{
title: '可见类型 0所有人 1登录可见 2密码可见',
dataIndex: 'permission',
key: 'permission',
align: 'center',
},
{
title: '访问密码',
dataIndex: 'password',
key: 'password',
align: 'center',
},
{
title: '位置 0不限 1顶部 2底部',
dataIndex: 'position',
key: 'position',
align: 'center',
},
{
title: '仅在顶部显示',
dataIndex: 'top',
key: 'top',
align: 'center',
},
{
title: '仅在底部显示',
dataIndex: 'bottom',
key: 'bottom',
align: 'center',
},
{
title: '菜单侧栏选中的path',
dataIndex: 'active',
key: 'active',
align: 'center',
},
{
title: '其它路由元信息',
dataIndex: 'meta',
key: 'meta',
align: 'center',
},
{
title: 'css样式',
dataIndex: 'style',
key: 'style',
align: 'center',
},
{
title: '父级栏目路由',
dataIndex: 'parentPath',
key: 'parentPath',
align: 'center',
},
{
title: '父级栏目名称',
dataIndex: 'parentName',
key: 'parentName',
align: 'center',
},
{
title: '模型名称',
dataIndex: 'modelName',
key: 'modelName',
align: 'center',
},
{
title: '类型(已废弃)',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '绑定的页面(已废弃)',
dataIndex: 'pageId',
key: 'pageId',
align: 'center',
},
{
title: '是否微信小程序菜单',
dataIndex: 'isMpWeixin',
key: 'isMpWeixin',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '设为首页',
dataIndex: 'home',
key: 'home',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: CmsNavigationParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsNavigation) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: CmsNavigation) => {
const hide = message.loading('请求中..', 0);
removeCmsNavigation(row.cmsNavigationId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsNavigation(selection.value.map((d) => d.cmsNavigationId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsNavigation) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsNavigation'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,374 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑网站信息' : '添加网站信息'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="Logo" name="avatar">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="网站名称" name="websiteName">
<a-input
allow-clear
placeholder="请输入网站名称"
v-model:value="form.websiteName"
/>
</a-form-item>
<a-form-item label="赠送域名" name="websiteCode">
<a-input
v-model:value="form.websiteCode"
placeholder="huawei"
addon-before="https://"
addon-after=".wsdns.cn"
/>
</a-form-item>
<a-form-item label="自定义域名" name="domain">
<a-input
v-model:value="form.domain"
placeholder="huawei.com"
addon-before="https://"
/>
</a-form-item>
<a-form-item label="网站描述" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入网站描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="SEO关键词" name="keywords">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入SEO关键词"
v-model:value="form.keywords"
/>
</a-form-item>
<a-form-item label="全局样式" name="style">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="全局样式(Tailwind CSS风格)"
v-model:value="form.style"
/>
</a-form-item>
<!-- <a-form-item label="访问域名" name="domain">-->
<!-- <a-input-->
<!-- v-model:value="form.domain"-->
<!-- placeholder="websoft.top"-->
<!-- addon-before="https://"-->
<!-- addon-after="websoft.top"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="后台管理" name="adminUrl">-->
<!-- <a-input v-model:value="form.adminUrl" placeholder="admin.domain.com">-->
<!-- <template #addonBefore>-->
<!-- <a-select v-model:value="form.prefix" style="width: 90px">-->
<!-- <a-select-option value="http://">http://</a-select-option>-->
<!-- <a-select-option value="https://">https://</a-select-option>-->
<!-- </a-select>-->
<!-- </template>-->
<!-- </a-input>-->
<!-- </a-form-item>-->
<!-- <a-form-item label="ICP备案号" name="icpNo">-->
<!-- <a-input-->
<!-- allow-clear-->
<!-- placeholder="请输入网站备案"-->
<!-- v-model:value="form.icpNo"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="网站类型" name="websiteType">-->
<!-- <a-select-->
<!-- :options="websiteType"-->
<!-- :value="form.websiteType"-->
<!-- placeholder="请选择主体类型"-->
<!-- @change="onWebsiteType"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="当前版本" name="version">-->
<!-- <a-tag color="red" v-if="form.version === 10">免费版</a-tag>-->
<!-- <a-tag color="green" v-if="form.version === 20">授权版</a-tag>-->
<!-- <a-tag color="cyan" v-if="form.version === 30">永久授权</a-tag>-->
<!-- </a-form-item>-->
<a-form-item label="状态" name="status">
<a-radio-group
v-model:value="form.status"
:disabled="form.status && form.status > 3"
>
<a-radio :value="1">运行中</a-radio>
<a-radio :value="2">维护中</a-radio>
<a-radio :value="3">已关闭</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item v-if="form.status == 2" label="维护说明" name="statusText">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="状态说明"
v-model:value="form.statusText"
/>
</a-form-item>
<!-- <a-divider style="margin-bottom: 24px" />-->
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid, SelectProps } from 'ele-admin-pro';
import { addCmsWebsite, updateCmsWebsite } from '@/api/cms/cmsWebsite';
import { CmsWebsite } from '@/api/cms/cmsWebsite/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { FormInstance, type Rule } from 'ant-design-vue/es/form';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FileRecord } from '@/api/system/file/model';
import { checkExistence } from '@/api/cms/cmsDomain';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: CmsWebsite | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
const websiteQrcode = ref<ItemType[]>([]);
const oldDomain = ref();
// 用户信息
const form = reactive<CmsWebsite>({
websiteId: undefined,
websiteLogo: undefined,
websiteName: undefined,
websiteCode: undefined,
keywords: '',
prefix: '',
domain: '',
adminUrl: '',
style: '',
icpNo: undefined,
email: undefined,
version: undefined,
websiteType: '',
expirationTime: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
statusText: undefined
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
comments: [
{
required: true,
type: 'string',
message: '请填写网站描述',
trigger: 'blur'
}
],
keywords: [
{
required: true,
type: 'string',
message: '请填写SEO关键词',
trigger: 'blur'
}
],
// domain: [
// {
// required: true,
// type: 'string',
// message: '请填写网站域名',
// trigger: 'blur'
// }
// ],
websiteCode: [
{
required: true,
type: 'string',
message: '该域名已存在',
validator: (_rule: Rule, value: string) => {
return new Promise<void>((resolve, reject) => {
if (!value) {
return reject('请输入二级域名');
}
checkExistence('domain', `${value}.wsdns.cn`)
.then(() => {
if (value === oldDomain.value) {
return resolve();
}
reject('已存在');
})
.catch(() => {
resolve();
});
});
},
trigger: 'blur'
}
],
adminUrl: [
{
required: true,
type: 'string',
message: '请填写网站后台管理地址',
trigger: 'blur'
}
],
icpNo: [
{
required: true,
type: 'string',
message: '请填写ICP备案号',
trigger: 'blur'
}
],
appSecret: [
{
required: true,
type: 'string',
message: '请填写网站秘钥',
trigger: 'blur'
}
],
websiteName: [
{
required: true,
type: 'string',
message: '请填写网站信息名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.websiteLogo = data.downloadUrl;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.websiteLogo = '';
};
const onWebsiteType = (text: string) => {
form.websiteType = text;
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form,
tenantId: localStorage.getItem('TenantId')
};
const saveOrUpdate = isUpdate.value ? updateCmsWebsite : addCmsWebsite;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
if (form.domain) {
localStorage.setItem('Domain', `https://${form.domain}`);
} else {
localStorage.setItem('Domain', `${form.websiteCode}.wsdns.cn`);
}
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
websiteQrcode.value = [];
if (props.data) {
assignObject(form, props.data);
if (props.data.websiteLogo) {
images.value.push({
uid: uuid(),
url: props.data.websiteLogo,
status: 'done'
});
}
if (props.data.websiteCode) {
oldDomain.value = props.data.websiteCode;
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,310 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="websiteId"
:columns="columns"
:datasource="datasource"
:parse-data="parseData"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
:website="website"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'websiteLogo'">
<a-image :src="record.websiteLogo" :width="50" />
</template>
<template v-if="column.key === 'domain'">
<a-button
v-if="record.domain"
type="link"
@click="openSpmUrl(`https://${record.domain}`, record)"
>
{{ record.domain }}
</a-button>
<a-button
type="link"
v-if="!record.domain"
@click="
openSpmUrl(
`https://${record.websiteCode}.wsdns.cn`,
record,
record.websiteId
)
"
>
{{ record.websiteCode ? `${record.websiteCode}.wsdns.cn` : '' }}
</a-button>
</template>
<template v-if="column.key === 'type'">
<a-tag v-if="record.type === 1" color="green"></a-tag>
<a-tag
v-if="record.type === 0"
@click="updateType(record)"
class="cursor-pointer"
></a-tag
>
</template>
<template v-if="column.key === 'version'">
<text v-if="record.version === 10">免费版</text>
<text v-if="record.version === 20">授权版</text>
<text v-if="record.version === 30">永久授权</text>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="red">未开通</a-tag>
<a-tag v-if="record.status === 1" color="green">运行中</a-tag>
<a-tag v-if="record.status === 2" color="orange">维护中</a-tag>
<a-tag v-if="record.status === 3" color="red">已关闭</a-tag>
<a-tag v-if="record.status === 4" color="red">已欠费停机</a-tag>
<a-tag v-if="record.status === 5" color="red">违规关停</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-divider type="vertical" />
<a @click="openEdit(record)">编辑</a>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<WebsiteEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import WebsiteEdit from './components/cmsWebsiteEdit.vue';
import {
pageCmsWebsite,
removeCmsWebsite,
removeBatchCmsWebsite,
updateCmsWebsite
} from '@/api/cms/cmsWebsite';
import type { CmsWebsite, CmsWebsiteParam } from '@/api/cms/cmsWebsite/model';
import { openSpmUrl } from '@/utils/common';
import { PageResult } from '@/api';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<CmsWebsite[]>([]);
// 当前编辑数据
const current = ref<CmsWebsite | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 当前网站项目
const website = ref<CmsWebsite>();
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageCmsWebsite({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '租户ID',
dataIndex: 'tenantId',
key: 'tenantId',
width: 80
},
{
title: '网站名称',
dataIndex: 'websiteName',
key: 'websiteName',
align: 'center'
},
{
title: 'Logo',
dataIndex: 'websiteLogo',
key: 'websiteLogo',
align: 'center'
},
{
title: '域名',
dataIndex: 'domain',
key: 'domain',
align: 'center'
},
{
title: '网站描述',
dataIndex: 'comments',
key: 'comments',
align: 'center'
},
{
title: '当前版本',
dataIndex: 'version',
key: 'version',
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center'
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
}
// {
// title: '操作',
// key: 'action',
// width: 180,
// fixed: 'right',
// align: 'center',
// hideInSetting: true
// }
]);
// 整理数据
const parseData = (data: PageResult<CmsWebsite>) => {
if (data?.count > 0) {
website.value = data.list[0];
}
return data;
};
/* 搜索 */
const reload = (where?: CmsWebsiteParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsWebsite) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
const updateType = (row: CmsWebsite) => {
updateCmsWebsite(row).then((msg) => {
message.success(msg);
reload();
});
};
/* 删除单个 */
const remove = (row: CmsWebsite) => {
const hide = message.loading('请求中..', 0);
removeCmsWebsite(row.websiteId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCmsWebsite(selection.value.map((d) => d.websiteId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: CmsWebsite) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'CmsWebsite'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,237 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="600"
:visible="visible"
:maskClosable="false"
:title="isUpdate ? '编辑参数' : '添加参数'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="{ md: { span: 3 }, sm: { span: 4 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 21 }, sm: { span: 22 }, xs: { span: 24 } }"
>
<a-form-item label="参数" name="comments">
<a-input
allow-clear
:maxlength="100"
placeholder="网站名称"
v-model:value="form.comments"
@pressEnter="save"
/>
</a-form-item>
<a-form-item label="调用" name="name">
<SelectWebsiteField
:placeholder="`可配置参数`"
class="input-item"
v-model:value="form.name"
@done="chooseData"
/>
</a-form-item>
<a-form-item label="配置值" name="value">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="网站名称"
v-model:value="form.value"
/>
</a-form-item>
<a-form-item label="css样式" name="style">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="css样式"
v-model:value="form.style"
/>
</a-form-item>
<a-form-item label="图片">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="排序" name="sortNumber">
<a-input-number
:min="0"
:max="99999"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { FormInstance } from 'ant-design-vue/es/form';
import useFormData from '@/utils/use-form-data';
import {
addCmsWebsiteField,
updateCmsWebsiteField
} from '@/api/cms/cmsWebsiteField';
import { message } from 'ant-design-vue/es';
import { removeSiteInfoCache } from '@/api/cms/website';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FileRecord } from '@/api/system/file/model';
import { uuid } from 'ele-admin-pro';
import { CmsWebsiteField } from '@/api/cms/cmsWebsiteField/model';
// 是否是修改
const isUpdate = ref(false);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
websiteId: number | null | undefined;
// 修改回显的数据
data?: CmsWebsiteField | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
const images = ref<ItemType[]>([]);
const formRef = ref<FormInstance | null>(null);
const { form, resetFields, assignFields } = useFormData<CmsWebsiteField>({
id: undefined,
type: 0,
name: undefined,
value: undefined,
modifyRange: undefined,
defaultValue: undefined,
comments: '',
style: '',
status: 0,
sortNumber: 100
});
// 表单验证规则
const rules = reactive({
name: [
{
required: true,
type: 'string',
message: '请输入参数名称(英语)'
}
],
// comments: [
// {
// required: true,
// type: 'string',
// message: '请输入描述'
// }
// ],
value: [
{
required: true,
type: 'string',
message: '请填写参数值'
}
]
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.value = data.downloadUrl;
form.type = 1;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.type = 0;
};
const chooseData = (data: CmsWebsiteField) => {
assignFields(data);
form.value = data.defaultValue;
if (data.type == 1) {
images.value.push({
uid: `${data.id}`,
url: data.defaultValue,
status: 'done'
});
}
};
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const data = {
...form,
// name: form.name?.toUpperCase(),
websiteId: props.websiteId
};
const saveOrUpdate = isUpdate.value
? updateCmsWebsiteField
: addCmsWebsiteField;
saveOrUpdate(data)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
// 清除缓存
removeSiteInfoCache('SiteInfo:' + localStorage.getItem('TenantId'));
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignFields(props.data);
form.comments = props.data.comments;
if (form.type == 1) {
images.value.push({
uid: uuid(),
url: props.data.value,
status: 'done'
});
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>

View File

@@ -0,0 +1,13 @@
<template>
<a-button @click="add">添加参数</a-button>
</template>
<script lang="ts" setup>
const emit = defineEmits<{
(e: 'add'): void;
}>();
const add = () => {
emit('add');
};
</script>

View File

@@ -0,0 +1,230 @@
<template>
<a-page-header :title="getPageTitle()" @back="() => $router.go(-1)">
<a-card :bordered="false">
<div class="website-field">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="websiteId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
:need-page="false"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<Search @add="openEdit" />
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
<div
class="ele-text-heading"
@click="copyText(`config.${record.name}`)"
>{{ record.name }}</div
>
<!-- <span class="ele-text-placeholder">{{ record.comments }}</span>-->
</template>
<template v-if="column.key === 'value'">
<a-image
v-if="record.type === 1"
:src="record.value"
:width="120"
/>
<div v-else>{{ record.value }}</div>
</template>
<template v-if="column.key === 'comments'">
<a-popover>
<template #content>
{{ record.comments }}
</template>
{{ record.comments }}
</a-popover>
</template>
<template v-if="column.key === 'action'">
<a @click="copyText('{{ config.' + record.name + ' }}')">调用</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">编辑</a>
<template v-if="record.deleted == 0">
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</template>
<template v-if="record.deleted == 1">
<a-divider type="vertical" />
<a-popconfirm
title="确定要放回原处吗?"
@confirm="recovery(record)"
>
<a class="ele-text-danger">恢复</a>
</a-popconfirm>
</template>
</template>
</template>
</ele-pro-table>
<!-- 编辑弹窗 -->
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</a-card>
</a-page-header>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { message } from 'ant-design-vue';
import type { EleProTable } from 'ele-admin-pro';
import type { DatasourceFunction } from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import Edit from './components/edit.vue';
import {
CmsWebsiteField,
CmsWebsiteFieldParam
} from '@/api/cms/cmsWebsiteField/model';
import {
listCmsWebsiteField,
removeCmsWebsiteField,
undeleteWebsiteField,
updateCmsWebsiteField
} from '@/api/cms/cmsWebsiteField';
import { copyText, getPageTitle } from '@/utils/common';
const props = defineProps<{
websiteId: any;
data: CmsWebsiteField;
}>();
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const selection = ref<any[]>();
// 当前编辑数据
const current = ref<CmsWebsiteField | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
// 搜索条件
return listCmsWebsiteField({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<any[]>([
{
title: '参数名',
dataIndex: 'comments',
key: 'comments',
width: 250,
ellipsis: true
},
{
title: '配置值',
dataIndex: 'value',
key: 'value',
ellipsis: true
},
{
title: '排序',
dataIndex: 'sortNumber',
width: 120,
align: 'center'
},
{
title: '操作',
key: 'action',
width: 180,
align: 'center',
hideInSetting: true
}
]);
const moveUp = (row?: CmsWebsiteField) => {
updateCmsWebsiteField({
id: row?.id,
sortNumber: Number(row?.sortNumber) + 1
}).then((msg) => {
message.success(msg);
reload();
});
};
/* 打开编辑弹窗 */
const openEdit = (row?: CmsWebsiteField) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 搜索 */
const reload = (where?: CmsWebsiteFieldParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 删除单个 */
const remove = (row: CmsWebsiteField) => {
const hide = message.loading('请求中..', 0);
removeCmsWebsiteField(row.id)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
// 从回收站放回原处
const recovery = (row: CmsWebsiteField) => {
const hide = message.loading('请求中..', 0);
undeleteWebsiteField(row.id)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 自定义行属性 */
const customRow = (record: CmsWebsiteField) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
watch(
() => props.websiteId,
(websiteId) => {
if (websiteId) {
reload();
}
},
{ immediate: true }
);
</script>
<script lang="ts">
export default {
name: 'CmsWebsiteFieldIndex'
};
</script>

View File

@@ -16,21 +16,30 @@
:label-col="{ md: { span: 3 }, sm: { span: 4 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 21 }, sm: { span: 22 }, xs: { span: 24 } }"
>
<a-form-item label="参数" name="comments">
<a-form-item label="模板" name="template">
<SelectWebsiteField
:placeholder="`选择参数`"
class="input-item"
v-model:value="form.template"
@done="chooseData"
/>
</a-form-item>
<a-form-item label="参数" name="name">
<a-input
allow-clear
:maxlength="100"
placeholder="网站名称"
v-model:value="form.comments"
placeholder="SiteLogo"
v-model:value="form.name"
@pressEnter="save"
/>
</a-form-item>
<a-form-item label="调用" name="name">
<SelectWebsiteField
:placeholder="`可配置参数`"
class="input-item"
v-model:value="form.name"
@done="chooseData"
<a-form-item label="参数名称" name="comments">
<a-input
allow-clear
:maxlength="100"
placeholder="参数名称"
v-model:value="form.comments"
@pressEnter="save"
/>
</a-form-item>
<a-form-item label="配置值" name="value">
@@ -108,6 +117,7 @@
type: 0,
name: undefined,
value: undefined,
template: '',
modifyRange: undefined,
defaultValue: undefined,
comments: '',
@@ -164,6 +174,7 @@
const chooseData = (data: WebsiteField) => {
assignFields(data);
form.value = data.defaultValue;
form.template = data.defaultValue;
if (data.type == 1) {
images.value.push({
uid: `${data.id}`,

View File

@@ -39,7 +39,6 @@
{{ record.comments }}
</template>
{{ record.comments }}
<!-- <ExclamationCircleOutlined />-->
</a-popover>
</template>
<template v-if="column.key === 'action'">
@@ -80,7 +79,6 @@
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import type { EleProTable } from 'ele-admin-pro';
import type { DatasourceFunction } from 'ele-admin-pro/es/ele-pro-table/types';
@@ -93,7 +91,6 @@
} from '@/api/cms/website/field/model';
import {
listWebsiteField,
pageWebsiteField,
removeWebsiteField,
undeleteWebsiteField,
updateWebsiteField

View File

@@ -31,7 +31,7 @@
<a-button
v-if="record.domain"
type="link"
@click="openSpmUrl(`${record.domain}`, record)"
@click="openSpmUrl(`https://${record.domain}`, record)"
>
{{ record.domain }}
</a-button>

View File

@@ -0,0 +1,676 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑应用' : '添加应用'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="应用名称" name="appName">
<a-input
allow-clear
placeholder="请输入应用名称"
v-model:value="form.appName"
/>
</a-form-item>
<a-form-item label="应用标识" name="appCode">
<a-input
allow-clear
placeholder="请输入应用标识"
v-model:value="form.appCode"
/>
</a-form-item>
<a-form-item label="应用秘钥" name="appSecret">
<a-input
allow-clear
placeholder="请输入应用秘钥"
v-model:value="form.appSecret"
/>
</a-form-item>
<a-form-item label="上级id, 0是顶级" name="parentId">
<a-input
allow-clear
placeholder="请输入上级id, 0是顶级"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="应用类型" name="appType">
<a-input
allow-clear
placeholder="请输入应用类型"
v-model:value="form.appType"
/>
</a-form-item>
<a-form-item label="应用类型" name="appTypeMultiple">
<a-input
allow-clear
placeholder="请输入应用类型"
v-model:value="form.appTypeMultiple"
/>
</a-form-item>
<a-form-item label="类型, 0菜单, 1按钮" name="menuType">
<a-input
allow-clear
placeholder="请输入类型, 0菜单, 1按钮"
v-model:value="form.menuType"
/>
</a-form-item>
<a-form-item label="企业ID" name="companyId">
<a-input
allow-clear
placeholder="请输入企业ID"
v-model:value="form.companyId"
/>
</a-form-item>
<a-form-item label="企业名称" name="companyName">
<a-input
allow-clear
placeholder="请输入企业名称"
v-model:value="form.companyName"
/>
</a-form-item>
<a-form-item label="应用图标" name="appIcon">
<a-input
allow-clear
placeholder="请输入应用图标"
v-model:value="form.appIcon"
/>
</a-form-item>
<a-form-item label="二维码" name="appQrcode">
<a-input
allow-clear
placeholder="请输入二维码"
v-model:value="form.appQrcode"
/>
</a-form-item>
<a-form-item label="链接地址" name="appUrl">
<a-input
allow-clear
placeholder="请输入链接地址"
v-model:value="form.appUrl"
/>
</a-form-item>
<a-form-item label="后台管理地址" name="adminUrl">
<a-input
allow-clear
placeholder="请输入后台管理地址"
v-model:value="form.adminUrl"
/>
</a-form-item>
<a-form-item label="下载地址" name="downUrl">
<a-input
allow-clear
placeholder="请输入下载地址"
v-model:value="form.downUrl"
/>
</a-form-item>
<a-form-item label="链接地址" name="serverUrl">
<a-input
allow-clear
placeholder="请输入链接地址"
v-model:value="form.serverUrl"
/>
</a-form-item>
<a-form-item label="文件服务器" name="fileUrl">
<a-input
allow-clear
placeholder="请输入文件服务器"
v-model:value="form.fileUrl"
/>
</a-form-item>
<a-form-item label="回调地址" name="callbackUrl">
<a-input
allow-clear
placeholder="请输入回调地址"
v-model:value="form.callbackUrl"
/>
</a-form-item>
<a-form-item label="腾讯文档地址" name="docsUrl">
<a-input
allow-clear
placeholder="请输入腾讯文档地址"
v-model:value="form.docsUrl"
/>
</a-form-item>
<a-form-item label="代码仓库地址" name="gitUrl">
<a-input
allow-clear
placeholder="请输入代码仓库地址"
v-model:value="form.gitUrl"
/>
</a-form-item>
<a-form-item label="原型图地址" name="prototypeUrl">
<a-input
allow-clear
placeholder="请输入原型图地址"
v-model:value="form.prototypeUrl"
/>
</a-form-item>
<a-form-item label="IP白名单" name="ipAddress">
<a-input
allow-clear
placeholder="请输入IP白名单"
v-model:value="form.ipAddress"
/>
</a-form-item>
<a-form-item label="应用截图" name="images">
<a-input
allow-clear
placeholder="请输入应用截图"
v-model:value="form.images"
/>
</a-form-item>
<a-form-item label="应用包名" name="packageName">
<a-input
allow-clear
placeholder="请输入应用包名"
v-model:value="form.packageName"
/>
</a-form-item>
<a-form-item label="下载次数" name="clicks">
<a-input
allow-clear
placeholder="请输入下载次数"
v-model:value="form.clicks"
/>
</a-form-item>
<a-form-item label="安装次数" name="installs">
<a-input
allow-clear
placeholder="请输入安装次数"
v-model:value="form.installs"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="应用介绍" name="content">
<a-input
allow-clear
placeholder="请输入应用介绍"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="项目需求" name="requirement">
<a-input
allow-clear
placeholder="请输入项目需求"
v-model:value="form.requirement"
/>
</a-form-item>
<a-form-item label="开发者(个人或公司)" name="developer">
<a-input
allow-clear
placeholder="请输入开发者(个人或公司)"
v-model:value="form.developer"
/>
</a-form-item>
<a-form-item label="项目负责人" name="director">
<a-input
allow-clear
placeholder="请输入项目负责人"
v-model:value="form.director"
/>
</a-form-item>
<a-form-item label="项目经理" name="projectDirector">
<a-input
allow-clear
placeholder="请输入项目经理"
v-model:value="form.projectDirector"
/>
</a-form-item>
<a-form-item label="业务员" name="salesman">
<a-input
allow-clear
placeholder="请输入业务员"
v-model:value="form.salesman"
/>
</a-form-item>
<a-form-item label="软件定价" name="price">
<a-input
allow-clear
placeholder="请输入软件定价"
v-model:value="form.price"
/>
</a-form-item>
<a-form-item label="划线价格" name="linePrice">
<a-input
allow-clear
placeholder="请输入划线价格"
v-model:value="form.linePrice"
/>
</a-form-item>
<a-form-item label="评分" name="score">
<a-input
allow-clear
placeholder="请输入评分"
v-model:value="form.score"
/>
</a-form-item>
<a-form-item label="星级" name="star">
<a-input
allow-clear
placeholder="请输入星级"
v-model:value="form.star"
/>
</a-form-item>
<a-form-item label="菜单路由地址" name="path">
<a-input
allow-clear
placeholder="请输入菜单路由地址"
v-model:value="form.path"
/>
</a-form-item>
<a-form-item label="菜单组件地址, 目录可为空" name="component">
<a-input
allow-clear
placeholder="请输入菜单组件地址, 目录可为空"
v-model:value="form.component"
/>
</a-form-item>
<a-form-item label="权限标识" name="authority">
<a-input
allow-clear
placeholder="请输入权限标识"
v-model:value="form.authority"
/>
</a-form-item>
<a-form-item label="打开位置" name="target">
<a-input
allow-clear
placeholder="请输入打开位置"
v-model:value="form.target"
/>
</a-form-item>
<a-form-item label="是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)" name="hide">
<a-input
allow-clear
placeholder="请输入是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)"
v-model:value="form.hide"
/>
</a-form-item>
<a-form-item label="禁止搜索1禁止 0 允许" name="search">
<a-input
allow-clear
placeholder="请输入禁止搜索1禁止 0 允许"
v-model:value="form.search"
/>
</a-form-item>
<a-form-item label="菜单侧栏选中的path" name="active">
<a-input
allow-clear
placeholder="请输入菜单侧栏选中的path"
v-model:value="form.active"
/>
</a-form-item>
<a-form-item label="其它路由元信息" name="meta">
<a-input
allow-clear
placeholder="请输入其它路由元信息"
v-model:value="form.meta"
/>
</a-form-item>
<a-form-item label="版本0正式版 1体验版 2开发版" name="edition">
<a-input
allow-clear
placeholder="请输入版本0正式版 1体验版 2开发版"
v-model:value="form.edition"
/>
</a-form-item>
<a-form-item label="版本号" name="version">
<a-input
allow-clear
placeholder="请输入版本号"
v-model:value="form.version"
/>
</a-form-item>
<a-form-item label="是否已安装" name="isUse">
<a-input
allow-clear
placeholder="请输入是否已安装"
v-model:value="form.isUse"
/>
</a-form-item>
<a-form-item label="附近1" name="file1">
<a-input
allow-clear
placeholder="请输入附近1"
v-model:value="form.file1"
/>
</a-form-item>
<a-form-item label="附件2" name="file2">
<a-input
allow-clear
placeholder="请输入附件2"
v-model:value="form.file2"
/>
</a-form-item>
<a-form-item label="附件3" name="file3">
<a-input
allow-clear
placeholder="请输入附件3"
v-model:value="form.file3"
/>
</a-form-item>
<a-form-item label="是否显示续费提醒" name="showExpiration">
<a-input
allow-clear
placeholder="请输入是否显示续费提醒"
v-model:value="form.showExpiration"
/>
</a-form-item>
<a-form-item label="是否作为案例展示" name="showCase">
<a-input
allow-clear
placeholder="请输入是否作为案例展示"
v-model:value="form.showCase"
/>
</a-form-item>
<a-form-item label="是否显示在首页" name="showIndex">
<a-input
allow-clear
placeholder="请输入是否显示在首页"
v-model:value="form.showIndex"
/>
</a-form-item>
<a-form-item label="是否推荐" name="recommend">
<a-input
allow-clear
placeholder="请输入是否推荐"
v-model:value="form.recommend"
/>
</a-form-item>
<a-form-item label="到期时间" name="expirationTime">
<a-input
allow-clear
placeholder="请输入到期时间"
v-model:value="form.expirationTime"
/>
</a-form-item>
<a-form-item label="续费金额" name="renewMoney">
<a-input
allow-clear
placeholder="请输入续费金额"
v-model:value="form.renewMoney"
/>
</a-form-item>
<a-form-item label="应用状态" name="appStatus">
<a-input
allow-clear
placeholder="请输入应用状态"
v-model:value="form.appStatus"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="机构id" name="organizationId">
<a-input
allow-clear
placeholder="请输入机构id"
v-model:value="form.organizationId"
/>
</a-form-item>
<a-form-item label="租户编号" name="tenantCode">
<a-input
allow-clear
placeholder="请输入租户编号"
v-model:value="form.tenantCode"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaApp, updateOaApp } from '@/api/oa/oaApp';
import { OaApp } from '@/api/oa/oaApp/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaApp | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaApp>({
appId: undefined,
appName: undefined,
appCode: undefined,
appSecret: undefined,
parentId: undefined,
appType: undefined,
appTypeMultiple: undefined,
menuType: undefined,
companyId: undefined,
companyName: undefined,
appIcon: undefined,
appQrcode: undefined,
appUrl: undefined,
adminUrl: undefined,
downUrl: undefined,
serverUrl: undefined,
fileUrl: undefined,
callbackUrl: undefined,
docsUrl: undefined,
gitUrl: undefined,
prototypeUrl: undefined,
ipAddress: undefined,
images: undefined,
packageName: undefined,
clicks: undefined,
installs: undefined,
comments: undefined,
content: undefined,
requirement: undefined,
developer: undefined,
director: undefined,
projectDirector: undefined,
salesman: undefined,
price: undefined,
linePrice: undefined,
score: undefined,
star: undefined,
path: undefined,
component: undefined,
authority: undefined,
target: undefined,
hide: undefined,
search: undefined,
active: undefined,
meta: undefined,
edition: undefined,
version: undefined,
isUse: undefined,
file1: undefined,
file2: undefined,
file3: undefined,
showExpiration: undefined,
showCase: undefined,
showIndex: undefined,
recommend: undefined,
expirationTime: undefined,
renewMoney: undefined,
appStatus: undefined,
sortNumber: undefined,
status: undefined,
deleted: undefined,
userId: undefined,
organizationId: undefined,
tenantCode: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
oaAppId: undefined,
oaAppName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAppName: [
{
required: true,
type: 'string',
message: '请填写应用名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaApp : addOaApp;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,599 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAppId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAppEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAppEdit from './components/oaAppEdit.vue';
import { pageOaApp, removeOaApp, removeBatchOaApp } from '@/api/oa/oaApp';
import type { OaApp, OaAppParam } from '@/api/oa/oaApp/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaApp[]>([]);
// 当前编辑数据
const current = ref<OaApp | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaApp({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
width: 90,
},
{
title: '应用名称',
dataIndex: 'appName',
key: 'appName',
align: 'center',
},
{
title: '应用标识',
dataIndex: 'appCode',
key: 'appCode',
align: 'center',
},
{
title: '应用秘钥',
dataIndex: 'appSecret',
key: 'appSecret',
align: 'center',
},
{
title: '上级id, 0是顶级',
dataIndex: 'parentId',
key: 'parentId',
align: 'center',
},
{
title: '应用类型',
dataIndex: 'appType',
key: 'appType',
align: 'center',
},
{
title: '应用类型',
dataIndex: 'appTypeMultiple',
key: 'appTypeMultiple',
align: 'center',
},
{
title: '类型, 0菜单, 1按钮',
dataIndex: 'menuType',
key: 'menuType',
align: 'center',
},
{
title: '企业ID',
dataIndex: 'companyId',
key: 'companyId',
align: 'center',
},
{
title: '企业名称',
dataIndex: 'companyName',
key: 'companyName',
align: 'center',
},
{
title: '应用图标',
dataIndex: 'appIcon',
key: 'appIcon',
align: 'center',
},
{
title: '二维码',
dataIndex: 'appQrcode',
key: 'appQrcode',
align: 'center',
},
{
title: '链接地址',
dataIndex: 'appUrl',
key: 'appUrl',
align: 'center',
},
{
title: '后台管理地址',
dataIndex: 'adminUrl',
key: 'adminUrl',
align: 'center',
},
{
title: '下载地址',
dataIndex: 'downUrl',
key: 'downUrl',
align: 'center',
},
{
title: '链接地址',
dataIndex: 'serverUrl',
key: 'serverUrl',
align: 'center',
},
{
title: '文件服务器',
dataIndex: 'fileUrl',
key: 'fileUrl',
align: 'center',
},
{
title: '回调地址',
dataIndex: 'callbackUrl',
key: 'callbackUrl',
align: 'center',
},
{
title: '腾讯文档地址',
dataIndex: 'docsUrl',
key: 'docsUrl',
align: 'center',
},
{
title: '代码仓库地址',
dataIndex: 'gitUrl',
key: 'gitUrl',
align: 'center',
},
{
title: '原型图地址',
dataIndex: 'prototypeUrl',
key: 'prototypeUrl',
align: 'center',
},
{
title: 'IP白名单',
dataIndex: 'ipAddress',
key: 'ipAddress',
align: 'center',
},
{
title: '应用截图',
dataIndex: 'images',
key: 'images',
align: 'center',
},
{
title: '应用包名',
dataIndex: 'packageName',
key: 'packageName',
align: 'center',
},
{
title: '下载次数',
dataIndex: 'clicks',
key: 'clicks',
align: 'center',
},
{
title: '安装次数',
dataIndex: 'installs',
key: 'installs',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '应用介绍',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '项目需求',
dataIndex: 'requirement',
key: 'requirement',
align: 'center',
},
{
title: '开发者(个人或公司)',
dataIndex: 'developer',
key: 'developer',
align: 'center',
},
{
title: '项目负责人',
dataIndex: 'director',
key: 'director',
align: 'center',
},
{
title: '项目经理',
dataIndex: 'projectDirector',
key: 'projectDirector',
align: 'center',
},
{
title: '业务员',
dataIndex: 'salesman',
key: 'salesman',
align: 'center',
},
{
title: '软件定价',
dataIndex: 'price',
key: 'price',
align: 'center',
},
{
title: '划线价格',
dataIndex: 'linePrice',
key: 'linePrice',
align: 'center',
},
{
title: '评分',
dataIndex: 'score',
key: 'score',
align: 'center',
},
{
title: '星级',
dataIndex: 'star',
key: 'star',
align: 'center',
},
{
title: '菜单路由地址',
dataIndex: 'path',
key: 'path',
align: 'center',
},
{
title: '菜单组件地址, 目录可为空',
dataIndex: 'component',
key: 'component',
align: 'center',
},
{
title: '权限标识',
dataIndex: 'authority',
key: 'authority',
align: 'center',
},
{
title: '打开位置',
dataIndex: 'target',
key: 'target',
align: 'center',
},
{
title: '是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)',
dataIndex: 'hide',
key: 'hide',
align: 'center',
},
{
title: '禁止搜索1禁止 0 允许',
dataIndex: 'search',
key: 'search',
align: 'center',
},
{
title: '菜单侧栏选中的path',
dataIndex: 'active',
key: 'active',
align: 'center',
},
{
title: '其它路由元信息',
dataIndex: 'meta',
key: 'meta',
align: 'center',
},
{
title: '版本0正式版 1体验版 2开发版',
dataIndex: 'edition',
key: 'edition',
align: 'center',
},
{
title: '版本号',
dataIndex: 'version',
key: 'version',
align: 'center',
},
{
title: '是否已安装',
dataIndex: 'isUse',
key: 'isUse',
align: 'center',
},
{
title: '附近1',
dataIndex: 'file1',
key: 'file1',
align: 'center',
},
{
title: '附件2',
dataIndex: 'file2',
key: 'file2',
align: 'center',
},
{
title: '附件3',
dataIndex: 'file3',
key: 'file3',
align: 'center',
},
{
title: '是否显示续费提醒',
dataIndex: 'showExpiration',
key: 'showExpiration',
align: 'center',
},
{
title: '是否作为案例展示',
dataIndex: 'showCase',
key: 'showCase',
align: 'center',
},
{
title: '是否显示在首页',
dataIndex: 'showIndex',
key: 'showIndex',
align: 'center',
},
{
title: '是否推荐',
dataIndex: 'recommend',
key: 'recommend',
align: 'center',
},
{
title: '到期时间',
dataIndex: 'expirationTime',
key: 'expirationTime',
align: 'center',
},
{
title: '续费金额',
dataIndex: 'renewMoney',
key: 'renewMoney',
align: 'center',
},
{
title: '应用状态',
dataIndex: 'appStatus',
key: 'appStatus',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '机构id',
dataIndex: 'organizationId',
key: 'organizationId',
align: 'center',
},
{
title: '租户编号',
dataIndex: 'tenantCode',
key: 'tenantCode',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAppParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaApp) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaApp) => {
const hide = message.loading('请求中..', 0);
removeOaApp(row.oaAppId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaApp(selection.value.map((d) => d.oaAppId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaApp) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaApp'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,212 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑应用参数' : '添加应用参数'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="应用ID" name="appId">
<a-input
allow-clear
placeholder="请输入应用ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="名称" name="name">
<a-input
allow-clear
placeholder="请输入名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1删除" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAppField, updateOaAppField } from '@/api/oa/oaAppField';
import { OaAppField } from '@/api/oa/oaAppField/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAppField | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAppField>({
id: undefined,
appId: undefined,
name: undefined,
comments: undefined,
userId: undefined,
status: undefined,
sortNumber: undefined,
tenantId: undefined,
createTime: undefined,
oaAppFieldId: undefined,
oaAppFieldName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAppFieldName: [
{
required: true,
type: 'string',
message: '请填写应用参数名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAppField : addOaAppField;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,251 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAppFieldId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAppFieldEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAppFieldEdit from './components/oaAppFieldEdit.vue';
import { pageOaAppField, removeOaAppField, removeBatchOaAppField } from '@/api/oa/oaAppField';
import type { OaAppField, OaAppFieldParam } from '@/api/oa/oaAppField/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaAppField[]>([]);
// 当前编辑数据
const current = ref<OaAppField | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaAppField({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '状态, 0正常, 1删除',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAppFieldParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaAppField) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaAppField) => {
const hide = message.loading('请求中..', 0);
removeOaAppField(row.oaAppFieldId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaAppField(selection.value.map((d) => d.oaAppFieldId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaAppField) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaAppField'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,242 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑续费管理' : '添加续费管理'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="应用ID" name="appId">
<a-input
allow-clear
placeholder="请输入应用ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="续费金额" name="money">
<a-input
allow-clear
placeholder="请输入续费金额"
v-model:value="form.money"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="开始时间" name="startTime">
<a-input
allow-clear
placeholder="请输入开始时间"
v-model:value="form.startTime"
/>
</a-form-item>
<a-form-item label="到期时间" name="endTime">
<a-input
allow-clear
placeholder="请输入到期时间"
v-model:value="form.endTime"
/>
</a-form-item>
<a-form-item label="企业ID" name="companyId">
<a-input
allow-clear
placeholder="请输入企业ID"
v-model:value="form.companyId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="付款凭证" name="images">
<a-input
allow-clear
placeholder="请输入付款凭证"
v-model:value="form.images"
/>
</a-form-item>
<a-form-item label="用户姓名" name="nickname">
<a-input
allow-clear
placeholder="请输入用户姓名"
v-model:value="form.nickname"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1待确认" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAppRenew, updateOaAppRenew } from '@/api/oa/oaAppRenew';
import { OaAppRenew } from '@/api/oa/oaAppRenew/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAppRenew | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAppRenew>({
appRenewId: undefined,
appId: undefined,
money: undefined,
comments: undefined,
startTime: undefined,
endTime: undefined,
companyId: undefined,
userId: undefined,
images: undefined,
nickname: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
oaAppRenewId: undefined,
oaAppRenewName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAppRenewName: [
{
required: true,
type: 'string',
message: '请填写续费管理名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAppRenew : addOaAppRenew;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,275 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAppRenewId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAppRenewEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAppRenewEdit from './components/oaAppRenewEdit.vue';
import { pageOaAppRenew, removeOaAppRenew, removeBatchOaAppRenew } from '@/api/oa/oaAppRenew';
import type { OaAppRenew, OaAppRenewParam } from '@/api/oa/oaAppRenew/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaAppRenew[]>([]);
// 当前编辑数据
const current = ref<OaAppRenew | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaAppRenew({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'appRenewId',
key: 'appRenewId',
align: 'center',
width: 90,
},
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '续费金额',
dataIndex: 'money',
key: 'money',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '开始时间',
dataIndex: 'startTime',
key: 'startTime',
align: 'center',
},
{
title: '到期时间',
dataIndex: 'endTime',
key: 'endTime',
align: 'center',
},
{
title: '企业ID',
dataIndex: 'companyId',
key: 'companyId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '付款凭证',
dataIndex: 'images',
key: 'images',
align: 'center',
},
{
title: '用户姓名',
dataIndex: 'nickname',
key: 'nickname',
align: 'center',
},
{
title: '状态, 0正常, 1待确认',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAppRenewParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaAppRenew) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaAppRenew) => {
const hide = message.loading('请求中..', 0);
removeOaAppRenew(row.oaAppRenewId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaAppRenew(selection.value.map((d) => d.oaAppRenewId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaAppRenew) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaAppRenew'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,228 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑项目域名' : '添加项目域名'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="应用ID" name="appId">
<a-input
allow-clear
placeholder="请输入应用ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="域名类型" name="name">
<a-input
allow-clear
placeholder="请输入域名类型"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="域名" name="domain">
<a-input
allow-clear
placeholder="请输入域名"
v-model:value="form.domain"
/>
</a-form-item>
<a-form-item label="账号" name="account">
<a-input
allow-clear
placeholder="请输入账号"
v-model:value="form.account"
/>
</a-form-item>
<a-form-item label="密码" name="password">
<a-input
allow-clear
placeholder="请输入密码"
v-model:value="form.password"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1待确认" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAppUrl, updateOaAppUrl } from '@/api/oa/oaAppUrl';
import { OaAppUrl } from '@/api/oa/oaAppUrl/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAppUrl | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAppUrl>({
appUrlId: undefined,
appId: undefined,
name: undefined,
domain: undefined,
account: undefined,
password: undefined,
comments: undefined,
sortNumber: undefined,
status: undefined,
createTime: undefined,
tenantId: undefined,
oaAppUrlId: undefined,
oaAppUrlName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAppUrlName: [
{
required: true,
type: 'string',
message: '请填写项目域名名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAppUrl : addOaAppUrl;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,263 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAppUrlId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAppUrlEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAppUrlEdit from './components/oaAppUrlEdit.vue';
import { pageOaAppUrl, removeOaAppUrl, removeBatchOaAppUrl } from '@/api/oa/oaAppUrl';
import type { OaAppUrl, OaAppUrlParam } from '@/api/oa/oaAppUrl/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaAppUrl[]>([]);
// 当前编辑数据
const current = ref<OaAppUrl | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaAppUrl({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'appUrlId',
key: 'appUrlId',
align: 'center',
width: 90,
},
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '域名类型',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '域名',
dataIndex: 'domain',
key: 'domain',
align: 'center',
},
{
title: '账号',
dataIndex: 'account',
key: 'account',
align: 'center',
},
{
title: '密码',
dataIndex: 'password',
key: 'password',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '状态, 0正常, 1待确认',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAppUrlParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaAppUrl) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaAppUrl) => {
const hide = message.loading('请求中..', 0);
removeOaAppUrl(row.oaAppUrlId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaAppUrl(selection.value.map((d) => d.oaAppUrlId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaAppUrl) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaAppUrl'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,201 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑应用成员' : '添加应用成员'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="角色10体验成员 20开发者成员 30管理员 " name="role">
<a-input
allow-clear
placeholder="请输入角色10体验成员 20开发者成员 30管理员 "
v-model:value="form.role"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="应用ID" name="appId">
<a-input
allow-clear
placeholder="请输入应用ID"
v-model:value="form.appId"
/>
</a-form-item>
<a-form-item label="昵称" name="nickname">
<a-input
allow-clear
placeholder="请输入昵称"
v-model:value="form.nickname"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1待确认" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAppUser, updateOaAppUser } from '@/api/oa/oaAppUser';
import { OaAppUser } from '@/api/oa/oaAppUser/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAppUser | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAppUser>({
appUserId: undefined,
role: undefined,
userId: undefined,
appId: undefined,
nickname: undefined,
status: undefined,
tenantId: undefined,
createTime: undefined,
oaAppUserId: undefined,
oaAppUserName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAppUserName: [
{
required: true,
type: 'string',
message: '请填写应用成员名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAppUser : addOaAppUser;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,245 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAppUserId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAppUserEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAppUserEdit from './components/oaAppUserEdit.vue';
import { pageOaAppUser, removeOaAppUser, removeBatchOaAppUser } from '@/api/oa/oaAppUser';
import type { OaAppUser, OaAppUserParam } from '@/api/oa/oaAppUser/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaAppUser[]>([]);
// 当前编辑数据
const current = ref<OaAppUser | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaAppUser({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '自增ID',
dataIndex: 'appUserId',
key: 'appUserId',
align: 'center',
width: 90,
},
{
title: '角色10体验成员 20开发者成员 30管理员 ',
dataIndex: 'role',
key: 'role',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '应用ID',
dataIndex: 'appId',
key: 'appId',
align: 'center',
},
{
title: '昵称',
dataIndex: 'nickname',
key: 'nickname',
align: 'center',
},
{
title: '状态, 0正常, 1待确认',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAppUserParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaAppUser) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaAppUser) => {
const hide = message.loading('请求中..', 0);
removeOaAppUser(row.oaAppUserId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaAppUser(selection.value.map((d) => d.oaAppUserId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaAppUser) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaAppUser'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,444 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑服务器资产记录表' : '添加服务器资产记录表'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="资产名称" name="name">
<a-input
allow-clear
placeholder="请输入资产名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="资产标识" name="code">
<a-input
allow-clear
placeholder="请输入资产标识"
v-model:value="form.code"
/>
</a-form-item>
<a-form-item label="资产类型" name="type">
<a-input
allow-clear
placeholder="请输入资产类型"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="服务器厂商" name="brand">
<a-input
allow-clear
placeholder="请输入服务器厂商"
v-model:value="form.brand"
/>
</a-form-item>
<a-form-item label="服务器配置" name="configuration">
<a-input
allow-clear
placeholder="请输入服务器配置"
v-model:value="form.configuration"
/>
</a-form-item>
<a-form-item label="初始账号" name="account">
<a-input
allow-clear
placeholder="请输入初始账号"
v-model:value="form.account"
/>
</a-form-item>
<a-form-item label="初始密码" name="password">
<a-input
allow-clear
placeholder="请输入初始密码"
v-model:value="form.password"
/>
</a-form-item>
<a-form-item label="(阿里云/腾讯云)登录账号" name="brandAccount">
<a-input
allow-clear
placeholder="请输入(阿里云/腾讯云)登录账号"
v-model:value="form.brandAccount"
/>
</a-form-item>
<a-form-item label="(阿里云/腾讯云)登录密码" name="brandPassword">
<a-input
allow-clear
placeholder="请输入(阿里云/腾讯云)登录密码"
v-model:value="form.brandPassword"
/>
</a-form-item>
<a-form-item label="宝塔面板" name="panel">
<a-input
allow-clear
placeholder="请输入宝塔面板"
v-model:value="form.panel"
/>
</a-form-item>
<a-form-item label="宝塔面板账号" name="panelAccount">
<a-input
allow-clear
placeholder="请输入宝塔面板账号"
v-model:value="form.panelAccount"
/>
</a-form-item>
<a-form-item label="宝塔面板密码" name="panelPassword">
<a-input
allow-clear
placeholder="请输入宝塔面板密码"
v-model:value="form.panelPassword"
/>
</a-form-item>
<a-form-item label="财务信息-合同金额" name="financeAmount">
<a-input
allow-clear
placeholder="请输入财务信息-合同金额"
v-model:value="form.financeAmount"
/>
</a-form-item>
<a-form-item label="购买年限" name="financeYears">
<a-input
allow-clear
placeholder="请输入购买年限"
v-model:value="form.financeYears"
/>
</a-form-item>
<a-form-item label="续费金额" name="financeRenew">
<a-input
allow-clear
placeholder="请输入续费金额"
v-model:value="form.financeRenew"
/>
</a-form-item>
<a-form-item label="客户名称" name="financeCustomerName">
<a-input
allow-clear
placeholder="请输入客户名称"
v-model:value="form.financeCustomerName"
/>
</a-form-item>
<a-form-item label="客户联系人" name="financeCustomerContact">
<a-input
allow-clear
placeholder="请输入客户联系人"
v-model:value="form.financeCustomerContact"
/>
</a-form-item>
<a-form-item label="客户联系电话" name="financeCustomerPhone">
<a-input
allow-clear
placeholder="请输入客户联系电话"
v-model:value="form.financeCustomerPhone"
/>
</a-form-item>
<a-form-item label="客户ID" name="customerId">
<a-input
allow-clear
placeholder="请输入客户ID"
v-model:value="form.customerId"
/>
</a-form-item>
<a-form-item label="客户名称" name="customerName">
<a-input
allow-clear
placeholder="请输入客户名称"
v-model:value="form.customerName"
/>
</a-form-item>
<a-form-item label="开放端口" name="openPort">
<a-input
allow-clear
placeholder="请输入开放端口"
v-model:value="form.openPort"
/>
</a-form-item>
<a-form-item label="详情内容" name="content">
<a-input
allow-clear
placeholder="请输入详情内容"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="购买时间" name="startTime">
<a-input
allow-clear
placeholder="请输入购买时间"
v-model:value="form.startTime"
/>
</a-form-item>
<a-form-item label="到期时间" name="endTime">
<a-input
allow-clear
placeholder="请输入到期时间"
v-model:value="form.endTime"
/>
</a-form-item>
<a-form-item label="置顶状态" name="isTop">
<a-input
allow-clear
placeholder="请输入置顶状态"
v-model:value="form.isTop"
/>
</a-form-item>
<a-form-item label="可见性(public,private,protected)" name="visibility">
<a-input
allow-clear
placeholder="请输入可见性(public,private,protected)"
v-model:value="form.visibility"
/>
</a-form-item>
<a-form-item label="宝塔接口秘钥" name="btSign">
<a-input
allow-clear
placeholder="请输入宝塔接口秘钥"
v-model:value="form.btSign"
/>
</a-form-item>
<a-form-item label="文章排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="描述" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="客户ID" name="companyId">
<a-input
allow-clear
placeholder="请输入客户ID"
v-model:value="form.companyId"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="机构id" name="organizationId">
<a-input
allow-clear
placeholder="请输入机构id"
v-model:value="form.organizationId"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAssets, updateOaAssets } from '@/api/oa/oaAssets';
import { OaAssets } from '@/api/oa/oaAssets/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAssets | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAssets>({
assetsId: undefined,
name: undefined,
code: undefined,
type: undefined,
brand: undefined,
configuration: undefined,
account: undefined,
password: undefined,
brandAccount: undefined,
brandPassword: undefined,
panel: undefined,
panelAccount: undefined,
panelPassword: undefined,
financeAmount: undefined,
financeYears: undefined,
financeRenew: undefined,
financeCustomerName: undefined,
financeCustomerContact: undefined,
financeCustomerPhone: undefined,
customerId: undefined,
customerName: undefined,
openPort: undefined,
content: undefined,
startTime: undefined,
endTime: undefined,
isTop: undefined,
visibility: undefined,
btSign: undefined,
sortNumber: undefined,
comments: undefined,
companyId: undefined,
userId: undefined,
organizationId: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
oaAssetsId: undefined,
oaAssetsName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAssetsName: [
{
required: true,
type: 'string',
message: '请填写服务器资产记录表名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAssets : addOaAssets;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加</span>
</a-button>
</a-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,425 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="oaAssetsId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<OaAssetsEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import { toDateString } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import OaAssetsEdit from './components/oaAssetsEdit.vue';
import { pageOaAssets, removeOaAssets, removeBatchOaAssets } from '@/api/oa/oaAssets';
import type { OaAssets, OaAssetsParam } from '@/api/oa/oaAssets/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<OaAssets[]>([]);
// 当前编辑数据
const current = ref<OaAssets | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageOaAssets({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '资产ID',
dataIndex: 'assetsId',
key: 'assetsId',
align: 'center',
width: 90,
},
{
title: '资产名称',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '资产标识',
dataIndex: 'code',
key: 'code',
align: 'center',
},
{
title: '资产类型',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '服务器厂商',
dataIndex: 'brand',
key: 'brand',
align: 'center',
},
{
title: '服务器配置',
dataIndex: 'configuration',
key: 'configuration',
align: 'center',
},
{
title: '初始账号',
dataIndex: 'account',
key: 'account',
align: 'center',
},
{
title: '初始密码',
dataIndex: 'password',
key: 'password',
align: 'center',
},
{
title: '(阿里云/腾讯云)登录账号',
dataIndex: 'brandAccount',
key: 'brandAccount',
align: 'center',
},
{
title: '(阿里云/腾讯云)登录密码',
dataIndex: 'brandPassword',
key: 'brandPassword',
align: 'center',
},
{
title: '宝塔面板',
dataIndex: 'panel',
key: 'panel',
align: 'center',
},
{
title: '宝塔面板账号',
dataIndex: 'panelAccount',
key: 'panelAccount',
align: 'center',
},
{
title: '宝塔面板密码',
dataIndex: 'panelPassword',
key: 'panelPassword',
align: 'center',
},
{
title: '财务信息-合同金额',
dataIndex: 'financeAmount',
key: 'financeAmount',
align: 'center',
},
{
title: '购买年限',
dataIndex: 'financeYears',
key: 'financeYears',
align: 'center',
},
{
title: '续费金额',
dataIndex: 'financeRenew',
key: 'financeRenew',
align: 'center',
},
{
title: '客户名称',
dataIndex: 'financeCustomerName',
key: 'financeCustomerName',
align: 'center',
},
{
title: '客户联系人',
dataIndex: 'financeCustomerContact',
key: 'financeCustomerContact',
align: 'center',
},
{
title: '客户联系电话',
dataIndex: 'financeCustomerPhone',
key: 'financeCustomerPhone',
align: 'center',
},
{
title: '客户ID',
dataIndex: 'customerId',
key: 'customerId',
align: 'center',
},
{
title: '客户名称',
dataIndex: 'customerName',
key: 'customerName',
align: 'center',
},
{
title: '开放端口',
dataIndex: 'openPort',
key: 'openPort',
align: 'center',
},
{
title: '详情内容',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '购买时间',
dataIndex: 'startTime',
key: 'startTime',
align: 'center',
},
{
title: '到期时间',
dataIndex: 'endTime',
key: 'endTime',
align: 'center',
},
{
title: '置顶状态',
dataIndex: 'isTop',
key: 'isTop',
align: 'center',
},
{
title: '可见性(public,private,protected)',
dataIndex: 'visibility',
key: 'visibility',
align: 'center',
},
{
title: '宝塔接口秘钥',
dataIndex: 'btSign',
key: 'btSign',
align: 'center',
},
{
title: '文章排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '描述',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '客户ID',
dataIndex: 'companyId',
key: 'companyId',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '机构id',
dataIndex: 'organizationId',
key: 'organizationId',
align: 'center',
},
{
title: '状态, 0正常, 1冻结',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: OaAssetsParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: OaAssets) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: OaAssets) => {
const hide = message.loading('请求中..', 0);
removeOaAssets(row.oaAssetsId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchOaAssets(selection.value.map((d) => d.oaAssetsId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: OaAssets) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'OaAssets'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,284 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑代码仓库' : '添加代码仓库'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="名称" name="name">
<a-input
allow-clear
placeholder="请输入名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="英文标识" name="code">
<a-input
allow-clear
placeholder="请输入英文标识"
v-model:value="form.code"
/>
</a-form-item>
<a-form-item label="仓库地址" name="gitUrl">
<a-input
allow-clear
placeholder="请输入仓库地址"
v-model:value="form.gitUrl"
/>
</a-form-item>
<a-form-item label="仓库品牌" name="brand">
<a-input
allow-clear
placeholder="请输入仓库品牌"
v-model:value="form.brand"
/>
</a-form-item>
<a-form-item label="价格" name="price">
<a-input
allow-clear
placeholder="请输入价格"
v-model:value="form.price"
/>
</a-form-item>
<a-form-item label="详情内容" name="content">
<a-input
allow-clear
placeholder="请输入详情内容"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="购买时间" name="startTime">
<a-input
allow-clear
placeholder="请输入购买时间"
v-model:value="form.startTime"
/>
</a-form-item>
<a-form-item label="到期时间" name="endTime">
<a-input
allow-clear
placeholder="请输入到期时间"
v-model:value="form.endTime"
/>
</a-form-item>
<a-form-item label="置顶状态" name="isTop">
<a-input
allow-clear
placeholder="请输入置顶状态"
v-model:value="form.isTop"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="描述" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="状态, 0正常, 1冻结" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addOaAssetsCode, updateOaAssetsCode } from '@/api/oa/oaAssetsCode';
import { OaAssetsCode } from '@/api/oa/oaAssetsCode/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: OaAssetsCode | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<OaAssetsCode>({
id: undefined,
name: undefined,
code: undefined,
gitUrl: undefined,
brand: undefined,
price: undefined,
content: undefined,
startTime: undefined,
endTime: undefined,
isTop: undefined,
sortNumber: undefined,
comments: undefined,
userId: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
oaAssetsCodeId: undefined,
oaAssetsCodeName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
oaAssetsCodeName: [
{
required: true,
type: 'string',
message: '请填写代码仓库名称',
trigger: 'blur'
}
]
});
const chooseImage = (data: FileRecord) => {
images.value.push({
uid: data.id,
url: data.path,
status: 'done'
});
form.image = data.path;
};
const onDeleteItem = (index: number) => {
images.value.splice(index, 1);
form.image = '';
};
const { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateOaAssetsCode : addOaAssetsCode;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

Some files were not shown because too many files have changed in this diff Show More