Browse Source

优化:文章编辑,兼容Image封面图if if(data.image && !data.files){...}

dev
科技小王子 3 months ago
parent
commit
618791d4d3
  1. 266
      SELECT_FILE_DRAG_DEMO.md
  2. 2
      src/api/cms/cmsWebsiteSetting/model/index.ts
  3. 1
      src/api/shop/shopGoods/model/index.ts
  4. 27
      src/api/system/setting/index.ts
  5. 2
      src/config/setting.ts
  6. 113
      src/i18n/lang/en/route.ts
  7. 119
      src/i18n/lang/zh_CN/route.ts
  8. 48
      src/layout/components/header-tools.vue
  9. 18
      src/layout/components/page-footer.vue
  10. 742
      src/layout/components/setting-drawer.vue
  11. 8
      src/store/modules/setting.ts
  12. 9
      src/store/modules/theme.ts
  13. 4
      src/views/cms/cmsAd/index.vue
  14. 14
      src/views/cms/cmsArticle/components/articleEdit.vue
  15. 4
      src/views/cms/cmsArticle/index.vue
  16. 2
      src/views/cms/cmsLink/index.vue
  17. 19
      src/views/cms/cmsNavigation/index.vue
  18. 8
      src/views/cms/cmsSetting/index.vue
  19. 24
      src/views/cms/cmsWebsiteSetting/components/cmsWebsiteSettingEdit.vue
  20. 2
      src/views/cms/cmsWebsiteSetting/index.vue
  21. 4
      src/views/cms/help/index.vue
  22. 2
      src/views/shop/shopGoods/components/extra.vue
  23. 56
      src/views/shop/shopGoods/components/search.vue
  24. 2577
      src/views/shop/shopGoods/components/shopGoodsEdit.vue
  25. 432
      src/views/shop/shopGoods/index.vue
  26. 102
      src/views/system/setting/components/privacy.vue
  27. 187
      src/views/system/setting/components/website.vue
  28. 93
      src/views/system/setting/index.vue

266
SELECT_FILE_DRAG_DEMO.md

@ -0,0 +1,266 @@
# 🔄 SelectFile组件拖拽调整顺序功能演示
## 🎯 功能概述
我已经成功为SelectFile组件添加了拖拽调整顺序的功能,让用户可以通过拖拽来重新排列文件的顺序。
### ✨ 核心功能
1. **🔄 拖拽排序**
- 支持鼠标拖拽调整文件顺序
- 实时视觉反馈和拖拽指示器
- 顺序指示器显示当前位置
2. **🎯 智能交互**
- 拖拽时显示拖拽指示器
- 悬停时显示拖拽提示
- 拖拽完成后自动更新数据
3. **📍 视觉反馈**
- 顺序指示器显示文件位置
- 拖拽时的视觉效果
- 悬停时的交互提示
### 🔧 技术实现
#### 1. 组件模板更新
```vue
<template>
<a-image-preview-group>
<div class="select-file-container">
<!-- 🔄 可拖拽的文件列表 -->
<div
class="draggable-file-list"
@dragover.prevent
@drop="onDrop"
>
<template v-for="(item, index) in localData" :key="item.id || index">
<div
class="image-upload-item draggable-item"
:class="{ 'dragging': dragIndex === index }"
draggable="true"
@dragstart="onDragStart(index, $event)"
@dragend="onDragEnd"
@dragenter="onDragEnter(index)"
@dragleave="onDragLeave"
v-if="isImage(item.url)"
>
<!-- 🎯 拖拽指示器 -->
<div class="drag-indicator">
<HolderOutlined />
</div>
<a-image :src="item.url" />
<!-- 📍 顺序指示器 -->
<div class="order-indicator">{{ index + 1 }}</div>
</div>
</template>
</div>
</div>
</a-image-preview-group>
</template>
```
#### 2. 拖拽逻辑实现
```typescript
// 🔄 拖拽相关状态
const dragIndex = ref<number | null>(null);
const dragOverIndex = ref<number | null>(null);
// 📝 本地数据副本,用于拖拽操作
const localData = ref<any[]>([]);
// 🔄 监听props.data变化,同步到localData
watch(
() => props.data,
(newData) => {
if (newData) {
localData.value = [...newData];
}
},
{ immediate: true, deep: true }
);
// 🔄 拖拽开始
const onDragStart = (index: number, event: DragEvent) => {
dragIndex.value = index;
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/html', index.toString());
}
};
// 🔄 拖拽结束
const onDragEnd = () => {
dragIndex.value = null;
dragOverIndex.value = null;
};
// 🔄 拖拽进入
const onDragEnter = (index: number) => {
dragOverIndex.value = index;
};
// 🔄 拖拽放置
const onDrop = (event: DragEvent) => {
event.preventDefault();
if (dragIndex.value !== null && dragOverIndex.value !== null && dragIndex.value !== dragOverIndex.value) {
const newData = [...localData.value];
const draggedItem = newData[dragIndex.value];
// 移除拖拽的项目
newData.splice(dragIndex.value, 1);
// 在新位置插入项目
const insertIndex = dragIndex.value < dragOverIndex.value ? dragOverIndex.value - 1 : dragOverIndex.value;
newData.splice(insertIndex, 0, draggedItem);
// 更新本地数据
localData.value = newData;
// 触发重新排序事件
emit('reorder', newData);
}
dragIndex.value = null;
dragOverIndex.value = null;
};
```
#### 3. 事件定义更新
```typescript
const emit = defineEmits<{
(e: 'done', data: FileRecord): void;
(e: 'del', index: number): void;
(e: 'clear'): void;
(e: 'reorder', data: any[]): void; // 新增重新排序事件
}>();
```
#### 4. 样式设计
```less
// 🔄 可拖拽项目样式
.draggable-item {
position: relative;
cursor: move;
transition: all 0.3s ease;
border-radius: 8px;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
.drag-indicator {
opacity: 1;
}
}
&.dragging {
opacity: 0.5;
transform: rotate(5deg) scale(0.95);
z-index: 1000;
}
}
// 🎯 拖拽指示器
.drag-indicator {
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
opacity: 0;
transition: opacity 0.2s ease;
z-index: 10;
pointer-events: none;
}
// 📍 顺序指示器
.order-indicator {
position: absolute;
top: -6px;
right: -6px;
background: #1890ff;
color: white;
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
z-index: 5;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
```
### 🔗 父组件集成
在articleEdit.vue中添加对reorder事件的处理:
```vue
<SelectFile
:placeholder="`请选择图片`"
:limit="6"
:data="files"
@done="chooseFile"
@del="onDeleteFile"
@reorder="onReorderFiles"
/>
```
```typescript
// 🔄 处理文件重新排序
const onReorderFiles = (newData: any[]) => {
files.value = newData;
form.files = JSON.stringify(files.value.map((d) => d.url));
message.success('文件顺序已更新');
};
```
### 🎨 用户体验
1. **直观操作**:用户可以直接拖拽文件来调整顺序
2. **视觉反馈**:拖拽时有清晰的视觉指示
3. **顺序显示**:每个文件都有序号显示当前位置
4. **即时更新**:拖拽完成后立即更新数据和UI
### 📊 功能特点
| 特性 | 描述 | 状态 |
|------|------|------|
| 拖拽排序 | 支持鼠标拖拽调整顺序 | ✅ |
| 视觉反馈 | 拖拽时的动画和指示器 | ✅ |
| 顺序指示 | 显示文件的当前位置 | ✅ |
| 数据同步 | 拖拽后自动更新数据 | ✅ |
| 事件通知 | 触发reorder事件通知父组件 | ✅ |
| 响应式设计 | 适配不同屏幕尺寸 | ✅ |
### 🚀 使用场景
1. **文章封面图排序**:调整封面图的显示顺序,第一张作为主封面
2. **图片轮播排序**:调整轮播图片的播放顺序
3. **文件优先级**:根据重要性调整文件的排列顺序
4. **展示顺序**:调整图片在前端的展示顺序
### 💡 技术亮点
- **原生HTML5拖拽API**:使用标准的拖拽事件
- **Vue3响应式**:利用Vue3的响应式系统
- **数据双向绑定**:保持组件内外数据同步
- **优雅的动画效果**:提供流畅的用户体验
- **类型安全**:完整的TypeScript类型定义
这个功能让用户可以更直观地管理文件顺序,特别是在处理多个封面图时,可以轻松调整哪张图片作为主封面显示!🎉

2
src/api/cms/cmsWebsiteSetting/model/index.ts

@ -28,6 +28,8 @@ export interface CmsWebsiteSetting {
loginBtn?: string;
// 显示悬浮客服工具
floatTool?: boolean;
// 显示版权信息
showCopyright?: boolean;
// 显示版权链接
copyrightLink?: string;
// 导航栏最多显示数量

1
src/api/shop/shopGoods/model/index.ts

@ -140,6 +140,7 @@ export interface ShopGoodsParam extends PageParam {
parentId?: number;
categoryId?: number;
goodsId?: number;
status?: number;
goodsName?: string;
isShow?: number;
stock?: number;

27
src/api/system/setting/index.ts

@ -48,6 +48,19 @@ export async function getSetting(id: number) {
return Promise.reject(new Error(res.data.message));
}
/**
* key查询
*/
export async function getSettingByKey(key: string) {
const res = await request.get<ApiResult<any>>(
SERVER_API_URL + '/system/setting/getByKey/' + key
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
*
*/
@ -76,6 +89,20 @@ export async function updateSetting(data: Setting) {
return Promise.reject(new Error(res.data.message));
}
/**
* Key修改设置
*/
export async function updateSettingByKey(data: Setting) {
const res = await request.put<ApiResult<unknown>>(
SERVER_API_URL + '/system/setting/updateByKey',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
*
*/

2
src/config/setting.ts

@ -65,7 +65,7 @@ export const TOKEN_HEADER_NAME = 'Authorization';
// token 存储的名称
export const TOKEN_STORE_NAME = 'access_token';
// 主题配置存储的名称
export const THEME_STORE_NAME = 'theme:';
export const THEME_STORE_NAME = 'theme';
// i18n 缓存的名称
export const I18N_CACHE_NAME = 'i18n-lang';
// 是否开启国际化功能

113
src/i18n/lang/en/route.ts

@ -8,48 +8,6 @@ export default {
analysis: { _name: 'Analysis' },
monitor: { _name: 'Monitor' }
},
system: {
_name: 'System',
user: {
_name: 'User',
details: { _name: '' }
},
role: { _name: 'Role' },
menu: { _name: 'Menu' },
dictionary: { _name: 'Dictionary' },
dict: { _name: 'Dictionary' },
organization: { _name: 'Organization' },
loginRecord: { _name: 'LoginRecord' },
operationRecord: { _name: 'OperationRecord' },
file: { _name: 'File' },
userInfo: { _name: '' },
admin: {_name: 'Admin'},
setting: {_name: 'Setting'}
},
form: {
_name: 'Form',
basic: { _name: 'Basic Form' },
advanced: { _name: 'Advanced Form' },
step: { _name: 'Step Form' }
},
list: {
_name: 'List',
basic: {
_name: 'Basic List',
add: { _name: 'UserAdd' },
edit: { _name: 'UserEdit' },
details: {
':id': { _name: '' }
}
},
advanced: { _name: 'Advanced List' },
card: {
_name: 'Card List',
project: { _name: 'Project' },
application: { _name: 'Application' },
article: { _name: 'Article' }
}
},
result: {
_name: 'Result',
success: { _name: 'Success' },
@ -60,76 +18,5 @@ export default {
'403': { _name: '403' },
'404': { _name: '404' },
'500': { _name: '500' }
},
user: {
_name: 'User',
profile: { _name: 'Profile' },
message: { _name: 'Message' }
},
extension: {
_name: 'Extension',
tag: { _name: 'Tags' },
dialog: { _name: 'DragDialog' },
file: { _name: 'FileList' },
upload: { _name: 'ImageUpload' },
dragsort: { _name: 'DragSort' },
colorPicker: { _name: 'ColorPicker' },
regions: { _name: 'CitySelect' },
printer: { _name: 'Printer' },
excel: { _name: 'Excel' },
countUp: { _name: 'CountUp' },
tableSelect: { _name: 'TableSelect' },
player: { _name: 'Player' },
map: { _name: 'Map' },
qrCode: { _name: 'QRCode' },
barCode: { _name: 'BarCode' },
editor: { _name: 'Editor' },
markdown: { _name: 'Markdown' }
},
example: {
_name: 'Example',
table: { _name: 'ProTable' },
menuBadge: { _name: 'MenuBadge' },
eleadmin: { _name: 'IFrame' },
eleadminDoc: { _name: 'IFrame2' },
document: { _name: 'Document' },
choose: { _name: 'Choose' }
},
'https://eleadminCom/goods/9': { _name: 'Authorization' },
website: {
_name: 'Content',
index: {
_name: 'Home'
},
navigation: {
_name: 'Category'
},
article: {
_name: 'Article'
},
link: {
_name: 'Link'
},
order: {
_name: 'Order'
},
photo: {
_name: 'Photo'
},
ad: {
_name: 'Ad'
},
form: {
_name: 'Form'
},
dict: {
_name: 'Source'
},
field: {
_name: 'Configuration'
},
template: {
_name: 'Template'
}
}
};

119
src/i18n/lang/zh_CN/route.ts

@ -2,54 +2,6 @@
export default {
login: { _name: '登录' },
forget: { _name: '忘记密码' },
system: {
_name: '系统管理',
user: {
_name: '用户管理',
add: { _name: '添加用户' },
edit: { _name: '修改用户' },
details: { _name: '' }
},
role: { _name: '角色管理' },
menu: { _name: '菜单管理' },
dictionary: { _name: '公共字典' },
dict: { _name: '字典管理' },
loginRecord: { _name: '登录日志' },
operationRecord: { _name: '操作日志' },
file: { _name: '文件管理' },
admin: {_name: '员工管理'},
setting: {_name: '系统设置'}
},
link: {
_name: '网址导航',
add: { _name: '添加网址' },
edit: { _name: '修改网址' },
details: { _name: '' }
},
form: {
_name: '表单页面',
basic: { _name: '基础表单' },
advanced: { _name: '复杂表单' },
step: { _name: '分步表单' }
},
list: {
_name: '列表页面',
basic: {
_name: '基础列表',
add: { _name: '添加用户' },
edit: { _name: '修改用户' },
details: {
':id': { _name: '' }
}
},
advanced: { _name: '复杂列表' },
card: {
_name: '卡片列表',
project: { _name: '项目列表' },
application: { _name: '应用列表' },
article: { _name: '文章列表' }
}
},
result: {
_name: '结果页面',
success: { _name: '成功页' },
@ -60,76 +12,5 @@ export default {
'403': { _name: '403' },
'404': { _name: '404' },
'500': { _name: '500' }
},
user: {
_name: '用户管理',
profile: { _name: '账号中心' },
message: { _name: '我的消息' }
},
extension: {
_name: '扩展组件',
tag: { _name: '标签组件' },
dialog: { _name: '拖拽弹窗' },
file: { _name: '文件列表' },
upload: { _name: '图片上传' },
dragsort: { _name: '拖拽排序' },
colorPicker: { _name: '颜色选择' },
regions: { _name: '城市选择' },
printer: { _name: '打印插件' },
excel: { _name: 'excel插件' },
countUp: { _name: '滚动数字' },
tableSelect: { _name: '表格下拉' },
player: { _name: '视频播放' },
map: { _name: '地图组件' },
qrCode: { _name: '二维码' },
barCode: { _name: '条形码' },
editor: { _name: '富文本框' },
markdown: { _name: 'markdown' }
},
example: {
_name: '常用实例',
table: { _name: '表格实例' },
menuBadge: { _name: '菜单徽章' },
eleadmin: { _name: '内嵌页面' },
eleadminDoc: { _name: '内嵌文档' },
document: { _name: '案卷调整' },
choose: { _name: '批量选择' }
},
'https://eleadminCom/goods/9': { _name: '获取授权' },
website: {
_name: '内容管理',
index: {
_name: '网站设置'
},
navigation: {
_name: '栏目导航'
},
article: {
_name: '文章管理'
},
link: {
_name: '友情链接'
},
order: {
_name: '订单管理'
},
photo: {
_name: '素材管理'
},
ad: {
_name: '广告管理'
},
form: {
_name: '表单管理'
},
dict: {
_name: '文章来源'
},
field: {
_name: '扩展程序'
},
template: {
_name: '网站模板'
}
}
};

48
src/layout/components/header-tools.vue

@ -3,7 +3,7 @@
<div class="ele-admin-header-tool">
<!-- 小程序码 -->
<div class="ele-admin-header-tool-item" @click="onQrCode">
<HomeOutlined />
<HomeOutlined/>
</div>
<!-- 消息通知 -->
<div class="ele-admin-header-tool-item" @click="openUrl(`/user/notice`)">
@ -95,12 +95,12 @@
</div>
</a-menu-item>
<template v-if="loginUser.username == 'admin' || loginUser.username == 'superAdmin'">
<!-- <a-menu-divider/>-->
<!-- <a-menu-item key="accessKey">-->
<!-- <div class="ele-cell">-->
<!-- <div class="ele-cell-content"> {{ t('layout.header.accessKey') }}</div>-->
<!-- </div>-->
<!-- </a-menu-item>-->
<a-menu-divider/>
<a-menu-item key="accessKey">
<div class="ele-cell">
<div class="ele-cell-content"> {{ t('layout.header.accessKey') }}</div>
</div>
</a-menu-item>
<a-menu-divider/>
<a-menu-item key="system">
<div class="ele-cell">
@ -121,9 +121,9 @@
</a-dropdown>
</div>
<!-- 主题设置 -->
<!-- <div class="ele-admin-header-tool-item" @click="openSetting">-->
<!-- <more-outlined />-->
<!-- </div>-->
<div class="ele-admin-header-tool-item" @click="openSetting">
<more-outlined/>
</div>
</div>
<!-- 修改密码弹窗 -->
<password-modal v-model:visible="passwordVisible"/>
@ -142,21 +142,18 @@ import {
DownOutlined,
ExclamationCircleOutlined,
FullscreenOutlined,
HomeOutlined,
MoreOutlined,
FullscreenExitOutlined
} from '@ant-design/icons-vue';
import {storeToRefs} from 'pinia';
import {copyText, openNew, openUrl} from '@/utils/common';
import {copyText, openUrl} from '@/utils/common';
import {useThemeStore} from '@/store/modules/theme';
import HeaderNotice from './header-notice.vue';
import PasswordModal from './password-modal.vue';
import SettingDrawer from './setting-drawer.vue';
import {useUserStore} from '@/store/modules/user';
import {logout} from '@/utils/page-tab-util';
import type {Menu} from '@/api/system/menu/model';
import {isExternalLink} from 'ele-admin-pro';
import {listRoles} from '@/api/system/role';
import I18nIcon from './i18n-icon.vue';
import {getSiteInfo} from "@/api/layout";
import {CmsWebsite} from "@/api/cms/cmsWebsite/model";
import Qrcode from "@/components/QrCode/index.vue";
@ -164,7 +161,6 @@ import Qrcode from "@/components/QrCode/index.vue";
//
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const i18n = localStorage.getItem('i18n');
const SiteUrl = localStorage.getItem('SiteUrl');
//
const showQrcode = ref(false);
@ -187,11 +183,9 @@ const passwordVisible = ref(false);
//
const settingVisible = ref(false);
const domain = ref(localStorage.getItem('Domain'))
//
const loginUser = computed(() => userStore.info ?? {});
const menuList = ref<Menu[]>([]);
const website = ref<CmsWebsite>();
/* 用户信息下拉点击 */
@ -231,18 +225,10 @@ const onQrCode = () => {
const hideShare = () => {
showQrcode.value = false;
}
const onChange = (index: number) => {
const item = menuList.value.find((d) => d.menuId == index);
const isExternal = isExternalLink(item?.path);
if (isExternal) {
return openNew(`${item?.path}`);
}
if (item?.parentId == 0) {
return push(item.path);
}
if (item?.component) {
return push(item.path);
}
/* 打开主题设置抽屉 */
const openSetting = () => {
settingVisible.value = true;
};
/* 切换全屏 */
@ -252,7 +238,7 @@ const toggleFullscreen = () => {
const reload = () => {
//
if(!localStorage.getItem('Domain')){
if (!localStorage.getItem('Domain')) {
getSiteInfo().then((data) => {
localStorage.setItem('Domain', `${data.domain}`)
localStorage.setItem('SiteUrl', `${data.prefix}${data.domain}`)

18
src/layout/components/page-footer.vue

@ -1,6 +1,6 @@
<!-- 全局页脚 -->
<template>
<div class="ele-text-center" style="padding: 16px 0">
<div v-if="config.setting?.showAdminCopyright" class="ele-text-center" style="padding: 16px 0">
<div class="ele-text-secondary" style="margin-top: 8px">
{{ t('layout.footer.copyright') }}
</div>
@ -8,7 +8,19 @@
</template>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
import {useI18n} from 'vue-i18n';
import {useWebsiteSettingStore} from "@/store/modules/setting";
import {getSettingByKey} from "@/api/system/setting";
const { t } = useI18n();
const {t} = useI18n();
const config = useWebsiteSettingStore();
const reload = async () => {
if (!config.setting) {
const info = await getSettingByKey('privacy');
config.setSetting(info)
}
}
reload();
</script>

742
src/layout/components/setting-drawer.vue

@ -26,12 +26,12 @@
class="ele-bg-base ele-side-dark"
@click="updateSideStyle('dark')"
>
<check-outlined v-if="sideStyle === 'dark'" />
<check-outlined v-if="sideStyle === 'dark'"/>
</div>
</a-tooltip>
<a-tooltip :title="t('layout.setting.sideStyles.light')">
<div class="ele-bg-base" @click="updateSideStyle('light')">
<check-outlined v-if="sideStyle === 'light'" />
<check-outlined v-if="sideStyle === 'light'"/>
</div>
</a-tooltip>
</div>
@ -42,7 +42,7 @@
class="ele-bg-base ele-head-light"
@click="updateHeadStyle('light')"
>
<check-outlined v-if="headStyle === 'light'" />
<check-outlined v-if="headStyle === 'light'"/>
</div>
</a-tooltip>
<a-tooltip :title="t('layout.setting.headStyles.dark')">
@ -50,7 +50,7 @@
class="ele-bg-base ele-head-dark"
@click="updateHeadStyle('dark')"
>
<check-outlined v-if="headStyle === 'dark'" />
<check-outlined v-if="headStyle === 'dark'"/>
</div>
</a-tooltip>
<a-tooltip :title="t('layout.setting.headStyles.primary')">
@ -59,7 +59,7 @@
@click="updateHeadStyle('primary')"
>
<div class="ele-bg-primary"></div>
<check-outlined v-if="headStyle === 'primary'" />
<check-outlined v-if="headStyle === 'primary'"/>
</div>
</a-tooltip>
</div>
@ -72,7 +72,7 @@
class="ele-setting-color-item"
@click="updateColor(item.value)"
>
<check-outlined v-if="item.value ? item.value === color : !color" />
<check-outlined v-if="item.value ? item.value === color : !color"/>
<a-tooltip :title="t('layout.setting.colors.' + item.name)">
<div class="ele-setting-color-tooltip"></div>
</a-tooltip>
@ -89,10 +89,10 @@
<div class="ele-setting-item">
<div class="setting-item-title">{{ t('layout.setting.darkMode') }}</div>
<div class="setting-item-control">
<a-switch size="small" :checked="darkMode" @change="updateDarkMode" />
<a-switch size="small" :checked="darkMode" @change="updateDarkMode"/>
</div>
</div>
<a-divider />
<a-divider/>
<!-- 导航布局 -->
<div
:class="[
@ -113,7 +113,7 @@
class="ele-bg-base ele-side-dark"
@click="updateLayoutStyle('side')"
>
<check-outlined v-if="layoutStyle === 'side'" />
<check-outlined v-if="layoutStyle === 'side'"/>
</div>
</a-tooltip>
<a-tooltip :title="t('layout.setting.layoutStyles.top')">
@ -121,7 +121,7 @@
class="ele-bg-base ele-head-dark ele-layout-top"
@click="updateLayoutStyle('top')"
>
<check-outlined v-if="layoutStyle === 'top'" />
<check-outlined v-if="layoutStyle === 'top'"/>
</div>
</a-tooltip>
<a-tooltip :title="t('layout.setting.layoutStyles.mix')">
@ -129,7 +129,7 @@
class="ele-bg-base ele-layout-mix"
@click="updateLayoutStyle('mix')"
>
<check-outlined v-if="layoutStyle === 'mix'" />
<check-outlined v-if="layoutStyle === 'mix'"/>
</div>
</a-tooltip>
</div>
@ -162,7 +162,7 @@
/>
</div>
</div>
<a-divider :class="{ 'hidden-xs-only': styleResponsive }" />
<a-divider :class="{ 'hidden-xs-only': styleResponsive }"/>
<div class="ele-setting-title ele-text-secondary">
{{ t('layout.setting.other') }}
</div>
@ -282,14 +282,14 @@
<div class="ele-setting-item">
<div class="setting-item-title">{{ t('layout.setting.weakMode') }}</div>
<div class="setting-item-control">
<a-switch size="small" :checked="weakMode" @change="updateWeakMode" />
<a-switch size="small" :checked="weakMode" @change="updateWeakMode"/>
</div>
</div>
<!-- 页签 -->
<div class="ele-setting-item">
<div class="setting-item-title">{{ t('layout.setting.showTabs') }}</div>
<div class="setting-item-control">
<a-switch size="small" :checked="showTabs" @change="updateShowTabs" />
<a-switch size="small" :checked="showTabs" @change="updateShowTabs"/>
</div>
</div>
<!-- 页签风格 -->
@ -345,12 +345,12 @@
</div>
</div>
<!-- 提示 -->
<a-divider />
<!-- <a-alert show-icon type="warning" :message="t('layout.setting.tips')">-->
<!-- <template #icon>-->
<!-- <sound-outlined />-->
<!-- </template>-->
<!-- </a-alert>-->
<a-divider/>
<a-alert show-icon type="warning" :message="t('layout.setting.tips')">
<template #icon>
<sound-outlined/>
</template>
</a-alert>
<!-- 重置 -->
<a-button block type="dashed" @click="resetSetting">
{{ t('layout.setting.reset') }}
@ -360,386 +360,388 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { message } from 'ant-design-vue/es';
import { CheckOutlined, SoundOutlined } from '@ant-design/icons-vue';
import { messageLoading } from 'ele-admin-pro/es';
import type {
ThemeItem,
HeadStyleType,
SideStyleType,
LayoutStyleType,
TabStyleType
} from 'ele-admin-pro/es';
import { useThemeStore } from '@/store/modules/theme';
defineProps<{
// drawer , v-model
visible: boolean;
}>();
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void;
}>();
const { t } = useI18n();
const themeStore = useThemeStore();
const {
showTabs,
showFooter,
headStyle,
sideStyle,
layoutStyle,
sideMenuStyle,
tabStyle,
transitionName,
fixedHeader,
fixedSidebar,
fixedBody,
bodyFull,
logoAutoSize,
colorfulIcon,
sideUniqueOpen,
styleResponsive,
weakMode,
darkMode,
color
} = storeToRefs(themeStore);
//
const themes = ref<ThemeItem[]>([
{
name: 'default',
color: '#1890ff'
},
{
name: 'dust',
value: '#5f80c7'
},
{
name: 'sunset',
value: '#faad14'
},
{
name: 'volcano',
value: '#f5686f'
},
{
name: 'purple',
value: '#9266f9'
},
{
name: 'green',
value: '#33cc99'
},
{
name: 'geekblue',
value: '#32a2d4'
}
]);
//
const predefineColors = ref<string[]>([
'#f5222d',
'#fa541c',
'#fa8c16',
'#faad14',
'#a0d911',
'#52c41a',
'#13c2c2',
'#2f54eb',
'#722ed1',
'#eb2f96'
]);
//
const colorValue = ref<string | undefined>(void 0);
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const updateShowTabs = (value: boolean) => {
themeStore.setShowTabs(value);
};
const updateShowFooter = (value: boolean) => {
themeStore.setShowFooter(value);
};
const updateHeadStyle = (value: HeadStyleType) => {
themeStore.setHeadStyle(value);
};
const updateSideStyle = (value: SideStyleType) => {
themeStore.setSideStyle(value);
};
const updateLayoutStyle = (value: LayoutStyleType) => {
themeStore.setLayoutStyle(value);
};
const updateSideMenuStyle = (value: boolean) => {
themeStore.setSideMenuStyle(value ? 'mix' : 'default');
};
const updateTabStyle = (value: TabStyleType) => {
themeStore.setTabStyle(value);
};
const updateTransitionName = (value: string) => {
themeStore.setTransitionName(value);
};
const updateFixedHeader = (value: boolean) => {
themeStore.setFixedHeader(value);
};
const updateFixedSidebar = (value: boolean) => {
themeStore.setFixedSidebar(value);
};
const updateFixedBody = (value: boolean) => {
themeStore.setFixedBody(value);
};
const updateBodyFull = (value: boolean) => {
themeStore.setBodyFull(!value);
};
const updateLogoAutoSize = (value: boolean) => {
themeStore.setLogoAutoSize(value);
};
const updateStyleResponsive = (value: boolean) => {
themeStore.setStyleResponsive(value);
updateVisible(false);
};
const updateColorfulIcon = (value: boolean) => {
themeStore.setColorfulIcon(value);
};
const updateSideUniqueOpen = (value: boolean) => {
themeStore.setSideUniqueOpen(value);
};
const updateWeakMode = (value: boolean) => {
themeStore.setWeakMode(value);
};
const updateDarkMode = (value: boolean) => {
doWithLoading(() => themeStore.setDarkMode(value));
};
const updateColor = (value?: string) => {
doWithLoading(() => themeStore.setColor(value));
};
const resetSetting = () => {
doWithLoading(() => themeStore.resetSetting());
};
const doWithLoading = (fun: () => Promise<void>) => {
const hide = messageLoading('正在加载主题..', 0);
setTimeout(() => {
fun()
.then(() => {
hide();
initColorValue();
})
.catch((e) => {
hide();
console.error(e);
message.error('主题加载失败');
});
}, 0);
};
const initColorValue = () => {
if (color?.value && !themes.value.some((t) => t.value === color.value)) {
colorValue.value = color.value;
} else {
colorValue.value = void 0;
}
};
import {ref} from 'vue';
import {useI18n} from 'vue-i18n';
import {storeToRefs} from 'pinia';
import {message} from 'ant-design-vue/es';
import {CheckOutlined, SoundOutlined} from '@ant-design/icons-vue';
import {messageLoading} from 'ele-admin-pro/es';
import type {
ThemeItem,
HeadStyleType,
SideStyleType,
LayoutStyleType,
TabStyleType
} from 'ele-admin-pro/es';
import {useThemeStore} from '@/store/modules/theme';
defineProps<{
// drawer , v-model
visible: boolean;
}>();
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void;
}>();
const {t} = useI18n();
const themeStore = useThemeStore();
const {
showTabs,
showFooter,
headStyle,
sideStyle,
layoutStyle,
sideMenuStyle,
tabStyle,
transitionName,
fixedHeader,
fixedSidebar,
fixedBody,
bodyFull,
logoAutoSize,
colorfulIcon,
sideUniqueOpen,
styleResponsive,
weakMode,
darkMode,
color
} = storeToRefs(themeStore);
//
const themes = ref<ThemeItem[]>([
{
name: 'default',
color: '#1890ff'
},
{
name: 'dust',
value: '#5f80c7'
},
{
name: 'sunset',
value: '#faad14'
},
{
name: 'volcano',
value: '#f5686f'
},
{
name: 'purple',
value: '#9266f9'
},
{
name: 'green',
value: '#33cc99'
},
{
name: 'geekblue',
value: '#32a2d4'
}
]);
//
const predefineColors = ref<string[]>([
'#f5222d',
'#fa541c',
'#fa8c16',
'#faad14',
'#a0d911',
'#52c41a',
'#13c2c2',
'#2f54eb',
'#722ed1',
'#eb2f96'
]);
//
const colorValue = ref<string | undefined>(void 0);
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const updateShowTabs = (value: boolean) => {
themeStore.setShowTabs(value);
};
const updateShowFooter = (value: boolean) => {
themeStore.setShowFooter(value);
};
const updateHeadStyle = (value: HeadStyleType) => {
themeStore.setHeadStyle(value);
};
const updateSideStyle = (value: SideStyleType) => {
themeStore.setSideStyle(value);
};
const updateLayoutStyle = (value: LayoutStyleType) => {
themeStore.setLayoutStyle(value);
};
const updateSideMenuStyle = (value: boolean) => {
themeStore.setSideMenuStyle(value ? 'mix' : 'default');
};
const updateTabStyle = (value: TabStyleType) => {
themeStore.setTabStyle(value);
};
const updateTransitionName = (value: string) => {
themeStore.setTransitionName(value);
};
const updateFixedHeader = (value: boolean) => {
themeStore.setFixedHeader(value);
};
const updateFixedSidebar = (value: boolean) => {
themeStore.setFixedSidebar(value);
};
const updateFixedBody = (value: boolean) => {
themeStore.setFixedBody(value);
};
const updateBodyFull = (value: boolean) => {
themeStore.setBodyFull(!value);
};
const updateLogoAutoSize = (value: boolean) => {
themeStore.setLogoAutoSize(value);
};
const updateStyleResponsive = (value: boolean) => {
themeStore.setStyleResponsive(value);
updateVisible(false);
};
const updateColorfulIcon = (value: boolean) => {
themeStore.setColorfulIcon(value);
};
const updateSideUniqueOpen = (value: boolean) => {
themeStore.setSideUniqueOpen(value);
};
const updateWeakMode = (value: boolean) => {
themeStore.setWeakMode(value);
};
const updateDarkMode = (value: boolean) => {
doWithLoading(() => themeStore.setDarkMode(value));
};
const updateColor = (value?: string) => {
doWithLoading(() => themeStore.setColor(value));
};
const resetSetting = () => {
doWithLoading(() => themeStore.resetSetting());
};
const doWithLoading = (fun: () => Promise<void>) => {
const hide = messageLoading('正在加载主题..', 0);
setTimeout(() => {
fun()
.then(() => {
hide();
initColorValue();
})
.catch((e) => {
hide();
console.error(e);
message.error('主题加载失败');
});
}, 0);
};
const initColorValue = () => {
if (color?.value && !themes.value.some((t) => t.value === color.value)) {
colorValue.value = color.value;
} else {
colorValue.value = void 0;
}
};
initColorValue();
initColorValue();
</script>
<style lang="less">
.ele-setting-wrapper {
padding: 20px 18px;
.ele-setting-wrapper {
padding: 20px 18px;
.ele-setting-title {
font-size: 13px;
margin-bottom: 15px;
}
.ele-setting-title {
font-size: 13px;
margin-bottom: 15px;
}
/* 主题风格 */
.ele-setting-theme > div {
width: 52px;
height: 36px;
line-height: 1;
border-radius: 3px;
margin: 0 20px 30px 0;
padding: 16px 0 0 26px;
box-sizing: border-box;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
display: inline-block;
vertical-align: top;
position: relative;
overflow: hidden;
cursor: pointer;
transition: background-color 0.2s;
/* 主题风格 */
&:before,
&:after,
& > .ele-bg-primary {
content: '';
width: 100%;
height: 10px;
background: #fff;
position: absolute;
left: 0;
top: 0;
transition: background-color 0.2s;
}
.ele-setting-theme > div {
width: 52px;
height: 36px;
line-height: 1;
border-radius: 3px;
margin: 0 20px 30px 0;
padding: 16px 0 0 26px;
box-sizing: border-box;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
display: inline-block;
vertical-align: top;
position: relative;
overflow: hidden;
cursor: pointer;
transition: background-color 0.2s;
&:before,
&:after,
& > .ele-bg-primary {
content: '';
width: 100%;
height: 10px;
background: #fff;
position: absolute;
left: 0;
top: 0;
transition: background-color 0.2s;
}
&:after {
width: 14px;
height: 100%;
}
&:after {
width: 14px;
height: 100%;
}
&.ele-side-dark:after,
&.ele-head-dark:before,
&.ele-layout-mix:before,
&.ele-layout-mix:after {
background: #001529;
}
&.ele-side-dark:after,
&.ele-head-dark:before,
&.ele-layout-mix:before,
&.ele-layout-mix:after {
background: #001529;
}
&.ele-head-light:before,
&.ele-head-dark:before,
& > .ele-bg-primary {
z-index: 1;
}
&.ele-head-light:before,
&.ele-head-dark:before,
& > .ele-bg-primary {
z-index: 1;
}
&.ele-layout-top {
padding-left: 19px;
&.ele-layout-top {
padding-left: 19px;
&:after {
display: none;
}
&:after {
display: none;
}
}
}
/* 主题色选择 */
.ele-setting-colors {
color: #fff;
margin-bottom: 20px;
}
/* 主题色选择 */
.ele-setting-color-item {
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 2px;
margin: 8px 8px 0 0;
display: inline-block;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
vertical-align: top;
position: relative;
text-align: center;
cursor: pointer;
.ele-setting-color-tooltip {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.ele-setting-colors {
color: #fff;
margin-bottom: 20px;
}
.ele-setting-color-item {
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 2px;
margin: 8px 8px 0 0;
display: inline-block;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
vertical-align: top;
position: relative;
text-align: center;
cursor: pointer;
.ele-setting-color-tooltip {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
/* 主题配置项 */
.ele-setting-item {
display: flex;
align-items: center;
margin-bottom: 20px;
/* 主题配置项 */
.setting-item-title {
flex: 1;
line-height: 28px;
}
.ele-setting-item {
display: flex;
align-items: center;
margin-bottom: 20px;
.setting-item-control {
line-height: 1;
}
.setting-item-title {
flex: 1;
line-height: 28px;
}
.ant-divider {
margin-bottom: 20px;
.setting-item-control {
line-height: 1;
}
}
.ant-alert + .ant-btn {
margin-top: 12px;
}
.ant-divider {
margin-bottom: 20px;
}
/* 暗黑模式 */
&.ele-setting-dark .ele-setting-theme > div {
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
.ant-alert + .ant-btn {
margin-top: 12px;
}
&:before,
&:after,
& > .ele-bg-primary {
background: #1f1f1f;
}
/* 暗黑模式 */
&.ele-side-dark:after,
&.ele-head-dark:before,
&.ele-layout-mix:before,
&.ele-layout-mix:after {
background: #262626;
}
}
}
&.ele-setting-dark .ele-setting-theme > div {
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
/* 颜色选择器 */
.ele-setting-color-picker.ele-color-picker-trigger {
padding: 0;
width: 20px;
height: 20px;
margin-top: 8px;
border: none !important;
background: none !important;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
&:before,
&:after,
& > .ele-bg-primary {
background: #1f1f1f;
}
& > .ele-color-picker-trigger-inner {
background: none;
&.is-empty {
background: conic-gradient(
from 90deg at 50% 50%,
rgb(255, 0, 0) -19.41deg,
rgb(255, 0, 0) 18.76deg,
rgb(255, 138, 0) 59.32deg,
rgb(255, 230, 0) 99.87deg,
rgb(20, 255, 0) 141.65deg,
rgb(0, 163, 255) 177.72deg,
rgb(5, 0, 255) 220.23deg,
rgb(173, 0, 255) 260.13deg,
rgb(255, 0, 199) 300.69deg,
rgb(255, 0, 0) 340.59deg,
rgb(255, 0, 0) 378.76deg
);
& + .ele-color-picker-trigger-arrow {
display: none;
}
&.ele-side-dark:after,
&.ele-head-dark:before,
&.ele-layout-mix:before,
&.ele-layout-mix:after {
background: #262626;
}
}
}
/* 颜色选择器 */
.ele-setting-color-picker.ele-color-picker-trigger {
padding: 0;
width: 20px;
height: 20px;
margin-top: 8px;
border: none !important;
background: none !important;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
& > .ele-color-picker-trigger-inner {
background: none;
&.is-empty {
background: conic-gradient(from 90deg at 50% 50%,
rgb(255, 0, 0) -19.41deg,
rgb(255, 0, 0) 18.76deg,
rgb(255, 138, 0) 59.32deg,
rgb(255, 230, 0) 99.87deg,
rgb(20, 255, 0) 141.65deg,
rgb(0, 163, 255) 177.72deg,
rgb(5, 0, 255) 220.23deg,
rgb(173, 0, 255) 260.13deg,
rgb(255, 0, 199) 300.69deg,
rgb(255, 0, 0) 340.59deg,
rgb(255, 0, 0) 378.76deg);
& + .ele-color-picker-trigger-arrow {
display: none;
}
}
}
}
</style>

8
src/store/modules/setting.ts

@ -2,10 +2,9 @@
* store
*/
import { defineStore } from 'pinia';
import { CmsWebsiteSetting } from '@/api/cms/cmsWebsiteSetting/model';
export interface ParamsState {
setting: CmsWebsiteSetting | null;
setting: any | null;
}
export const useWebsiteSettingStore = defineStore({
@ -16,8 +15,11 @@ export const useWebsiteSettingStore = defineStore({
}),
getters: {},
actions: {
setSetting(value: CmsWebsiteSetting) {
setSetting(value: any) {
this.setting = value;
},
getSetting(value: any){
return value;
}
},
});

9
src/store/modules/theme.ts

@ -100,17 +100,8 @@ let disableTransitionTimer: number, updateContentSizeTimer: number;
function getCacheSetting(): any {
try {
const value = localStorage.getItem(THEME_STORE_NAME);
// 加载redis缓存
// getCache('theme').then((data) => {
// if (typeof data === 'object') {
// // 写入本地缓存
// localStorage.setItem(THEME_STORE_NAME, JSON.stringify(data));
// return data;
// }
// });
if (value) {
const cache = JSON.parse(value);
// 加载本地缓存
if (typeof cache === 'object') {
return cache;
}

4
src/views/cms/cmsAd/index.vue

@ -246,9 +246,7 @@ const query = () => {
loading.value = true;
//
if (!navigationList.value) {
listCmsNavigation({
lang: localStorage.getItem('i18n-lang') || undefined
}).then((res) => {
listCmsNavigation({}).then((res) => {
navigationList.value = toTreeData({
data: res?.map((d) => {
d.value = d.navigationId;

14
src/views/cms/cmsArticle/components/articleEdit.vue

@ -1261,13 +1261,6 @@ watch(
if (data.content) {
content.value = data.content;
}
if (data.image) {
images.value.push({
uid: uuid(),
url: data.image,
status: 'done'
});
}
if (!data.source) {
form.source = undefined;
}
@ -1289,6 +1282,13 @@ watch(
});
});
}
if (data.image && !data.files) {
files.value.push({
uid: uuid(),
url: data.image,
status: 'done'
});
}
loading.value = false;
isUpdate.value = true;
} else {

4
src/views/cms/cmsArticle/index.vue

@ -397,9 +397,7 @@ const customRow = (record: CmsArticle) => {
//
if (!navigationList.value) {
listCmsNavigation({
lang: localStorage.getItem('i18n-lang') || undefined
}).then((res) => {
listCmsNavigation({}).then((res) => {
navigationList.value = toTreeData({
data: res?.map((d) => {
d.value = d.navigationId;

2
src/views/cms/cmsLink/index.vue

@ -232,7 +232,7 @@ const query = () => {
loading.value = true;
//
if (!navigationList.value) {
listCmsNavigation({lang: getLang()}).then((res) => {
listCmsNavigation({}).then((res) => {
navigationList.value = toTreeData({
data: res?.map((d) => {
d.value = d.navigationId;

19
src/views/cms/cmsNavigation/index.vue

@ -160,14 +160,15 @@
<!-- <a-tooltip :title="`自定义组件`">-->
<!-- <a @click="openDesign(record)">组件</a>-->
<!-- </a-tooltip>-->
<!-- <a-divider type="vertical"/>-->
<!-- <a-popconfirm-->
<!-- placement="topRight"-->
<!-- title="确定要删除此菜单吗?"-->
<!-- @confirm="remove(record)"-->
<!-- >-->
<!-- <a class="ele-text-danger">删除</a>-->
<!-- </a-popconfirm>-->
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical"/>
<a-popconfirm
placement="topRight"
title="确定要删除此菜单吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</template>
</template>
</template>
@ -542,7 +543,7 @@ const customRow = (record: CmsNavigation) => {
},
//
onDblclick: () => {
if(record.model !== 'index'){
if (record.model !== 'index') {
openEdit(record);
}
}

8
src/views/cms/cmsSetting/index.vue

@ -21,6 +21,9 @@
<a-form-item label="显示站内搜索" name="searchBtn">
<a-switch v-model:checked="form.searchBtn" checked-children="显示" un-checked-children="隐藏" @change="save" />
</a-form-item>
<a-form-item label="显示版权" name="showCopyright">
<a-switch v-model:checked="form.showCopyright" checked-children="显示" un-checked-children="隐藏" @change="save" />
</a-form-item>
<a-form-item label="启用登录注册" name="loginBtn">
<a-switch v-model:checked="form.loginBtn" checked-children="启用" un-checked-children="不启用" @change="save" />
</a-form-item>
@ -61,7 +64,10 @@
import router from "@/router";
import {CmsWebsiteSetting} from "@/api/cms/cmsWebsiteSetting/model";
import {getCmsWebsiteSetting, updateCmsWebsiteSetting} from "@/api/cms/cmsWebsiteSetting";
import {useWebsiteSettingStore} from "@/store/modules/setting";
//
const setting = useWebsiteSettingStore();
const useForm = Form.useForm;
//
const themeStore = useThemeStore();
@ -87,6 +93,7 @@
searchBtn: undefined,
loginBtn: undefined,
floatTool: undefined,
showCopyright: undefined,
copyrightLink: undefined,
maxMenuNum: undefined,
deleted: undefined,
@ -137,6 +144,7 @@
const formData = {
...form
};
setting.setSetting(formData);
updateCmsWebsiteSetting(formData)
.then((msg) => {
loading.value = false;

24
src/views/cms/cmsWebsiteSetting/components/cmsWebsiteSettingEdit.vue

@ -133,14 +133,13 @@
<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 { assignObject } from 'ele-admin-pro';
import { addCmsWebsiteSetting, updateCmsWebsiteSetting } from '@/api/cms/cmsWebsiteSetting';
import { CmsWebsiteSetting } from '@/api/cms/cmsWebsiteSetting/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);
@ -208,20 +207,6 @@
]
});
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);
/* 保存编辑 */
@ -259,13 +244,6 @@
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;

2
src/views/cms/cmsWebsiteSetting/index.vue

@ -236,7 +236,7 @@
/* 删除单个 */
const remove = (row: CmsWebsiteSetting) => {
const hide = message.loading('请求中..', 0);
removeCmsWebsiteSetting(row.cmsWebsiteSettingId)
removeCmsWebsiteSetting(row.id)
.then((msg) => {
hide();
message.success(msg);

4
src/views/cms/help/index.vue

@ -323,9 +323,7 @@ const customRow = (record: CmsArticle) => {
//
if (!navigationList.value) {
listCmsNavigation({
lang: localStorage.getItem('i18n-lang') || undefined
}).then((res) => {
listCmsNavigation({}).then((res) => {
navigationList.value = toTreeData({
data: res?.map((d) => {
d.value = d.navigationId;

2
src/views/shop/shopGoods/components/extra.vue

@ -4,7 +4,7 @@
style="flex-wrap: wrap"
v-if="hasRole('superAdmin') || hasRole('admin') || hasRole('foundation')"
>
<a-button type="text" @click="push('/shop/category')">商品分类</a-button>
<a-button type="text" @click="push('/website/navigation')">商品分类</a-button>
</a-space>
</template>

56
src/views/shop/shopGoods/components/search.vue

@ -18,27 +18,27 @@
>已售罄({{ goodsCount?.totalNum3 }})
</a-radio-button>
</a-radio-group>
<SelectMerchant
:placeholder="`商户刷新`"
class="input-item"
v-if="!merchantId"
v-model:value="where.merchantName"
@done="chooseMerchantId"
/>
<SelectGoodsCategory
class="input-item"
:placeholder="`请选择商品分类`"
v-model:value="where.categoryId"
@done="chooseGoodsCategory"
<a-tree-select
allow-clear
:tree-data="navigationList"
tree-default-expand-all
style="width: 240px"
:listHeight="700"
placeholder="请选择栏目"
:value="where.categoryId || undefined"
:dropdown-style="{ overflow: 'auto' }"
@update:value="(value?: number) => (where.categoryId = value)"
@change="onCategoryId"
/>
<a-input-search
allow-clear
placeholder="请输入关键词"
style="width: 360px"
v-model:value="where.keywords"
@pressEnter="reload"
@search="reload"
/>
<a-button @click="reset">重置</a-button>
<a-button type="text" @click="reset">重置</a-button>
</a-space>
</template>
@ -48,15 +48,15 @@
import { getCount } from '@/api/shop/shopGoods';
import type { GoodsCount, ShopGoodsParam } from '@/api/shop/shopGoods/model';
import useSearch from '@/utils/use-search';
import { ShopMerchant } from '@/api/shop/shopMerchant/model';
import { ShopGoodsCategory } from '@/api/shop/shopGoodsCategory/model';
import { getMerchantId } from '@/utils/merchant';
import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
const props = withDefaults(
defineProps<{
//
selection?: [];
merchantId?: number;
navigationList?: CmsNavigation[];
}>(),
{
merchantId: getMerchantId()
@ -112,22 +112,6 @@
emit('search', where);
};
/* 搜索 */
const chooseMerchantId = (item: ShopMerchant) => {
where.merchantName = item.merchantName;
where.merchantId = item.merchantId;
reload();
};
const chooseGoodsCategory = (
category: ShopGoodsCategory,
data: ShopGoodsCategory
) => {
where.categoryName = data[1].label;
where.categoryId = data[1].value;
reload();
};
/* 重置 */
const reset = () => {
resetFields();
@ -135,10 +119,12 @@
reload();
};
// watch(
// () => props.selection,
// () => {}
// );
//
const onCategoryId = (id: number) => {
where.categoryId = id;
emit('search', where);
};
watch(
() => props.merchantId,
(id) => {

2577
src/views/shop/shopGoods/components/shopGoodsEdit.vue

File diff suppressed because it is too large

432
src/views/shop/shopGoods/index.vue

@ -1,7 +1,7 @@
<template>
<a-page-header :title="getPageTitle()" @back="() => $router.go(-1)">
<template #extra>
<Extra />
<Extra/>
</template>
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
@ -17,6 +17,7 @@
<search
@search="reload"
:selection="selection"
:navigationList="navigationList"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
@ -25,7 +26,7 @@
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
<a-space class="flex items-center">
<a-image :src="record.image" v-if="record.image" :width="50" />
<a-image :src="record.image" v-if="record.image" :width="50"/>
<span class="text-gray-700 font-bold">{{ record.name }}</span>
</a-space>
</template>
@ -38,7 +39,7 @@
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
@ -52,230 +53,249 @@
</a-card>
<!-- 编辑弹窗 -->
<ShopGoodsEdit v-model:visible="showEdit" :data="current" @done="reload" />
<ShopGoodsEdit v-model:visible="showEdit" :navigationList="navigationList" :data="current" @done="reload"/>
</a-page-header>
</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 ShopGoodsEdit from './components/shopGoodsEdit.vue';
import {
pageShopGoods,
removeShopGoods,
removeBatchShopGoods
} from '@/api/shop/shopGoods';
import type { ShopGoods, ShopGoodsParam } from '@/api/shop/shopGoods/model';
import { getPageTitle } from '@/utils/common';
import Extra from '@/views/shop/shopGoods/components/extra.vue';
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 {toTreeData} 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 ShopGoodsEdit from './components/shopGoodsEdit.vue';
import Extra from '@/views/shop/shopGoods/components/extra.vue';
import {
pageShopGoods,
removeShopGoods,
removeBatchShopGoods
} from '@/api/shop/shopGoods';
import type {ShopGoods, ShopGoodsParam} from '@/api/shop/shopGoods/model';
import {getPageTitle} from '@/utils/common';
import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
import {listCmsNavigation} from "@/api/cms/cmsNavigation";
//
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
//
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
//
const selection = ref<ShopGoods[]>([]);
//
const current = ref<ShopGoods | null>(null);
//
const showEdit = ref(false);
//
const showMove = ref(false);
//
const loading = ref(true);
//
const selection = ref<ShopGoods[]>([]);
//
const current = ref<ShopGoods | null>(null);
//
const navigationList = ref<CmsNavigation[]>();
//
const showEdit = ref(false);
//
const showMove = ref(false);
//
const loading = ref(true);
//
const datasource: DatasourceFunction = ({
//
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageShopGoods({
...where,
...orders,
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageShopGoods({
...where,
...orders,
page,
limit
});
};
limit
});
};
//
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'goodsId',
key: 'goodsId',
align: 'center',
width: 90
},
{
title: '商品',
dataIndex: 'name',
key: 'name',
width: 280
},
// {
// title: '',
// dataIndex: 'code',
// key: 'code',
// align: 'center',
// },
{
title: '价格',
dataIndex: 'price',
key: 'price',
align: 'center'
},
{
title: '销量',
dataIndex: 'sales',
key: 'sales',
align: 'center'
},
{
title: '库存',
dataIndex: 'stock',
key: 'stock',
align: 'center'
},
{
title: '推荐',
dataIndex: 'recommend',
key: 'recommend',
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center'
},
// {
// title: '',
// dataIndex: 'comments',
// key: 'comments',
// 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 columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'goodsId',
key: 'goodsId',
align: 'center',
width: 90
},
{
title: '商品',
dataIndex: 'name',
key: 'name',
width: 280
},
// {
// title: '',
// dataIndex: 'code',
// key: 'code',
// align: 'center',
// },
{
title: '价格',
dataIndex: 'price',
key: 'price',
align: 'center'
},
{
title: '销量',
dataIndex: 'sales',
key: 'sales',
align: 'center'
},
{
title: '库存',
dataIndex: 'stock',
key: 'stock',
align: 'center'
},
{
title: '推荐',
dataIndex: 'recommend',
key: 'recommend',
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center'
},
// {
// title: '',
// dataIndex: 'comments',
// key: 'comments',
// 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?: ShopGoodsParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 搜索 */
const reload = (where?: ShopGoodsParam) => {
selection.value = [];
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: ShopGoods) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开编辑弹窗 */
const openEdit = (row?: ShopGoods) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: ShopGoods) => {
const hide = message.loading('请求中..', 0);
removeShopGoods(row.shopGoodsId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 删除单个 */
const remove = (row: ShopGoods) => {
const hide = message.loading('请求中..', 0);
removeShopGoods(row.goodsId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchShopGoods(selection.value.map((d) => d.goodsId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchShopGoods(selection.value.map((d) => d.shopGoodsId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 查询 */
const query = () => {
loading.value = true;
//
if (!navigationList.value) {
listCmsNavigation({}).then((res) => {
navigationList.value = toTreeData({
data: res?.map((d) => {
d.value = d.navigationId;
d.label = d.title;
return d;
}),
idField: 'navigationId',
parentIdField: 'parentId'
});
});
}
};
/* 自定义行属性 */
const customRow = (record: ShopGoods) => {
return {
//
onClick: () => {
// console.log(record);
},
//
onDblclick: () => {
openEdit(record);
}
};
/* 自定义行属性 */
const customRow = (record: ShopGoods) => {
return {
//
onClick: () => {
// console.log(record);
},
//
onDblclick: () => {
openEdit(record);
}
};
query();
};
query();
</script>
<script lang="ts">
export default {
name: 'ShopGoods'
};
export default {
name: 'ShopGoods'
};
</script>
<style lang="less" scoped></style>

102
src/views/system/setting/components/privacy.vue

@ -0,0 +1,102 @@
<template>
<a-card :bordered="false">
<a-form
ref="formRef"
:model="form"
:label-col="styleResponsive ? { md: 3, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="styleResponsive ? { md: 9, sm: 19, xs: 24 } : { flex: '1' }"
>
<a-form-item label="允许被搜索" name="name" extra="关闭后,用户无法通过名称搜索到此网站">
<a-switch v-model:checked="form.searched" checked-children="允许" un-checked-children="不允许" @change="save" />
</a-form-item>
<a-form-item label="文章发布审核" name="articleReview" extra="开启需要审核后发布,关闭则直接发布">
<a-switch v-model:checked="form.articleReview" checked-children="需要" un-checked-children="不需要" @change="save" />
</a-form-item>
<a-form-item label="开发者模式" name="plugin" extra="开启开发者模式">
<a-switch v-model:checked="form.plugin" checked-children="启用" un-checked-children="禁用" @change="save" />
</a-form-item>
<a-form-item label="隐藏底部版权信息" name="showAdminCopyright">
<a-switch v-model:checked="form.showAdminCopyright" checked-children="显示" un-checked-children="隐藏" @change="save" />
</a-form-item>
</a-form>
</a-card>
</template>
<script lang="ts" setup>
import {ref, watch} from 'vue';
import {message} from 'ant-design-vue';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {FormInstance} from 'ant-design-vue/es/form';
import useFormData from '@/utils/use-form-data';
import {addSetting, updateSettingByKey} from "@/api/system/setting";
import {useWebsiteSettingStore} from "@/store/modules/setting";
const props = defineProps<{
value?: string;
//
data?: any | null;
}>();
//
const themeStore = useThemeStore();
const settingStore = useWebsiteSettingStore();
const {styleResponsive} = storeToRefs(themeStore);
//
const loading = ref(false);
//
const isUpdate = ref(false);
//
const formRef = ref<FormInstance | null>(null);
//
const {form, resetFields, assignFields} = useFormData<any>({
settingId: undefined,
settingKey: 'privacy',
searched: undefined,
showAdminCopyright: ''
});
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
//
settingStore.setSetting(form)
const appForm = {
...form,
content: JSON.stringify(form)
};
const saveOrUpdate = isUpdate.value ? updateSettingByKey : addSetting;
saveOrUpdate(appForm)
.then(() => {
message.success('保存成功');
})
.catch((e) => {
message.error(e.message);
});
})
.catch(() => {
});
};
watch(
() => props.data,
(data) => {
console.log(data,'propss')
if (data?.settingKey) {
isUpdate.value = true
//
assignFields(data);
} else {
//
isUpdate.value = false
resetFields();
}
}
);
</script>

187
src/views/system/setting/components/website.vue

@ -0,0 +1,187 @@
<template>
<a-card :bordered="false">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 3, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="styleResponsive ? { md: 9, sm: 19, xs: 24 } : { flex: '1' }"
>
<a-form-item label="悬浮工具栏" name="floatTool" extra="显示网站悬浮客服工具栏">
<a-switch v-model:checked="form.floatTool" checked-children="显示" un-checked-children="隐藏" @change="save" />
</a-form-item>
<a-form-item label="显示站内搜索" name="searchBtn">
<a-switch v-model:checked="form.searchBtn" checked-children="显示" un-checked-children="隐藏" @change="save" />
</a-form-item>
<a-form-item label="启用登录注册" name="loginBtn">
<a-switch v-model:checked="form.loginBtn" checked-children="启用" un-checked-children="不启用" @change="save" />
</a-form-item>
<a-form-item label="默认编辑器" name="editor" extra="设置默认编辑器">
<a-select v-model:value="form.editor" placeholder="请选择编辑器" class="max-w-xs" @change="save">
<a-select-option :value="1">富文本编辑器</a-select-option>
<a-select-option :value="2">Markdown编辑器</a-select-option>
</a-select>
</a-form-item>
</a-form>
</a-card>
</template>
<script lang="ts" setup>
import {reactive, ref, watch} from 'vue';
import {message} from 'ant-design-vue';
import {Setting} from '@/api/system/setting/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {FormInstance} from 'ant-design-vue/es/form';
import useFormData from '@/utils/use-form-data';
import {addSetting, updateSetting} from "@/api/system/setting";
import {ItemType} from "ele-admin-pro/es/ele-image-upload/types";
import {uploadFile} from "@/api/system/file";
const props = defineProps<{
value?: string;
//
data?: Setting | null;
}>();
// (key,contentjson)
const settingKey = ref('website');
//
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
//
const loading = ref(false);
//
const isUpdate = ref(false);
//
const formRef = ref<FormInstance | null>(null);
//
const {form, resetFields, assignFields} = useFormData<Setting>({
settingKey: 'website',
type: 1,
roleId: undefined,
openWxAuth: 1,
openWxBindPhone: 1,
openWxofficialAuth: 1,
openWxofficialBindPhone: 1,
tokenExpireTime: 86400,
comments: '',
tenantId: localStorage.getItem('TenantId')
});
//
const rules = reactive({
type: [
{
required: true,
message: '请选择默认注册方式',
type: 'number',
trigger: 'blur'
}
],
roleId: [
{
required: true,
message: '请选择默认角色',
type: 'number',
trigger: 'blur'
}
],
openWxAuth: [
{
required: true,
message: '请输入系统名称',
type: 'number',
trigger: 'blur'
}
],
openWxBindPhone: [
{
required: true,
message: '请输入系统名称',
type: 'number',
trigger: 'blur'
}
],
openWxofficialAuth: [
{
required: true,
message: '请输入系统名称',
type: 'number',
trigger: 'blur'
}
],
openWxofficialBindPhone: [
{
required: true,
message: '请输入系统名称',
type: 'number',
trigger: 'blur'
}
]
});
const onUpload = (d: ItemType) => {
uploadFile(<File>d.file)
.then((result) => {
form.logo = result.path;
message.success('上传成功');
})
.catch((e) => {
message.error(e.message);
});
};
const onClose = () => {
form.logo = undefined
}
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const appForm = {
...form,
content: JSON.stringify(form)
};
const saveOrUpdate = isUpdate.value ? updateSetting : addSetting;
saveOrUpdate(appForm)
.then((msg) => {
message.success('保存成功');
})
.catch((e) => {
message.error(e.message);
});
})
.catch(() => {
});
};
watch(
() => props.data,
(data) => {
if (data?.settingId) {
isUpdate.value = true
//
if (data.content) {
const jsonData = JSON.parse(data.content);
assignFields(jsonData);
}
//
form.settingId = data.settingId
form.settingKey = data.settingKey
} else {
//
isUpdate.value = false
resetFields();
form.settingKey = settingKey.value
}
}
);
</script>

93
src/views/system/setting/index.vue

@ -5,32 +5,35 @@
:body-style="{ paddingTop: '0px', minHeight: '800px' }"
>
<a-tabs v-model:active-key="active">
<a-tab-pane tab="网站设置" key="website">
<Website v-model:value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="上传设置" key="upload">
<Upload v-model:value="active" :data="data" />
<Upload v-model:value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="短信设置" key="sms">
<Sms v-model:value="active" :data="data" />
<Sms v-model:value="active" :data="data"/>
</a-tab-pane>
<!-- <a-tab-pane tab="支付设置" key="payment">-->
<!-- <Payment :value="active" :data="data" />-->
<!-- </a-tab-pane>-->
<a-tab-pane tab="注册设置" key="register">
<Register :value="active" :data="data" />
<Register :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="微信小程序" key="mp-weixin">
<MpWeixin :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="企业微信" key="wx-work">
<WxWork :value="active" :data="data" />
<WxWork :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="微信公众号" key="wx-official">
<WxOfficial :value="active" :data="data" />
<WxOfficial :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="微信小程序" key="mp-weixin">
<MpWeixin :value="active" :data="data" />
<a-tab-pane tab="隐私与安全" key="privacy">
<Privacy :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="打印设置" key="printer">
<Printer :value="active" :data="data" />
<Printer :value="active" :data="data"/>
</a-tab-pane>
<a-tab-pane tab="更新缓存" key="clear">
<Clear :value="active" :data="data" />
<Clear :value="active" :data="data"/>
</a-tab-pane>
</a-tabs>
</a-card>
@ -38,46 +41,44 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { Setting } from '@/api/system/setting/model';
import Upload from './components/upload.vue';
import Register from './components/register.vue';
import WxWork from './components/wx-work.vue';
import WxOfficial from './components/wx-official.vue';
import MpWeixin from './components/mp-weixin.vue';
// import Payment from './components/payment.vue';
import Sms from './components/sms.vue';
import Printer from './components/printer.vue';
import Clear from './components/clear.vue';
import { listSetting } from '@/api/system/setting';
import {ref, watch} from 'vue';
import {Setting} from '@/api/system/setting/model';
import Website from './components/website.vue';
import Upload from './components/upload.vue';
import Register from './components/register.vue';
import WxWork from './components/wx-work.vue';
import WxOfficial from './components/wx-official.vue';
import MpWeixin from './components/mp-weixin.vue';
import Privacy from './components/privacy.vue';
// import Payment from './components/payment.vue';
import Sms from './components/sms.vue';
import Printer from './components/printer.vue';
import Clear from './components/clear.vue';
import {getSettingByKey} from '@/api/system/setting';
// tab
const active = ref('upload');
// tab
const active = ref('privacy');
const data = ref<Setting>();
const data = ref<Setting>();
const reload = () => {
listSetting({ settingKey: active.value }).then((res) => {
if (res.length > 0) {
data.value = res[0];
} else {
data.value = {};
}
});
};
const reload = () => {
getSettingByKey(active.value).then(res => {
data.value = res;
})
};
reload();
reload();
watch(
() => active.value,
(value) => {
reload();
}
);
watch(
() => active.value,
() => {
reload();
}
);
</script>
<script lang="ts">
export default {
name: 'Setting'
};
export default {
name: 'Setting'
};
</script>

Loading…
Cancel
Save