优化修复网站导航的bug
This commit is contained in:
@@ -141,3 +141,13 @@ export async function checkExistence(
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
export async function getCount(params: ArticleParam) {
|
||||
const res = await request.get(MODULES_API_URL + '/cms/article/data', {
|
||||
params
|
||||
});
|
||||
if (res.data.code === 0) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface ArticleParam extends PageParam {
|
||||
articleId?: number;
|
||||
categoryId?: number;
|
||||
navigationId?: number;
|
||||
status?: string;
|
||||
status?: number;
|
||||
sortNumber?: string;
|
||||
createTime?: string;
|
||||
username?: string;
|
||||
|
||||
@@ -4,13 +4,20 @@
|
||||
export interface Navigation {
|
||||
navigationId?: number;
|
||||
parentId?: number;
|
||||
parentName?: string;
|
||||
parentPath?: string;
|
||||
title?: string;
|
||||
code?: string;
|
||||
path?: string;
|
||||
icon?: string;
|
||||
component?: string;
|
||||
model?: string;
|
||||
modelName?: string;
|
||||
type?: number;
|
||||
sortNumber?: number;
|
||||
hide?: number;
|
||||
permission?: number;
|
||||
password?: string;
|
||||
home?: number;
|
||||
position?: number;
|
||||
top?: number;
|
||||
@@ -31,6 +38,8 @@ export interface Navigation {
|
||||
pageName?: string;
|
||||
createTime?: string;
|
||||
isMpWeixin?: boolean;
|
||||
label?: string;
|
||||
value?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,8 @@ export interface WebsiteField {
|
||||
value?: string;
|
||||
comments?: string;
|
||||
userId?: number;
|
||||
defaultValue?: string;
|
||||
modifyRange?: string;
|
||||
type?: number;
|
||||
status?: any;
|
||||
sortNumber?: any;
|
||||
|
||||
@@ -4,15 +4,15 @@ import type {
|
||||
Config,
|
||||
WebsiteField,
|
||||
WebsiteFieldParam
|
||||
} from "@/api/cms/website/field/model";
|
||||
import { MODULES_API_URL } from '@/config/setting';
|
||||
} from '@/api/cms/website/field/model';
|
||||
import { MODULES_API_URL, SERVER_API_URL } from "@/config/setting";
|
||||
|
||||
/**
|
||||
* 分页查询项目参数
|
||||
*/
|
||||
export async function pageWebsiteField(params: WebsiteFieldParam) {
|
||||
const res = await request.get<ApiResult<PageResult<WebsiteField>>>(
|
||||
MODULES_API_URL + '/cms/website-field/page',
|
||||
SERVER_API_URL + '/system/website-field/page',
|
||||
{
|
||||
params
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export async function pageWebsiteField(params: WebsiteFieldParam) {
|
||||
*/
|
||||
export async function listWebsiteField(params?: WebsiteFieldParam) {
|
||||
const res = await request.get<ApiResult<WebsiteField[]>>(
|
||||
'https://modules.gxwebsoft.com/api/cms/website-field',
|
||||
SERVER_API_URL + '/system/website-field',
|
||||
{
|
||||
params
|
||||
}
|
||||
@@ -44,7 +44,7 @@ export async function listWebsiteField(params?: WebsiteFieldParam) {
|
||||
*/
|
||||
export async function getWebsiteField(id: number) {
|
||||
const res = await request.get<ApiResult<WebsiteField>>(
|
||||
MODULES_API_URL + '/cms/website-field/' + id
|
||||
SERVER_API_URL + '/system/website-field/' + id
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
@@ -57,7 +57,7 @@ export async function getWebsiteField(id: number) {
|
||||
*/
|
||||
export async function addWebsiteField(data: WebsiteField) {
|
||||
const res = await request.post<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field',
|
||||
SERVER_API_URL + '/system/website-field',
|
||||
data
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
@@ -71,7 +71,7 @@ export async function addWebsiteField(data: WebsiteField) {
|
||||
*/
|
||||
export async function updateWebsiteField(data: WebsiteField) {
|
||||
const res = await request.put<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field',
|
||||
SERVER_API_URL + '/system/website-field',
|
||||
data
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
@@ -85,7 +85,7 @@ export async function updateWebsiteField(data: WebsiteField) {
|
||||
*/
|
||||
export async function removeWebsiteField(id?: number) {
|
||||
const res = await request.delete<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field/' + id
|
||||
SERVER_API_URL + '/system/website-field/' + id
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.message;
|
||||
@@ -98,7 +98,7 @@ export async function removeWebsiteField(id?: number) {
|
||||
*/
|
||||
export async function removeBatchWebsiteField(data: (number | undefined)[]) {
|
||||
const res = await request.delete<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field/batch',
|
||||
SERVER_API_URL + '/system/website-field/batch',
|
||||
{
|
||||
data
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export async function checkExistence(
|
||||
id?: number
|
||||
) {
|
||||
const res = await request.get<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field/existence',
|
||||
SERVER_API_URL + '/system/website-field/existence',
|
||||
{
|
||||
params: { field, value, id }
|
||||
}
|
||||
@@ -134,7 +134,7 @@ export async function checkExistence(
|
||||
*/
|
||||
export async function configWebsiteField(params?: WebsiteFieldParam) {
|
||||
const res = await request.get<ApiResult<Config>>(
|
||||
'https://modules.gxwebsoft.com/api/cms/website-field/config',
|
||||
'https://modules.gxwebsoft.com/api/system/website-field/config',
|
||||
{
|
||||
params
|
||||
}
|
||||
@@ -144,3 +144,16 @@ export async function configWebsiteField(params?: WebsiteFieldParam) {
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复项目参数
|
||||
*/
|
||||
export async function undeleteWebsiteField(id?: number) {
|
||||
const res = await request.delete<ApiResult<unknown>>(
|
||||
MODULES_API_URL + '/cms/website-field/undelete/' + id
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.message;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
@@ -9,10 +9,31 @@ export interface WebsiteField {
|
||||
value?: string;
|
||||
comments?: string;
|
||||
userId?: number;
|
||||
websiteId?: number;
|
||||
defaultValue?: string;
|
||||
modifyRange?: string;
|
||||
type?: number;
|
||||
status?: any;
|
||||
sortNumber?: any;
|
||||
createTime?: string;
|
||||
deleted?: number;
|
||||
}
|
||||
|
||||
// 约定的网站参数名称
|
||||
export interface WebsiteParam {
|
||||
// 网站名称
|
||||
site_logo?: string;
|
||||
// 登录页面标题
|
||||
login_name?: string;
|
||||
// 登录页面的背景图片
|
||||
login_bg_img?: string;
|
||||
}
|
||||
|
||||
// 约定的小程序参数名称
|
||||
export interface MpWeixinParam {
|
||||
// 小程序LOGO
|
||||
site_logo?: string;
|
||||
// 我的页面顶部背景图片
|
||||
mp_user_top?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,5 +42,22 @@ export interface WebsiteField {
|
||||
export interface WebsiteFieldParam extends PageParam {
|
||||
id?: number;
|
||||
userId?: number;
|
||||
name?: string;
|
||||
websiteId?: number;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
siteName?: string;
|
||||
siteLogo?: string;
|
||||
domain?: string;
|
||||
icpNo?: string;
|
||||
copyright?: string;
|
||||
loginBgImg?: string;
|
||||
address?: string;
|
||||
tel?: string;
|
||||
kefu2?: string;
|
||||
kefu1?: string;
|
||||
email?: string;
|
||||
loginTitle?: string;
|
||||
sysLogo?: string;
|
||||
}
|
||||
|
||||
72
src/components/ChooseDictionary/index.vue
Normal file
72
src/components/ChooseDictionary/index.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<!-- 公共参数数据源 -->
|
||||
<template>
|
||||
<a-select
|
||||
:allow-clear="allowClear"
|
||||
show-search
|
||||
optionFilterProp="label"
|
||||
:options="data"
|
||||
:value="value"
|
||||
class="w-full"
|
||||
:placeholder="placeholder"
|
||||
@update:value="updateValue"
|
||||
@change="change"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { listDictionaryData } from '@/api/system/dictionary-data';
|
||||
import type { DictionaryData } from '@/api/system/dictionary-data/model';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string): void;
|
||||
(e: 'index', index: number): void;
|
||||
(e: 'blur'): void;
|
||||
(e: 'done', item: DictionaryData): void;
|
||||
}>();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
allowClear?: boolean;
|
||||
width?: number;
|
||||
index?: number;
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择'
|
||||
}
|
||||
);
|
||||
|
||||
const data = ref<DictionaryData[]>();
|
||||
|
||||
/* 更新选中数据 */
|
||||
const updateValue = (value: string) => {
|
||||
emit('update:value', value);
|
||||
emit('index', Number(props.index));
|
||||
};
|
||||
|
||||
/* 失去焦点 */
|
||||
const onBlur = () => {
|
||||
emit('blur');
|
||||
};
|
||||
|
||||
const change = (e: any, item: any) => {
|
||||
emit('done', item);
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
data.value = [];
|
||||
listDictionaryData({ dictCode: 'NavigationModel' }).then((list) => {
|
||||
data.value = list.map((d) => {
|
||||
return {
|
||||
label: d.dictDataName,
|
||||
value: d.dictDataCode
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
reload();
|
||||
</script>
|
||||
72
src/components/ChooseWebsiteField/index.vue
Normal file
72
src/components/ChooseWebsiteField/index.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<!-- 公共参数数据源 -->
|
||||
<template>
|
||||
<a-select
|
||||
:allow-clear="allowClear"
|
||||
show-search
|
||||
optionFilterProp="label"
|
||||
:options="data"
|
||||
:value="value"
|
||||
class="w-full"
|
||||
:placeholder="placeholder"
|
||||
@update:value="updateValue"
|
||||
@change="change"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { listWebsiteField } from '@/api/system/website/field';
|
||||
import { WebsiteField } from '@/api/cms/website/field/model';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string): void;
|
||||
(e: 'index', index: number): void;
|
||||
(e: 'blur'): void;
|
||||
(e: 'done', item: WebsiteField): void;
|
||||
}>();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
allowClear?: boolean;
|
||||
width?: number;
|
||||
index?: number;
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择'
|
||||
}
|
||||
);
|
||||
|
||||
const data = ref<WebsiteField[]>();
|
||||
|
||||
/* 更新选中数据 */
|
||||
const updateValue = (value: string) => {
|
||||
emit('update:value', value);
|
||||
emit('index', Number(props.index));
|
||||
};
|
||||
|
||||
/* 失去焦点 */
|
||||
const onBlur = () => {
|
||||
emit('blur');
|
||||
};
|
||||
|
||||
const change = (e, item) => {
|
||||
emit('done', item);
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
data.value = [];
|
||||
listWebsiteField({}).then((list) => {
|
||||
data.value = list.map((d) => {
|
||||
return {
|
||||
label: d.name,
|
||||
value: d.value
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
reload();
|
||||
</script>
|
||||
@@ -48,9 +48,8 @@
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import { EleProTable } from 'ele-admin-pro';
|
||||
import useSearch from '@/utils/use-search';
|
||||
import { pageDictData } from '@/api/system/dict-data';
|
||||
import { DictData, DictDataParam } from '@/api/system/dict-data/model';
|
||||
import { pageDictionaryData } from "@/api/system/dictionary-data";
|
||||
import { pageDictionaryData } from '@/api/system/dictionary-data';
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
|
||||
@@ -47,9 +47,23 @@
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a-button
|
||||
size="small"
|
||||
type="link"
|
||||
@click="onRadio"
|
||||
:disabled="record.type == model"
|
||||
class="cursor-pointer"
|
||||
>{{ record.title }}</a-button
|
||||
>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<template v-if="pageId == record.id">
|
||||
<a-radio v-model:checked="checked" @click="onRadio(record)" />
|
||||
<a-radio
|
||||
v-model:checked="checked"
|
||||
disabled
|
||||
@click="onRadio(record)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<lebal>
|
||||
@@ -65,14 +79,16 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
ColumnItem,
|
||||
DatasourceFunction
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import { listNavigation, pageNavigation } from '@/api/cms/navigation';
|
||||
import { EleProTable } from 'ele-admin-pro';
|
||||
import { toTreeData } from 'ele-admin-pro/es';
|
||||
import { toTreeData, eachTreeData } from 'ele-admin-pro/es';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem,
|
||||
EleProTableDone
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import type { Navigation, NavigationParam } from '@/api/cms/navigation/model';
|
||||
import type { Menu } from '@/api/system/menu/model';
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
@@ -81,6 +97,8 @@
|
||||
title?: string;
|
||||
// 修改回显的数据
|
||||
data?: Navigation | null;
|
||||
// 当前模型
|
||||
model?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -100,6 +118,8 @@
|
||||
const expandedRowKeys = ref<number[]>([]);
|
||||
const searchText = ref('');
|
||||
const position = ref(1);
|
||||
// 菜单数据
|
||||
const menuData = ref<Navigation[]>([]);
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
@@ -137,9 +157,13 @@
|
||||
return listNavigation({ ...where });
|
||||
};
|
||||
|
||||
/* 表格渲染完成回调 */
|
||||
const onDone: EleProTableDone<Navigation> = ({ data }) => {
|
||||
menuData.value = data;
|
||||
};
|
||||
|
||||
/* 数据转为树形结构 */
|
||||
const parseData = (data: Navigation[]) => {
|
||||
console.log(data);
|
||||
return toTreeData({
|
||||
data: data.map((d) => {
|
||||
return { ...d, key: d.navigationId, value: d.navigationId };
|
||||
@@ -149,6 +173,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
/* 展开全部 */
|
||||
const expandAll = () => {
|
||||
let keys: number[] = [];
|
||||
eachTreeData(menuData.value, (d) => {
|
||||
if (d.children && d.children.length && d.navigationId) {
|
||||
keys.push(d.navigationId);
|
||||
}
|
||||
});
|
||||
expandedRowKeys.value = keys;
|
||||
};
|
||||
|
||||
/* 折叠全部 */
|
||||
const foldAll = () => {
|
||||
expandedRowKeys.value = [];
|
||||
};
|
||||
|
||||
/* 点击展开图标时触发 */
|
||||
const onExpand = (expanded: boolean, record: Navigation) => {
|
||||
if (expanded) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
v-model:visible="showEdit"
|
||||
:data="current"
|
||||
:title="placeholder"
|
||||
:model="model"
|
||||
@done="onChange"
|
||||
/>
|
||||
</div>
|
||||
@@ -31,6 +32,7 @@
|
||||
defineProps<{
|
||||
value?: any;
|
||||
placeholder?: string;
|
||||
model?: string;
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择'
|
||||
|
||||
170
src/components/SelectWebsiteField/components/select-data.vue
Normal file
170
src/components/SelectWebsiteField/components/select-data.vue
Normal file
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<ele-modal
|
||||
width="70%"
|
||||
:visible="visible"
|
||||
:maskClosable="false"
|
||||
:title="title"
|
||||
:footer="null"
|
||||
:body-style="{ paddingBottom: '28px' }"
|
||||
@update:visible="updateVisible"
|
||||
>
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:datasource="datasource"
|
||||
:columns="columns"
|
||||
:customRow="customRow"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #toolbar>
|
||||
<a-input-search
|
||||
allow-clear
|
||||
v-model:value="searchText"
|
||||
placeholder="请输入搜索关键词"
|
||||
style="width: 200px"
|
||||
@search="reload"
|
||||
@pressEnter="reload"
|
||||
/>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'name'">
|
||||
<div class="ele-text-heading" @click="onRadio(record)">
|
||||
{{ record.name }}
|
||||
</div>
|
||||
<div class="ele-text-placeholder">{{ record.comments }}</div>
|
||||
</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>
|
||||
<ExclamationCircleOutlined />
|
||||
</a-popover>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a @click="onRadio(record)">选择</a>
|
||||
</template>
|
||||
</template>
|
||||
</ele-pro-table>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
ColumnItem,
|
||||
DatasourceFunction
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { EleProTable } from 'ele-admin-pro';
|
||||
import { Company, CompanyParam } from '@/api/oa/company/model';
|
||||
import { pageWebsiteField } from '@/api/system/website/field';
|
||||
import { WebsiteField } from '@/api/system/website/field/model';
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 标题
|
||||
title?: string;
|
||||
// 修改回显的数据
|
||||
data?: WebsiteField | null;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done', data: Company): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
// 搜索内容
|
||||
const searchText = ref(null);
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
// 表格配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: '参数名',
|
||||
dataIndex: 'name',
|
||||
width: 180,
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'comments',
|
||||
key: 'comments',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '默认值',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
dataIndex: 'defaultValue'
|
||||
},
|
||||
{
|
||||
title: '可设置范围',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
dataIndex: 'modifyRange'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
where = {};
|
||||
// 搜索条件
|
||||
if (searchText.value) {
|
||||
where.keywords = searchText.value;
|
||||
}
|
||||
return pageWebsiteField({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const reload = (where?: CompanyParam) => {
|
||||
tableRef?.value?.reload({ page: 1, where });
|
||||
};
|
||||
|
||||
const onRadio = (record: Company) => {
|
||||
updateVisible(false);
|
||||
emit('done', record);
|
||||
};
|
||||
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: Company) => {
|
||||
return {
|
||||
// 行点击事件
|
||||
// onClick: () => {
|
||||
// updateVisible(false);
|
||||
// emit('done', record);
|
||||
// },
|
||||
// 行双击事件
|
||||
onDblclick: () => {
|
||||
updateVisible(false);
|
||||
emit('done', record);
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
61
src/components/SelectWebsiteField/index.vue
Normal file
61
src/components/SelectWebsiteField/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-input-group compact>
|
||||
<a-input
|
||||
disabled
|
||||
style="width: calc(100% - 32px)"
|
||||
v-model:value="value"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
<a-button @click="openEdit">
|
||||
<template #icon><BulbOutlined class="ele-text-warning" /></template>
|
||||
</a-button>
|
||||
</a-input-group>
|
||||
<!-- 选择弹窗 -->
|
||||
<SelectData
|
||||
v-model:visible="showEdit"
|
||||
:data="current"
|
||||
:title="placeholder"
|
||||
:customer-type="customerType"
|
||||
@done="onChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { BulbOutlined } from '@ant-design/icons-vue';
|
||||
import { ref } from 'vue';
|
||||
import SelectData from './components/select-data.vue';
|
||||
import { Company } from '@/api/system/company/model';
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
value?: any;
|
||||
customerType?: string;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请选择数据'
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done', Customer): void;
|
||||
(e: 'clear'): void;
|
||||
}>();
|
||||
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 当前编辑数据
|
||||
const current = ref<Company | null>(null);
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: Company) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
const onChange = (row) => {
|
||||
emit('done', row);
|
||||
};
|
||||
</script>
|
||||
@@ -30,16 +30,16 @@ export const routes = [
|
||||
// component: () => import('@/views/passport/token-login/index.vue'),
|
||||
// meta: { title: '快捷登录' }
|
||||
// },
|
||||
{
|
||||
path: '/cms/category/:id',
|
||||
component: () => import('@/views/cms/category/preview/index.vue'),
|
||||
meta: { title: '文章列表' }
|
||||
},
|
||||
{
|
||||
path: '/cms/article/:id',
|
||||
component: () => import('@/views/cms/article/preview/index.vue'),
|
||||
meta: { title: '文章详情' }
|
||||
},
|
||||
// {
|
||||
// path: '/cms/category/:id',
|
||||
// component: () => import('@/views/cms/category/preview/index.vue'),
|
||||
// meta: { title: '文章列表' }
|
||||
// },
|
||||
// {
|
||||
// path: '/cms/article/:id',
|
||||
// component: () => import('@/views/cms/article/preview/index.vue'),
|
||||
// meta: { title: '文章详情' }
|
||||
// },
|
||||
// 404
|
||||
{
|
||||
path: '/:path(.*)*',
|
||||
|
||||
@@ -21,13 +21,17 @@
|
||||
>
|
||||
<a-tabs type="card" v-model:active-key="active" @change="onChange">
|
||||
<a-tab-pane tab="基本信息" key="base">
|
||||
<a-form-item label="选择栏目" name="categoryId">
|
||||
<SelectNavigsation
|
||||
:data="data"
|
||||
placeholder="请选择栏目"
|
||||
<a-form-item label="文章标题" name="categoryId">
|
||||
<a-tree-select
|
||||
allow-clear
|
||||
:tree-data="navigationList"
|
||||
tree-default-expand-all
|
||||
style="width: 558px"
|
||||
v-model:value="form.categoryName"
|
||||
@done="chooseCategory"
|
||||
placeholder="请选择栏目"
|
||||
:value="form.categoryId || undefined"
|
||||
:dropdown-style="{ maxHeight: '360px', overflow: 'auto' }"
|
||||
@update:value="(value?: number) => (form.categoryId = value)"
|
||||
@change="onCategoryId"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文章标题" name="title">
|
||||
@@ -177,6 +181,8 @@
|
||||
data?: Article | null;
|
||||
// 商户ID
|
||||
merchantId?: number;
|
||||
// 栏目数据
|
||||
navigationList?: Navigation[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -340,14 +346,13 @@
|
||||
form.image = data.path;
|
||||
};
|
||||
|
||||
const chooseCategory = (data: Navigation) => {
|
||||
form.categoryName = data.title
|
||||
form.categoryId = data.navigationId
|
||||
}
|
||||
// 选择栏目
|
||||
const onCategoryId = (id: number) => {
|
||||
form.categoryId = id;
|
||||
};
|
||||
|
||||
const onChange = (text: string) => {
|
||||
const onChange = () => {
|
||||
// 加载文章多规格
|
||||
|
||||
};
|
||||
|
||||
const onDeleteItem = (index: number) => {
|
||||
@@ -9,27 +9,25 @@
|
||||
</a-button>
|
||||
<a-radio-group v-model:value="type" @change="handleSearch">
|
||||
<a-radio-button value="已发布"
|
||||
>已发布({{ goodsCount?.totalNum }})</a-radio-button
|
||||
>已发布({{ articleCount?.totalNum }})</a-radio-button
|
||||
>
|
||||
<a-radio-button value="待审核"
|
||||
>待审核({{ goodsCount?.totalNum2 }})</a-radio-button
|
||||
>待审核({{ articleCount?.totalNum2 }})</a-radio-button
|
||||
>
|
||||
<a-radio-button value="已驳回"
|
||||
>已驳回({{ goodsCount?.totalNum3 }})</a-radio-button
|
||||
>已驳回({{ articleCount?.totalNum3 }})</a-radio-button
|
||||
>
|
||||
</a-radio-group>
|
||||
<!-- <SelectMerchant-->
|
||||
<!-- :placeholder="`选择商户`"-->
|
||||
<!-- class="input-item"-->
|
||||
<!-- v-if="!merchantId"-->
|
||||
<!-- v-model:value="where.merchantName"-->
|
||||
<!-- @done="chooseMerchantId"-->
|
||||
<!-- />-->
|
||||
<SelectNavigsation
|
||||
class="input-item"
|
||||
:placeholder="`选择栏目`"
|
||||
v-model:value="where.categoryName"
|
||||
@done="chooseArticleCategory"
|
||||
<a-tree-select
|
||||
allow-clear
|
||||
:tree-data="navigationList"
|
||||
tree-default-expand-all
|
||||
style="width: 230px"
|
||||
placeholder="请选择栏目"
|
||||
:value="where.categoryId || undefined"
|
||||
:dropdown-style="{ maxHeight: '360px', overflow: 'auto' }"
|
||||
@update:value="(value?: number) => (where.categoryId = value)"
|
||||
@change="onCategoryId"
|
||||
/>
|
||||
<a-input-search
|
||||
allow-clear
|
||||
@@ -45,10 +43,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { getCount } from '@/api/shop/goods';
|
||||
import { getCount } from '@/api/cms/article';
|
||||
import type { ArticleCount, ArticleParam } from '@/api/cms/article/model';
|
||||
import useSearch from '@/utils/use-search';
|
||||
import { Merchant } from '@/api/shop/merchant/model';
|
||||
import { Navigation } from '@/api/cms/navigation/model';
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -56,13 +53,15 @@
|
||||
// 选中的角色
|
||||
selection?: [];
|
||||
merchantId?: number;
|
||||
navigationList?: Navigation[];
|
||||
model?: string;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
const type = ref<string>();
|
||||
// 统计数据
|
||||
const goodsCount = ref<ArticleCount>();
|
||||
const articleCount = ref<ArticleCount>();
|
||||
|
||||
// 表单数据
|
||||
const { where, resetFields } = useSearch<ArticleParam>({
|
||||
@@ -70,6 +69,7 @@
|
||||
navigationId: undefined,
|
||||
categoryId: undefined,
|
||||
merchantId: undefined,
|
||||
status: undefined,
|
||||
keywords: ''
|
||||
});
|
||||
|
||||
@@ -89,10 +89,10 @@
|
||||
const text = e.target.value;
|
||||
resetFields();
|
||||
if (text === '已发布') {
|
||||
where.status = 1;
|
||||
where.status = 0;
|
||||
}
|
||||
if (text === '待审核') {
|
||||
where.status = 0;
|
||||
where.status = 1;
|
||||
}
|
||||
if (text === '已驳回') {
|
||||
where.status = 2;
|
||||
@@ -102,22 +102,15 @@
|
||||
|
||||
const reload = () => {
|
||||
getCount(where).then((data: any) => {
|
||||
goodsCount.value = data;
|
||||
articleCount.value = data;
|
||||
});
|
||||
emit('search', where);
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const chooseMerchantId = (item: Merchant) => {
|
||||
where.merchantName = item.merchantName;
|
||||
where.merchantId = item.merchantId;
|
||||
reload();
|
||||
};
|
||||
|
||||
const chooseArticleCategory = (category: Navigation) => {
|
||||
where.categoryName = category.title;
|
||||
where.navigationId = category.navigationId;
|
||||
reload();
|
||||
// 按分类查询
|
||||
const onCategoryId = (id: number) => {
|
||||
where.categoryId = id;
|
||||
emit('search', where);
|
||||
};
|
||||
|
||||
/* 重置 */
|
||||
@@ -127,10 +120,6 @@
|
||||
reload();
|
||||
};
|
||||
|
||||
// watch(
|
||||
// () => props.selection,
|
||||
// () => {}
|
||||
// );
|
||||
watch(
|
||||
() => props.merchantId,
|
||||
(id) => {
|
||||
@@ -1,220 +1,292 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="ele-body">
|
||||
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||
<ele-split-layout
|
||||
width="266px"
|
||||
allow-collapse
|
||||
:right-style="{ overflow: 'hidden' }"
|
||||
:style="{ minHeight: 'calc(100vh - 152px)' }"
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="articleId"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:customRow="customRow"
|
||||
:scroll="{ x: 1200 }"
|
||||
tool-class="ele-toolbar-form"
|
||||
class="sys-org-table"
|
||||
>
|
||||
<div>
|
||||
<ele-toolbar theme="default">
|
||||
<a-space :size="10">
|
||||
<a-button
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit()"
|
||||
>
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
<template #toolbar>
|
||||
<search
|
||||
@search="reload"
|
||||
:selection="selection"
|
||||
:navigationList="navigationList"
|
||||
:merchantId="merchantId"
|
||||
:model="model"
|
||||
@add="openEdit"
|
||||
@remove="removeBatch"
|
||||
@batchMove="openMove"
|
||||
/>
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit(current)"
|
||||
>
|
||||
<template #icon>
|
||||
<edit-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
danger
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="remove"
|
||||
>
|
||||
<template #icon>
|
||||
<delete-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
</ele-toolbar>
|
||||
<div class="ele-border-split sys-category-list">
|
||||
<a-tree
|
||||
:tree-data="data"
|
||||
v-model:expanded-keys="expandedRowKeys"
|
||||
v-model:selected-keys="selectedRowKeys"
|
||||
@select="onTreeSelect"
|
||||
>
|
||||
<template #title="{ type, key: treeKey, title }">
|
||||
<a-dropdown :trigger="['contextmenu']">
|
||||
<span>{{ title }}</span>
|
||||
<template #overlay v-if="type == 0">
|
||||
<a-menu
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a
|
||||
@click="
|
||||
({ key: menuKey }) =>
|
||||
onContextMenuClick(treeKey, menuKey)
|
||||
openSpmUrl(
|
||||
`/article/detail/${record.articleId}.html`,
|
||||
record,
|
||||
record.articleId
|
||||
)
|
||||
"
|
||||
>{{ record.title }}</a
|
||||
>
|
||||
<a-menu-item key="1">修改</a-menu-item>
|
||||
<a-menu-item key="2">删除</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<template v-if="column.key === 'type'">
|
||||
<a-tag v-if="record.type === 0">虚拟文章</a-tag>
|
||||
<a-tag v-if="record.type === 1">实物文章</a-tag>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
</div>
|
||||
<template #content>
|
||||
<list
|
||||
v-if="current"
|
||||
:category-list="data"
|
||||
:data="current"
|
||||
:category-id="current.categoryId"
|
||||
/>
|
||||
<template v-if="column.key === 'image'">
|
||||
<a-image :src="record.image" :width="80" />
|
||||
</template>
|
||||
</ele-split-layout>
|
||||
<template v-if="column.key === 'salePrice'">
|
||||
¥{{ formatNumber(record.salePrice) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag
|
||||
:color="record.status == 0 ? 'green' : 'red'"
|
||||
class="cursor-pointer"
|
||||
@click="onUpdate(record)"
|
||||
>{{ record.statusText }}</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>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<category-edit
|
||||
<ArticleEdit
|
||||
v-model:visible="showEdit"
|
||||
:data="editData"
|
||||
:category-list="data"
|
||||
:category-id="current?.categoryId"
|
||||
@done="query"
|
||||
:navigationList="navigationList"
|
||||
:data="current"
|
||||
@done="reload"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { createVNode, ref, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import type { EleProTable } from 'ele-admin-pro';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import Search from './components/search.vue';
|
||||
import ArticleEdit from './components/articleEdit.vue';
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
ExclamationCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import { toTreeData, eachTreeData } from 'ele-admin-pro';
|
||||
import List from './list.vue';
|
||||
import CategoryEdit from './components/category-edit.vue';
|
||||
import {
|
||||
listArticleCategory,
|
||||
removeArticleCategory
|
||||
} from '@/api/cms/category';
|
||||
import { ArticleCategory } from '@/api/cms/category/model';
|
||||
pageArticle,
|
||||
removeArticle,
|
||||
removeBatchArticle
|
||||
} from '@/api/cms/article';
|
||||
import type { Article, ArticleParam } from '@/api/cms/article/model';
|
||||
import { formatNumber } from 'ele-admin-pro/es';
|
||||
import router from '@/router';
|
||||
import { toTreeData } from 'ele-admin-pro';
|
||||
import { openSpmUrl } from '@/utils/common';
|
||||
import { getSiteDomain } from '@/utils/domain';
|
||||
import { listNavigation } from '@/api/cms/navigation';
|
||||
import { Navigation } from '@/api/cms/navigation/model';
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
// 树形数据
|
||||
const data = ref<ArticleCategory[]>([]);
|
||||
|
||||
// 树展开的key
|
||||
const expandedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 树选中的key
|
||||
const selectedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 选中数据
|
||||
const current = ref<ArticleCategory | any>(null);
|
||||
|
||||
// 是否显示表单弹窗
|
||||
// 表格选中数据
|
||||
const selection = ref<Article[]>([]);
|
||||
// 当前编辑数据
|
||||
const current = ref<Article | null>(null);
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// 店铺ID
|
||||
const merchantId = ref<number>();
|
||||
// 栏目ID
|
||||
const categoryId = ref<number>();
|
||||
// 当前模型
|
||||
const model = ref<number>();
|
||||
// 网站域名
|
||||
const domain = getSiteDomain();
|
||||
// 随机数
|
||||
const token = ref<any>('');
|
||||
// 栏目数据
|
||||
const navigationList = ref<Navigation[]>();
|
||||
|
||||
// 编辑回显数据
|
||||
const editData = ref<ArticleCategory | null>(null);
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
if (categoryId.value) {
|
||||
where.categoryId = categoryId.value;
|
||||
}
|
||||
return pageArticle({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
listArticleCategory()
|
||||
.then((list) => {
|
||||
loading.value = false;
|
||||
const eks: number[] = [];
|
||||
list.forEach((d) => {
|
||||
d.key = d.categoryId;
|
||||
d.value = d.categoryId;
|
||||
if (typeof d.categoryId === 'number') {
|
||||
eks.push(d.categoryId);
|
||||
}
|
||||
});
|
||||
expandedRowKeys.value = eks;
|
||||
data.value = toTreeData({
|
||||
data: list.map((d) => {
|
||||
d.disabled = d.type != 0;
|
||||
return d;
|
||||
}),
|
||||
idField: 'categoryId',
|
||||
parentIdField: 'parentId'
|
||||
});
|
||||
if (list.length) {
|
||||
if (typeof list[0].categoryId === 'number') {
|
||||
selectedRowKeys.value = [list[0].categoryId];
|
||||
}
|
||||
current.value = list[0];
|
||||
} else {
|
||||
selectedRowKeys.value = [];
|
||||
current.value = null;
|
||||
// 表格列配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'articleId',
|
||||
key: 'articleId',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '文章标题',
|
||||
dataIndex: 'title',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: '封面图',
|
||||
dataIndex: 'image',
|
||||
key: 'image',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '所属栏目',
|
||||
dataIndex: 'categoryId',
|
||||
key: 'categoryId',
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '实际阅读量',
|
||||
dataIndex: 'actualViews',
|
||||
key: 'actualViews',
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '虚拟阅读量',
|
||||
dataIndex: 'virtualViews',
|
||||
key: 'virtualViews',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '推荐',
|
||||
dataIndex: 'recommend',
|
||||
key: 'recommend',
|
||||
sorter: true,
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '排序号',
|
||||
dataIndex: 'sortNumber',
|
||||
key: 'sortNumber',
|
||||
sorter: true,
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
align: 'center',
|
||||
width: 180,
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
/* 搜索 */
|
||||
const reload = (where?: ArticleParam) => {
|
||||
selection.value = [];
|
||||
tableRef?.value?.reload({ where: where });
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: Article) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 打开批量移动弹窗 */
|
||||
const openMove = () => {
|
||||
showMove.value = true;
|
||||
};
|
||||
|
||||
const onUpdate = (row?: Article) => {
|
||||
// const isShow = row?.isShow == 0 ? 1 : 0;
|
||||
// updateArticle({ ...row, isShow }).then((msg) => {
|
||||
// message.success(msg);
|
||||
// reload();
|
||||
// });
|
||||
};
|
||||
|
||||
/* 删除单个 */
|
||||
const remove = (row: Article) => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeArticle(row.articleId)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
/* 选择数据 */
|
||||
const onTreeSelect = () => {
|
||||
current.value = {};
|
||||
eachTreeData(data.value, (d) => {
|
||||
if (
|
||||
typeof d.categoryId === 'number' &&
|
||||
selectedRowKeys.value.includes(d.categoryId)
|
||||
) {
|
||||
current.value = d;
|
||||
return false;
|
||||
/* 批量删除 */
|
||||
const removeBatch = () => {
|
||||
if (!selection.value.length) {
|
||||
message.error('请至少选择一条数据');
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onContextMenuClick = (treeKey: number, menuKey: number) => {
|
||||
// 修改
|
||||
if (menuKey == 1) {
|
||||
openEdit(current.value);
|
||||
}
|
||||
// 删除
|
||||
if (menuKey == 2) {
|
||||
remove();
|
||||
}
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (item?: ArticleCategory | null) => {
|
||||
editData.value = item ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 删除 */
|
||||
const remove = () => {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的分类吗?',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
maskClosable: true,
|
||||
onOk: () => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeArticleCategory(current.value?.categoryId)
|
||||
removeBatchArticle(selection.value.map((d) => d.articleId))
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
query();
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
@@ -224,21 +296,55 @@
|
||||
});
|
||||
};
|
||||
|
||||
query();
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: Article) => {
|
||||
return {
|
||||
// 行点击事件
|
||||
onClick: () => {
|
||||
// console.log(record);
|
||||
},
|
||||
// 行双击事件
|
||||
onDblclick: () => {
|
||||
openEdit(record);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 加载栏目数据
|
||||
if (!navigationList.value) {
|
||||
listNavigation({}).then((res) => {
|
||||
navigationList.value = toTreeData({
|
||||
data: res?.map((d) => {
|
||||
d.value = d.navigationId;
|
||||
d.label = d.title;
|
||||
if (d.type != 2) {
|
||||
d.disabled = true;
|
||||
}
|
||||
return d;
|
||||
}),
|
||||
idField: 'navigationId',
|
||||
parentIdField: 'parentId'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.query,
|
||||
(query) => {
|
||||
if (query) {
|
||||
categoryId.value = Number(query.categoryId);
|
||||
model.value = Number(query.type);
|
||||
reload();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ArticleIndex'
|
||||
name: 'ArticleV2'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sys-category-list {
|
||||
padding: 12px 6px;
|
||||
height: calc(100vh - 242px);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
244
src/views/cms/articleV0/index.vue
Normal file
244
src/views/cms/articleV0/index.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<div class="ele-body">
|
||||
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||
<ele-split-layout
|
||||
width="266px"
|
||||
allow-collapse
|
||||
:right-style="{ overflow: 'hidden' }"
|
||||
:style="{ minHeight: 'calc(100vh - 152px)' }"
|
||||
>
|
||||
<div>
|
||||
<ele-toolbar theme="default">
|
||||
<a-space :size="10">
|
||||
<a-button
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit()"
|
||||
>
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="openEdit(current)"
|
||||
>
|
||||
<template #icon>
|
||||
<edit-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
danger
|
||||
type="primary"
|
||||
:size="`small`"
|
||||
:disabled="!current"
|
||||
class="ele-btn-icon"
|
||||
@click="remove"
|
||||
>
|
||||
<template #icon>
|
||||
<delete-outlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
</ele-toolbar>
|
||||
<div class="ele-border-split sys-category-list">
|
||||
<a-tree
|
||||
:tree-data="data"
|
||||
v-model:expanded-keys="expandedRowKeys"
|
||||
v-model:selected-keys="selectedRowKeys"
|
||||
@select="onTreeSelect"
|
||||
>
|
||||
<template #title="{ type, key: treeKey, title }">
|
||||
<a-dropdown :trigger="['contextmenu']">
|
||||
<span>{{ title }}</span>
|
||||
<template #overlay v-if="type == 0">
|
||||
<a-menu
|
||||
@click="
|
||||
({ key: menuKey }) =>
|
||||
onContextMenuClick(treeKey, menuKey)
|
||||
"
|
||||
>
|
||||
<a-menu-item key="1">修改</a-menu-item>
|
||||
<a-menu-item key="2">删除</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
</div>
|
||||
<template #content>
|
||||
<list
|
||||
v-if="current"
|
||||
:category-list="data"
|
||||
:data="current"
|
||||
:category-id="current.categoryId"
|
||||
/>
|
||||
</template>
|
||||
</ele-split-layout>
|
||||
</a-card>
|
||||
<!-- 编辑弹窗 -->
|
||||
<category-edit
|
||||
v-model:visible="showEdit"
|
||||
:data="editData"
|
||||
:category-list="data"
|
||||
:category-id="current?.categoryId"
|
||||
@done="query"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
ExclamationCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import { toTreeData, eachTreeData } from 'ele-admin-pro';
|
||||
import List from './list.vue';
|
||||
import CategoryEdit from './components/category-edit.vue';
|
||||
import {
|
||||
listArticleCategory,
|
||||
removeArticleCategory
|
||||
} from '@/api/cms/category';
|
||||
import { ArticleCategory } from '@/api/cms/category/model';
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
|
||||
// 树形数据
|
||||
const data = ref<ArticleCategory[]>([]);
|
||||
|
||||
// 树展开的key
|
||||
const expandedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 树选中的key
|
||||
const selectedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 选中数据
|
||||
const current = ref<ArticleCategory | any>(null);
|
||||
|
||||
// 是否显示表单弹窗
|
||||
const showEdit = ref(false);
|
||||
|
||||
// 编辑回显数据
|
||||
const editData = ref<ArticleCategory | null>(null);
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
listArticleCategory()
|
||||
.then((list) => {
|
||||
loading.value = false;
|
||||
const eks: number[] = [];
|
||||
list.forEach((d) => {
|
||||
d.key = d.categoryId;
|
||||
d.value = d.categoryId;
|
||||
if (typeof d.categoryId === 'number') {
|
||||
eks.push(d.categoryId);
|
||||
}
|
||||
});
|
||||
expandedRowKeys.value = eks;
|
||||
data.value = toTreeData({
|
||||
data: list.map((d) => {
|
||||
d.disabled = d.type != 0;
|
||||
return d;
|
||||
}),
|
||||
idField: 'categoryId',
|
||||
parentIdField: 'parentId'
|
||||
});
|
||||
if (list.length) {
|
||||
if (typeof list[0].categoryId === 'number') {
|
||||
selectedRowKeys.value = [list[0].categoryId];
|
||||
}
|
||||
current.value = list[0];
|
||||
} else {
|
||||
selectedRowKeys.value = [];
|
||||
current.value = null;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
/* 选择数据 */
|
||||
const onTreeSelect = () => {
|
||||
current.value = {};
|
||||
eachTreeData(data.value, (d) => {
|
||||
if (
|
||||
typeof d.categoryId === 'number' &&
|
||||
selectedRowKeys.value.includes(d.categoryId)
|
||||
) {
|
||||
current.value = d;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onContextMenuClick = (treeKey: number, menuKey: number) => {
|
||||
// 修改
|
||||
if (menuKey == 1) {
|
||||
openEdit(current.value);
|
||||
}
|
||||
// 删除
|
||||
if (menuKey == 2) {
|
||||
remove();
|
||||
}
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (item?: ArticleCategory | null) => {
|
||||
editData.value = item ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 删除 */
|
||||
const remove = () => {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的分类吗?',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
maskClosable: true,
|
||||
onOk: () => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeArticleCategory(current.value?.categoryId)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
query();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
query();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ArticleIndex'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sys-category-list {
|
||||
padding: 12px 6px;
|
||||
height: calc(100vh - 242px);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -34,7 +34,7 @@
|
||||
* 加载数据
|
||||
*/
|
||||
const reload = (id: number) => {
|
||||
console.log(id);
|
||||
console.log(id,'0000');
|
||||
// 加载项目详情
|
||||
getArticle(id).then((data) => {
|
||||
assignFields(data);
|
||||
@@ -1,324 +0,0 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="ele-body">
|
||||
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="articleId"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:customRow="customRow"
|
||||
:scroll="{ x: 1200 }"
|
||||
tool-class="ele-toolbar-form"
|
||||
class="sys-org-table"
|
||||
>
|
||||
<template #toolbar>
|
||||
<search
|
||||
@search="reload"
|
||||
:selection="selection"
|
||||
:merchantId="merchantId"
|
||||
@add="openEdit"
|
||||
@remove="removeBatch"
|
||||
@batchMove="openMove"
|
||||
/>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a
|
||||
@click="
|
||||
openSpmUrl(
|
||||
`/article/detail/${record.articleId}.html`,
|
||||
record,
|
||||
record.articleId
|
||||
)
|
||||
"
|
||||
>{{ record.title }}</a
|
||||
>
|
||||
</template>
|
||||
<template v-if="column.key === 'type'">
|
||||
<a-tag v-if="record.type === 0">虚拟文章</a-tag>
|
||||
<a-tag v-if="record.type === 1">实物文章</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'image'">
|
||||
<a-image :src="record.image" :width="80" />
|
||||
</template>
|
||||
<template v-if="column.key === 'salePrice'">
|
||||
¥{{ formatNumber(record.salePrice) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag
|
||||
:color="record.status == 0 ? 'green' : 'red'"
|
||||
class="cursor-pointer"
|
||||
@click="onUpdate(record)"
|
||||
>{{ record.statusText }}</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>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<ArticleEdit v-model:visible="showEdit" :data="current" @done="reload" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import type { EleProTable } from 'ele-admin-pro';
|
||||
import { uuid } from 'ele-admin-pro';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import Search from './components/search.vue';
|
||||
import ArticleEdit from './components/articleEdit.vue';
|
||||
import {
|
||||
pageArticle,
|
||||
removeArticle,
|
||||
removeBatchArticle
|
||||
} from '@/api/cms/article';
|
||||
import type { Article, ArticleParam } from '@/api/cms/article/model';
|
||||
import { formatNumber } from 'ele-admin-pro/es';
|
||||
import router from '@/router';
|
||||
import { openSpmUrl, openUrl, openUrlSpm } from '@/utils/common';
|
||||
import { getSiteDomain } from '@/utils/domain';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
// 表格选中数据
|
||||
const selection = ref<Article[]>([]);
|
||||
// 当前编辑数据
|
||||
const current = ref<Article | null>(null);
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// 店铺ID
|
||||
const merchantId = ref<number>();
|
||||
// 网站域名
|
||||
const domain = getSiteDomain();
|
||||
// 随机数
|
||||
const token = ref<any>('');
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({
|
||||
page,
|
||||
limit,
|
||||
where,
|
||||
orders,
|
||||
filters
|
||||
}) => {
|
||||
if (filters) {
|
||||
where.status = filters.status;
|
||||
}
|
||||
if (merchantId.value) {
|
||||
where.merchantId = merchantId.value;
|
||||
}
|
||||
return pageArticle({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'articleId',
|
||||
key: 'articleId',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '文章标题',
|
||||
dataIndex: 'title',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: '封面图',
|
||||
dataIndex: 'image',
|
||||
key: 'image',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '所属栏目',
|
||||
dataIndex: 'categoryId',
|
||||
key: 'categoryId',
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '实际阅读量',
|
||||
dataIndex: 'actualViews',
|
||||
key: 'actualViews',
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '虚拟阅读量',
|
||||
dataIndex: 'virtualViews',
|
||||
key: 'virtualViews',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '推荐',
|
||||
dataIndex: 'recommend',
|
||||
key: 'recommend',
|
||||
sorter: true,
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '排序号',
|
||||
dataIndex: 'sortNumber',
|
||||
key: 'sortNumber',
|
||||
sorter: true,
|
||||
align: 'center',
|
||||
hideInTable: true
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
align: 'center',
|
||||
width: 180,
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
/* 搜索 */
|
||||
const reload = (where?: ArticleParam) => {
|
||||
selection.value = [];
|
||||
tableRef?.value?.reload({ where: where });
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: Article) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 打开批量移动弹窗 */
|
||||
const openMove = () => {
|
||||
showMove.value = true;
|
||||
};
|
||||
|
||||
const onUpdate = (row?: Article) => {
|
||||
// const isShow = row?.isShow == 0 ? 1 : 0;
|
||||
// updateArticle({ ...row, isShow }).then((msg) => {
|
||||
// message.success(msg);
|
||||
// reload();
|
||||
// });
|
||||
};
|
||||
|
||||
/* 删除单个 */
|
||||
const remove = (row: Article) => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeArticle(row.articleId)
|
||||
.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);
|
||||
removeBatchArticle(selection.value.map((d) => d.articleId))
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: Article) => {
|
||||
return {
|
||||
// 行点击事件
|
||||
onClick: () => {
|
||||
// console.log(record);
|
||||
},
|
||||
// 行双击事件
|
||||
onDblclick: () => {
|
||||
openEdit(record);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.params.id,
|
||||
(id) => {
|
||||
merchantId.value = Number(id);
|
||||
token.value = uuid();
|
||||
reload();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ArticleV2'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -4,7 +4,7 @@
|
||||
:width="500"
|
||||
:visible="visible"
|
||||
:maskClosable="false"
|
||||
:title="isUpdate ? '编辑字段' : '添加字段'"
|
||||
:title="isUpdate ? '编辑参数' : '添加参数'"
|
||||
:body-style="{ paddingBottom: '28px' }"
|
||||
@update:visible="updateVisible"
|
||||
@ok="save"
|
||||
@@ -13,23 +13,34 @@
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="{ md: { span: 4 }, sm: { span: 4 }, xs: { span: 24 } }"
|
||||
:label-col="{ md: { span: 5 }, sm: { span: 4 }, xs: { span: 24 } }"
|
||||
:wrapper-col="{ md: { span: 21 }, sm: { span: 22 }, xs: { span: 24 } }"
|
||||
>
|
||||
<a-form-item label="键" name="name">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="site_name"
|
||||
<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-form-item label="配置值" name="value">
|
||||
<a-input allow-clear placeholder="淘宝网" v-model:value="form.value" />
|
||||
</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="comments">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="网站名称"
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
:maxlength="200"
|
||||
placeholder="描述"
|
||||
v-model:value="form.comments"
|
||||
/>
|
||||
</a-form-item>
|
||||
@@ -41,15 +52,6 @@
|
||||
v-model:value="form.sortNumber"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="(选填)">
|
||||
<SelectFile
|
||||
:placeholder="`请选择图片`"
|
||||
:limit="1"
|
||||
:data="images"
|
||||
@done="chooseImage"
|
||||
@del="onDeleteItem"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ele-modal>
|
||||
</template>
|
||||
@@ -92,6 +94,8 @@
|
||||
type: 0,
|
||||
name: undefined,
|
||||
value: undefined,
|
||||
modifyRange: undefined,
|
||||
defaultValue: undefined,
|
||||
comments: '',
|
||||
status: 0,
|
||||
sortNumber: 100
|
||||
@@ -142,6 +146,11 @@
|
||||
form.type = 0;
|
||||
};
|
||||
|
||||
const chooseData = (data: WebsiteField) => {
|
||||
assignFields(data);
|
||||
form.value = data.defaultValue;
|
||||
};
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
if (!formRef.value) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:customRow="customRow"
|
||||
:need-page="false"
|
||||
tool-class="ele-toolbar-form"
|
||||
class="sys-org-table"
|
||||
>
|
||||
@@ -17,8 +18,12 @@
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'name'">
|
||||
<div class="ele-text-heading">{{ record.name }}</div>
|
||||
<span class="ele-text-placeholder">{{ record.comments }}</span>
|
||||
<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
|
||||
@@ -26,7 +31,15 @@
|
||||
:src="record.value"
|
||||
:width="120"
|
||||
/>
|
||||
<span v-else>{{ record.value }}</span>
|
||||
<div v-else>{{ record.value }}</div>
|
||||
</template>
|
||||
<template v-if="column.key === 'comments'">
|
||||
<a-popover>
|
||||
<template #content>
|
||||
{{ record.comments }}
|
||||
</template>
|
||||
<ExclamationCircleOutlined />
|
||||
</a-popover>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a @click="copyText('{{ config.' + record.name + ' }}')">调用</a>
|
||||
@@ -66,6 +79,7 @@
|
||||
|
||||
<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';
|
||||
@@ -77,6 +91,7 @@
|
||||
WebsiteFieldParam
|
||||
} from '@/api/cms/website/field/model';
|
||||
import {
|
||||
listWebsiteField,
|
||||
pageWebsiteField,
|
||||
removeWebsiteField,
|
||||
undeleteWebsiteField,
|
||||
@@ -100,7 +115,7 @@
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
// 搜索条件
|
||||
return pageWebsiteField({
|
||||
return listWebsiteField({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
@@ -111,14 +126,32 @@
|
||||
// 表格列配置
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
title: '键',
|
||||
title: '参数名',
|
||||
dataIndex: 'name',
|
||||
width: 180,
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '值',
|
||||
title: '描述',
|
||||
dataIndex: 'comments',
|
||||
key: 'comments',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '配置值',
|
||||
dataIndex: 'value',
|
||||
key: 'value'
|
||||
key: 'value',
|
||||
width: 400,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '默认值',
|
||||
dataIndex: 'defaultValue'
|
||||
},
|
||||
{
|
||||
title: '可设置范围',
|
||||
dataIndex: 'modifyRange'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- 编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="740"
|
||||
:width="800"
|
||||
:visible="visible"
|
||||
:confirm-loading="loading"
|
||||
:title="isUpdate ? '修改导航' : '新建导航'"
|
||||
@@ -41,123 +41,70 @@
|
||||
@pressEnter="save"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择页面" v-if="form.type == 1">
|
||||
<SelectDesign
|
||||
:placeholder="`请选择页面`"
|
||||
v-model:value="form.pageName"
|
||||
@done="choosePageId"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择列表" v-if="form.type == 2">
|
||||
<SelectArticleCategory
|
||||
:placeholder="`请选择列表`"
|
||||
v-model:value="form.pageName"
|
||||
@done="chooseArticleCategoryId"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择文章" v-if="form.type == 3">
|
||||
<SelectArticle
|
||||
:placeholder="`请选择文章`"
|
||||
v-model:value="form.pageName"
|
||||
@done="chooseArticle"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择表单" v-if="form.type == 4">
|
||||
<SelectForm
|
||||
:placeholder="`请选择表单`"
|
||||
v-model:value="form.pageName"
|
||||
@done="chooseForm"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择文档" v-if="form.type == 5">
|
||||
<SelectDocsBook
|
||||
:placeholder="`请选择知识文档`"
|
||||
v-model:value="form.title"
|
||||
@done="chooseDocsBook"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择分类" v-if="form.type == 6">
|
||||
<SelectGoodsCategory
|
||||
:placeholder="`请选择商品分类`"
|
||||
v-model:value="form.title"
|
||||
@done="chooseGoodsCategory"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择商品详情" v-if="form.type == 7">
|
||||
<SelectDocsBook
|
||||
:placeholder="`请选择商品详情`"
|
||||
v-model:value="form.title"
|
||||
@done="chooseGoods"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:label="form.type == 9 ? '链接地址' : '路由地址'"
|
||||
name="path"
|
||||
>
|
||||
<a-input
|
||||
allow-clear
|
||||
:placeholder="form.type == 9 ? '请输入链接地址' : '/about.html'"
|
||||
:placeholder="
|
||||
form.type == 9 ? '请输入链接地址' : '/iphone-15-pro'
|
||||
"
|
||||
v-model:value="form.path"
|
||||
@pressEnter="save"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="组件路径" name="component" v-if="form.type == 0">
|
||||
<a-form-item label="组件路径" name="component">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="/custom/index"
|
||||
placeholder="/pages/[custom].vue"
|
||||
v-model:value="form.component"
|
||||
@pressEnter="save"
|
||||
/>
|
||||
</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-col>
|
||||
<a-col
|
||||
v-bind="styleResponsive ? { md: 12, sm: 24, xs: 24 } : { span: 12 }"
|
||||
>
|
||||
<!-- <a-form-item label="模型" name="type">-->
|
||||
<!-- <a-select-->
|
||||
<!-- ref="select"-->
|
||||
<!-- v-model:value="form.type"-->
|
||||
<!-- style="width: 253px"-->
|
||||
<!-- @change="onType"-->
|
||||
<!-- >-->
|
||||
<!-- <a-select-option :value="0">通用模型</a-select-option>-->
|
||||
<!-- <a-select-option :value="1">单页内容</a-select-option>-->
|
||||
<!-- <a-select-option :value="2">新闻分类</a-select-option>-->
|
||||
<!-- <a-select-option :value="3">新闻详情</a-select-option>-->
|
||||
<!-- <a-select-option :value="4">表单设计</a-select-option>-->
|
||||
<!-- <a-select-option :value="5">知识文档</a-select-option>-->
|
||||
<!-- <a-select-option :value="6">商品分类</a-select-option>-->
|
||||
<!-- <a-select-option :value="7">商品详情</a-select-option>-->
|
||||
<!-- <a-select-option :value="9">外部链接</a-select-option>-->
|
||||
<!-- </a-select>-->
|
||||
<!-- </a-form-item>-->
|
||||
<!-- <a-form-item label="位置" name="position">-->
|
||||
<!-- <a-radio-group v-model:value="form.position">-->
|
||||
<!-- <a-radio :value="0">全部</a-radio>-->
|
||||
<!-- <a-radio :value="1">顶部</a-radio>-->
|
||||
<!-- <a-radio :value="2">底部</a-radio>-->
|
||||
<!-- </a-radio-group>-->
|
||||
<!-- </a-form-item>-->
|
||||
<a-form-item label="模型" name="model">
|
||||
<ChooseDictionary
|
||||
dict-code="NavigationModel"
|
||||
:placeholder="`选择模型`"
|
||||
v-model:value="form.model"
|
||||
@done="chooseModel"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="位置" name="top">
|
||||
<a-radio-group v-model:value="form.position" @change="onPosition">
|
||||
<a-radio-button :value="0">不限</a-radio-button>
|
||||
<a-radio-button :value="1">顶部</a-radio-button>
|
||||
<a-radio-button :value="2">底部</a-radio-button>
|
||||
<a-radio :value="1">顶部</a-radio>
|
||||
<a-radio :value="2">底部</a-radio>
|
||||
<a-radio :value="0">不限</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- <a-space>-->
|
||||
<!-- <a-switch-->
|
||||
<!-- checked-children="显示"-->
|
||||
<!-- un-checked-children="隐藏"-->
|
||||
<!-- :checked="form.top === 0"-->
|
||||
<!-- @update:checked="updateTopValue"-->
|
||||
<!-- />-->
|
||||
<!-- <a-switch-->
|
||||
<!-- checked-children="显示"-->
|
||||
<!-- un-checked-children="隐藏"-->
|
||||
<!-- :checked="form.bottom === 0"-->
|
||||
<!-- @update:checked="updateBottomValue"-->
|
||||
<!-- />-->
|
||||
<!-- </a-space>-->
|
||||
</a-form-item>
|
||||
<a-form-item label="权限" name="">
|
||||
<a-radio-group v-model:value="form.permission">
|
||||
<a-radio :value="0">所有人</a-radio>
|
||||
<a-radio :value="1">登录可见</a-radio>
|
||||
<a-radio :value="2">密码可见</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="允许评论" name="">
|
||||
<a-space>
|
||||
<a-switch
|
||||
checked-children="是"
|
||||
un-checked-children="否"
|
||||
:checked="form.hide === 0"
|
||||
@update:checked="updateHideValue"
|
||||
/>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" name="hide">
|
||||
<a-space>
|
||||
@@ -191,26 +138,6 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- <div style="margin-bottom: 22px">-->
|
||||
<!-- <a-divider />-->
|
||||
<!-- </div>-->
|
||||
<!-- <a-form-item-->
|
||||
<!-- label="备注"-->
|
||||
<!-- name="comments"-->
|
||||
<!-- :label-col="-->
|
||||
<!-- styleResponsive ? { md: 3, sm: 4, xs: 24 } : { flex: '90px' }-->
|
||||
<!-- "-->
|
||||
<!-- :wrapper-col="-->
|
||||
<!-- styleResponsive ? { md: 21, sm: 20, xs: 24 } : { flex: '1' }-->
|
||||
<!-- "-->
|
||||
<!-- >-->
|
||||
<!-- <a-textarea-->
|
||||
<!-- :rows="4"-->
|
||||
<!-- :maxlength="200"-->
|
||||
<!-- placeholder="请输入备注信息"-->
|
||||
<!-- v-model:value="form.comments"-->
|
||||
<!-- />-->
|
||||
<!-- </a-form-item>-->
|
||||
</a-form>
|
||||
</ele-modal>
|
||||
</template>
|
||||
@@ -224,16 +151,10 @@
|
||||
import useFormData from '@/utils/use-form-data';
|
||||
import { Navigation } from '@/api/cms/navigation/model';
|
||||
import { addNavigation, updateNavigation } from '@/api/cms/navigation';
|
||||
import { Design } from '@/api/cms/design/model';
|
||||
import { removeSiteInfoCache } from '@/api/cms/website';
|
||||
import { ArticleCategory } from '@/api/cms/category/model';
|
||||
import { Article } from '@/api/cms/article/model';
|
||||
import { Form } from '@/api/cms/form/model';
|
||||
import { DocsBook } from '@/api/cms/docs-book/model';
|
||||
import { Goods } from '@/api/shop/goods/model';
|
||||
import { GoodsCategory } from '@/api/shop/goodsCategory/model';
|
||||
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
|
||||
import { FileRecord } from '@/api/system/file/model';
|
||||
import { uuid } from 'ele-admin-pro';
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
@@ -269,15 +190,22 @@
|
||||
// 表单数据
|
||||
const { form, resetFields, assignFields } = useFormData<Navigation>({
|
||||
navigationId: undefined,
|
||||
model: '[custom]',
|
||||
code: undefined,
|
||||
modelName: '',
|
||||
type: 0,
|
||||
title: '',
|
||||
parentId: 0,
|
||||
path: '',
|
||||
component: '',
|
||||
parentName: undefined,
|
||||
parentPath: undefined,
|
||||
path: undefined,
|
||||
component: undefined,
|
||||
sortNumber: 100,
|
||||
hide: 0,
|
||||
permission: 0,
|
||||
password: uuid(),
|
||||
position: 1,
|
||||
top: 1,
|
||||
top: 0,
|
||||
bottom: 1,
|
||||
status: 0,
|
||||
pageId: 0,
|
||||
@@ -297,6 +225,14 @@
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
model: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择模型',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
// component: [
|
||||
// {
|
||||
// required: true,
|
||||
@@ -367,77 +303,10 @@
|
||||
]
|
||||
});
|
||||
|
||||
const onType = (index: number) => {
|
||||
if (index == 0) {
|
||||
form.path = '/';
|
||||
form.component = '';
|
||||
}
|
||||
if (index == 1) {
|
||||
form.path = '';
|
||||
form.component = '';
|
||||
}
|
||||
if (index == 2) {
|
||||
form.path = '';
|
||||
form.component = '';
|
||||
}
|
||||
if (index == 9) {
|
||||
form.path = undefined;
|
||||
form.component = '';
|
||||
}
|
||||
};
|
||||
|
||||
const choosePageId = (data: Design) => {
|
||||
form.pageId = data.pageId;
|
||||
form.pageName = data.name;
|
||||
form.title = data.name;
|
||||
form.path = data.path;
|
||||
form.component = data.component;
|
||||
};
|
||||
|
||||
const chooseArticleCategoryId = (data: ArticleCategory) => {
|
||||
form.articleCategoryId = data.categoryId;
|
||||
form.pageName = data.title;
|
||||
form.title = data.title;
|
||||
form.path = '/article/' + data.categoryId;
|
||||
form.component = '/article/index';
|
||||
};
|
||||
|
||||
const chooseArticle = (data: Article) => {
|
||||
form.articleId = data.articleId;
|
||||
form.title = data.title;
|
||||
form.pageName = data.title;
|
||||
form.path = '/a/' + data.articleId;
|
||||
form.component = '/article/detail';
|
||||
};
|
||||
|
||||
const chooseForm = (data: Form) => {
|
||||
form.formId = data.formId;
|
||||
form.title = data.name;
|
||||
form.pageName = data.name;
|
||||
form.path = '/form/' + data.formId;
|
||||
form.component = '/form/detail';
|
||||
};
|
||||
|
||||
const chooseDocsBook = (data: DocsBook) => {
|
||||
form.bookCode = data.code;
|
||||
form.title = data.name;
|
||||
form.pageName = data.name;
|
||||
form.path = '/docs/' + data.code;
|
||||
form.component = '/docs/index';
|
||||
};
|
||||
|
||||
const chooseGoodsCategory = (data: GoodsCategory) => {
|
||||
form.goodsCategoryId = data.categoryId;
|
||||
form.title = data.title;
|
||||
form.pageName = data.title;
|
||||
form.path = '/goods/search?categoryId=' + data.categoryId;
|
||||
form.component = '/goods/search';
|
||||
};
|
||||
|
||||
const chooseGoods = (data: Goods) => {
|
||||
form.goodsId = data.goodsId;
|
||||
form.path = '/goods/detail/' + data.goodsId;
|
||||
form.component = '/goods/search';
|
||||
const chooseModel = (item: Navigation) => {
|
||||
form.model = `${item.value}`;
|
||||
form.modelName = `${item.label}`;
|
||||
form.component = `/pages/${item.value}`;
|
||||
};
|
||||
|
||||
const chooseFile = (data: FileRecord) => {
|
||||
@@ -480,10 +349,6 @@
|
||||
const navigationForm = {
|
||||
...form
|
||||
};
|
||||
// if (form.path != '' && form.path?.charAt(0) != '/') {
|
||||
// message.error('路由必须以"/"开头');
|
||||
// return false;
|
||||
// }
|
||||
const saveOrUpdate = isUpdate.value ? updateNavigation : addNavigation;
|
||||
saveOrUpdate(navigationForm)
|
||||
.then((msg) => {
|
||||
@@ -509,14 +374,6 @@
|
||||
form.hide = value ? 0 : 1;
|
||||
};
|
||||
|
||||
const updateTopValue = (value: boolean) => {
|
||||
form.top = value ? 0 : 1;
|
||||
};
|
||||
|
||||
const updateBottomValue = (value: boolean) => {
|
||||
form.bottom = value ? 0 : 1;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
@@ -525,8 +382,7 @@
|
||||
if (props.data) {
|
||||
assignFields({
|
||||
...props.data,
|
||||
parentId:
|
||||
props.data.parentId === 0 ? undefined : props.data.parentId,
|
||||
parentId: props.data.parentId ? props.data.parentId : 0,
|
||||
tempPath: props.data.path
|
||||
});
|
||||
if (props.data.type == 2) {
|
||||
@@ -534,7 +390,6 @@
|
||||
}
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
form.parentId = props.parentId;
|
||||
isUpdate.value = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -60,19 +60,22 @@
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="column.key === 'type'">
|
||||
<a-tag v-if="isExternalLink(record.path)" color="red">外链</a-tag>
|
||||
<a-tag v-if="isExternalLink(record.path)" color="purple"
|
||||
>外部链接</a-tag
|
||||
>
|
||||
<a-tag v-else-if="index === 0" color="orange">首页</a-tag>
|
||||
<a-tag v-else-if="isExternalLink(record.component)" color="orange">
|
||||
内链
|
||||
</a-tag>
|
||||
<span v-else-if="isDirectory(record)"></span>
|
||||
<a-tag v-else-if="record.type === 0">通用</a-tag>
|
||||
<a-tag v-else-if="record.type === 0">通用模型</a-tag>
|
||||
<a-tag v-else-if="record.type === 1" color="purple">页面</a-tag>
|
||||
<a-tag v-else-if="record.type === 2">列表</a-tag>
|
||||
<a-tag v-else-if="record.type === 2" color="blue">文章列表</a-tag>
|
||||
<a-tag v-else-if="record.type === 3">文章</a-tag>
|
||||
<a-tag v-else-if="record.type === 4" color="cyan">表单</a-tag>
|
||||
<a-tag v-else-if="record.type === 5" color="green">文档</a-tag>
|
||||
<a-tag v-else-if="record.type === 9" color="orange">链接</a-tag>
|
||||
<a-tag v-else-if="record.type === 6" color="pink">图片列表</a-tag>
|
||||
<a-tag v-else-if="record.type === 9" color="purple">外部链接</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'title'">
|
||||
<a-avatar
|
||||
@@ -82,10 +85,9 @@
|
||||
style="margin-right: 10px"
|
||||
v-if="record.image"
|
||||
/>
|
||||
<a v-if="!isDirectory(record)" @click="openSpmUrl(record.path)">{{
|
||||
<a @click="openSpmUrl(record.path, record, record.navigationId)">{{
|
||||
record.title
|
||||
}}</a>
|
||||
<a v-else>{{ record.title }}</a>
|
||||
</template>
|
||||
<template v-if="column.key === 'showIndex'">
|
||||
<a-tag v-if="record.showIndex === 1" color="green">显示</a-tag>
|
||||
@@ -112,7 +114,9 @@
|
||||
<a-space>
|
||||
<a class="text-fuchsia-300" @click="openLayout(record)">布局</a>
|
||||
<a-divider type="vertical" />
|
||||
<a class="text-gray-400" @click="openDesign(record)">设置</a>
|
||||
<a-tooltip :title="`配置SEO及页面元素`">
|
||||
<a class="text-gray-400" @click="openDesign(record)">内容</a>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openEdit(null, record.navigationId)">添加</a>
|
||||
<a-divider type="vertical" />
|
||||
@@ -183,10 +187,11 @@
|
||||
updateNavigation
|
||||
} from '@/api/cms/navigation';
|
||||
import type { Navigation, NavigationParam } from '@/api/cms/navigation/model';
|
||||
import { openPreview, openSpmUrl, openUrl } from '@/utils/common';
|
||||
import { openSpmUrl } from '@/utils/common';
|
||||
import { getSiteInfo } from '@/api/layout';
|
||||
import { Design } from '@/api/cms/design/model';
|
||||
import { listDesign } from '@/api/cms/design';
|
||||
import router from '@/router';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
@@ -294,7 +299,7 @@
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ where }) => {
|
||||
where = {};
|
||||
where.title = searchText.value;
|
||||
where.keywords = searchText.value;
|
||||
// where.position = position.value;
|
||||
where.top = 0;
|
||||
where.bottom = undefined;
|
||||
@@ -350,6 +355,7 @@
|
||||
};
|
||||
|
||||
const openDesign = (row?: Navigation) => {
|
||||
// TODO 通用模型
|
||||
listDesign({
|
||||
navigationId: row?.navigationId,
|
||||
limit: 1
|
||||
@@ -361,6 +367,15 @@
|
||||
.finally(() => {
|
||||
showDesignEdit.value = true;
|
||||
});
|
||||
// TODO 文章列表
|
||||
if (row?.type === 2) {
|
||||
router.push({
|
||||
path: '/cms/article',
|
||||
query: { categoryId: row.navigationId, type: row.type }
|
||||
});
|
||||
}
|
||||
console.log(row);
|
||||
// /cms/article
|
||||
};
|
||||
|
||||
const openLayout = (row?: Navigation) => {
|
||||
|
||||
230
src/views/system/field/components/website-field-edit.vue
Normal file
230
src/views/system/field/components/website-field-edit.vue
Normal file
@@ -0,0 +1,230 @@
|
||||
<!-- 用户编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="500"
|
||||
: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: 5 }, sm: { span: 4 }, xs: { span: 24 } }"
|
||||
:wrapper-col="{ md: { span: 21 }, sm: { span: 22 }, xs: { span: 24 } }"
|
||||
>
|
||||
<a-form-item label="参数名" name="name">
|
||||
<!-- <ChooseWebsiteField-->
|
||||
<!-- v-model:value="form.name"-->
|
||||
<!-- :placeholder="`选择参数`"-->
|
||||
<!-- @done="chooseData"-->
|
||||
<!-- />-->
|
||||
<SelectWebsiteField
|
||||
:placeholder="`添加参数`"
|
||||
class="input-item"
|
||||
v-model:value="form.name"
|
||||
@done="chooseData"
|
||||
/>
|
||||
</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="图片格式">
|
||||
<SelectFile
|
||||
:placeholder="`请选择图片`"
|
||||
:limit="1"
|
||||
:data="images"
|
||||
@done="chooseImage"
|
||||
@del="onDeleteItem"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="可配置范围" name="modifyRange">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="[0-1]"
|
||||
v-model:value="form.modifyRange"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="默认值" name="defaultValue">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="0"
|
||||
v-model:value="form.defaultValue"
|
||||
/>
|
||||
</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="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 { WebsiteField } from '@/api/system/website/field/model';
|
||||
import useFormData from '@/utils/use-form-data';
|
||||
import { addWebsiteField, updateWebsiteField } from '@/api/system/website/field';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { removeSiteInfoCache } from '@/api/system/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';
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
websiteId: number | null | undefined;
|
||||
// 修改回显的数据
|
||||
data?: WebsiteField | 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<WebsiteField>({
|
||||
id: undefined,
|
||||
type: 0,
|
||||
name: undefined,
|
||||
value: undefined,
|
||||
modifyRange: undefined,
|
||||
defaultValue: undefined,
|
||||
comments: '',
|
||||
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: WebsiteField) => {
|
||||
assignFields(data);
|
||||
};
|
||||
|
||||
/* 保存编辑 */
|
||||
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
|
||||
? updateWebsiteField
|
||||
: addWebsiteField;
|
||||
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>
|
||||
13
src/views/system/field/components/website-field-search.vue
Normal file
13
src/views/system/field/components/website-field-search.vue
Normal 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>
|
||||
252
src/views/system/field/index.vue
Normal file
252
src/views/system/field/index.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<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>
|
||||
<WebsiteFieldSearch @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
|
||||
>
|
||||
</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>
|
||||
<ExclamationCircleOutlined />
|
||||
</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>
|
||||
<!-- 编辑弹窗 -->
|
||||
<WebsiteFieldEdit
|
||||
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 { 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';
|
||||
import WebsiteFieldSearch from './components/website-field-search.vue';
|
||||
import { Website } from '@/api/system/website/model';
|
||||
import WebsiteFieldEdit from './components/website-field-edit.vue';
|
||||
import {
|
||||
WebsiteField,
|
||||
WebsiteFieldParam
|
||||
} from '@/api/system/website/field/model';
|
||||
import {
|
||||
listWebsiteField,
|
||||
removeWebsiteField,
|
||||
undeleteWebsiteField,
|
||||
updateWebsiteField
|
||||
} from '@/api/system/website/field';
|
||||
import { copyText, getPageTitle } from '@/utils/common';
|
||||
|
||||
const props = defineProps<{
|
||||
websiteId: any;
|
||||
data: Website;
|
||||
}>();
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
const selection = ref<any[]>();
|
||||
// 当前编辑数据
|
||||
const current = ref<WebsiteField | null>(null);
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
// 搜索条件
|
||||
return listWebsiteField({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
title: '参数名',
|
||||
dataIndex: 'name',
|
||||
width: 180,
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'comments',
|
||||
key: 'comments',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '配置值',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
width: 300,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '默认值',
|
||||
width: 180,
|
||||
dataIndex: 'defaultValue'
|
||||
},
|
||||
{
|
||||
title: '可设置范围',
|
||||
width: 180,
|
||||
dataIndex: 'modifyRange'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortNumber',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
const moveUp = (row?: WebsiteField) => {
|
||||
updateWebsiteField({
|
||||
id: row?.id,
|
||||
sortNumber: Number(row?.sortNumber) + 1
|
||||
}).then((msg) => {
|
||||
message.success(msg);
|
||||
reload();
|
||||
});
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: WebsiteField) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const reload = (where?: WebsiteFieldParam) => {
|
||||
selection.value = [];
|
||||
tableRef?.value?.reload({ where: where });
|
||||
};
|
||||
|
||||
/* 删除单个 */
|
||||
const remove = (row: WebsiteField) => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeWebsiteField(row.id)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
// 从回收站放回原处
|
||||
const recovery = (row: WebsiteField) => {
|
||||
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: WebsiteField) => {
|
||||
return {
|
||||
// 行点击事件
|
||||
onClick: () => {
|
||||
// console.log(record);
|
||||
},
|
||||
// 行双击事件
|
||||
onDblclick: () => {
|
||||
openEdit(record);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.websiteId,
|
||||
(websiteId) => {
|
||||
if (websiteId) {
|
||||
reload();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'WebsiteFieldIndex'
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user