v1.0.0-beta.1
16
admin/.env.development
Normal file
@ -0,0 +1,16 @@
|
||||
NODE_ENV = 'development'
|
||||
|
||||
# api请求地址
|
||||
VITE_APP_BASE_URL='/adminapi/'
|
||||
|
||||
# 图片服务器地址
|
||||
VITE_IMG_DOMAIN=''
|
||||
|
||||
# 请求时header中token的参数名
|
||||
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
||||
|
||||
# 请求时header中站点的参数名
|
||||
VITE_REQUEST_HEADER_SITEID_KEY='site-id'
|
||||
|
||||
# wap手机端请求地址
|
||||
VITE_WAP_DOMAIN=''
|
||||
16
admin/.env.production
Normal file
@ -0,0 +1,16 @@
|
||||
NODE_ENV = 'production'
|
||||
|
||||
# api请求地址
|
||||
VITE_APP_BASE_URL='/adminapi/'
|
||||
|
||||
# 图片服务器地址
|
||||
VITE_IMG_DOMAIN=''
|
||||
|
||||
# 请求时header中token的参数名
|
||||
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
||||
|
||||
# 请求时header中站点的参数名
|
||||
VITE_REQUEST_HEADER_SITEID_KEY='site-id'
|
||||
|
||||
# wap手机端请求地址
|
||||
VITE_WAP_DOMAIN=''
|
||||
27
admin/.eslintrc.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"standard-with-typescript",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"overrides": [
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"plugins": [
|
||||
"vue",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"no-tabs":"off",
|
||||
"indent": [1, 4, { "SwitchCase": 1 }],
|
||||
"eqeqeq":"off"
|
||||
}
|
||||
}
|
||||
24
admin/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
3
admin/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
||||
18
admin/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
5
admin/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
export {}
|
||||
declare global {
|
||||
|
||||
}
|
||||
78
admin/components.d.ts
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
|
||||
DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
|
||||
Editor: typeof import('./src/components/editor/index.vue')['default']
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElFooter: typeof import('element-plus/es')['ElFooter']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElImage: typeof import('element-plus/es')['ElImage']
|
||||
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElStatistic: typeof import('element-plus/es')['ElStatistic']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
Icon: typeof import('./src/components/icon/index.vue')['default']
|
||||
PopoverInput: typeof import('./src/components/popover-input/index.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SelectArea: typeof import('./src/components/select-area/index.vue')['default']
|
||||
SelectIcon: typeof import('./src/components/select-icon/index.vue')['default']
|
||||
UploadAttachment: typeof import('./src/components/upload-attachment/index.vue')['default']
|
||||
UploadFile: typeof import('./src/components/upload-file/index.vue')['default']
|
||||
UploadImage: typeof import('./src/components/upload-image/index.vue')['default']
|
||||
UploadVideo: typeof import('./src/components/upload-video/index.vue')['default']
|
||||
VideoPlayer: typeof import('./src/components/video-player/index.vue')['default']
|
||||
}
|
||||
export interface ComponentCustomProperties {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
}
|
||||
}
|
||||
13
admin/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image" href="/niucloud.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>管理端</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
11486
admin/package-lock.json
generated
Normal file
51
admin/package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "admin",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.3.1",
|
||||
"css-color-function": "^1.3.3",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.2.29",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.30",
|
||||
"qrcode": "^1.5.1",
|
||||
"sass": "^1.58.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-video-play": "^1.3.1-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/line-clamp": "^0.4.2",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^15.6.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"typescript": "^4.9.5",
|
||||
"unplugin-auto-import": "^0.13.0",
|
||||
"unplugin-vue-components": "^0.23.0",
|
||||
"vite": "^4.1.0",
|
||||
"vue-tsc": "^1.0.24"
|
||||
}
|
||||
}
|
||||
6
admin/postcss.config.cjs
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
BIN
admin/public/niucloud.ico
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
40
admin/src/App.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<el-config-provider :locale="locale">
|
||||
<router-view></router-view>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||
import en from 'element-plus/dist/locale/en.mjs'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { language } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 初始化设置语言
|
||||
const systemStore = useSystemStore()
|
||||
const locale = computed(() => (systemStore.lang === 'zh-cn' ? zhCn : en))
|
||||
language.loadLocaleMessages(route.path, systemStore.lang)
|
||||
|
||||
const toggleDark = useToggle(useDark())
|
||||
|
||||
watch(route, () => {
|
||||
useAppStore().$patch(state => {
|
||||
state.route = route.path
|
||||
})
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 设置主题色
|
||||
toggleDark(systemStore.dark)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
26
admin/src/api/aliapp.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取支付宝小程序配置
|
||||
* @returns
|
||||
*/
|
||||
export function getAliappConfig() {
|
||||
return request.get('aliapp/config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑支付宝小程序配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setAliappConfig(params: Record<string, any>) {
|
||||
return request.put('aliapp/config', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付宝小程序静态资源
|
||||
* @returns
|
||||
*/
|
||||
export function getAliappStatic() {
|
||||
return request.get('aliapp/static')
|
||||
}
|
||||
105
admin/src/api/article.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 文章表 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取文章表列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleList(params: Record<string, any>) {
|
||||
return request.get(`article/article`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章表详情
|
||||
* @param id 文章表id
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleInfo(id: number) {
|
||||
return request.get(`article/article/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addArticle(params: Record<string, any>) {
|
||||
return request.post('article/article', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章表
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateArticle(params: Record<string, any>) {
|
||||
return request.put(`article/article/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章表
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteArticle(id: number) {
|
||||
return request.delete(`article/article/${id}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
/***************************************************** 文章分类管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取文章分类列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleCategoryList(params: Record<string, any>) {
|
||||
return request.get(`article/category`, { params })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文章全部分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleCategoryAll(params: Record<string, any>) {
|
||||
return request.get(`article/category/all`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类详情
|
||||
* @param id 文章分类id
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleCategoryInfo(category_id: number) {
|
||||
return request.get(`article/category/${category_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addArticleCategory(params: Record<string, any>) {
|
||||
return request.post('article/category', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateArticleCategory(params: Record<string, any>) {
|
||||
return request.put(`article/category/${params.category_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类删除
|
||||
* @param id 文章分类id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteArticleCategory(category_id: number) {
|
||||
return request.delete(`article/category/${category_id}`, { showErrorMessage: true, showSuccessMessage: true });
|
||||
}
|
||||
26
admin/src/api/auth.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function login(params: Record<string, any>) {
|
||||
return request.get('login', { params, showErrorMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户权限
|
||||
* @returns
|
||||
*/
|
||||
export function getAuthMenus() {
|
||||
return request.get('auth/authmenu')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户权限
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteInfo() {
|
||||
return request.get('auth/site')
|
||||
}
|
||||
117
admin/src/api/diy.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 自定义页面 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取自定义页面列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyPageList(params: Record<string, any>) {
|
||||
return request.get(`diy/diy`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义页面详情
|
||||
* @param id 自定义页面id
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyPageInfo(id: number) {
|
||||
return request.get(`diy/diy/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加自定义页面
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addDiyPage(params: Record<string, any>) {
|
||||
return request.post('diy/diy', params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑自定义页面
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyPage(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/${params.id}`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 设为使用
|
||||
* @param params
|
||||
*/
|
||||
export function setUseDiyPage(params: Record<string, any>) {
|
||||
return request.put(`diy/use`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自定义页面分享内容
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyPageShare(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/share`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自定义页面
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteDiyPage(id: number) {
|
||||
return request.delete(`diy/diy/${id}`, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义页面初始化数据
|
||||
*/
|
||||
export function initPage(params: Record<string, any>) {
|
||||
return request.get(`diy/init`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义链接列表
|
||||
*/
|
||||
export function getLink(params: Record<string, any>) {
|
||||
return request.get(`diy/link`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部导航数据
|
||||
*/
|
||||
export function getDiyBottom(params: Record<string, any>) {
|
||||
return request.get(`diy/bottom`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置底部导航数据
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setDiyBottom(params: Record<string, any>) {
|
||||
return request.post('diy/bottom', params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面类型
|
||||
*/
|
||||
export function getDiyPageType(params: Record<string, any>) {
|
||||
return request.get(`diy/type`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义路由列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyRouteList(params: Record<string, any>) {
|
||||
return request.get(`diy/route`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改路由页面分享内容
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyRouteShare(params: Record<string, any>) {
|
||||
return request.put(`diy/route/share`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
18
admin/src/api/h5.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取h5配置
|
||||
* @returns
|
||||
*/
|
||||
export function getH5Config() {
|
||||
return request.get('channel/h5/config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑h5配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setH5Config(params: Record<string, any>) {
|
||||
return request.put('channel/h5/config', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
219
admin/src/api/member.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
/***************************************************** 会员管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取会员列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberList(params: Record<string, any>) {
|
||||
return request.get(`member/member`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员详情
|
||||
* @param id 会员id
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberInfo(id: number) {
|
||||
return request.get(`member/member/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会员
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addMember(params: Record<string, any>) {
|
||||
return request.post(`member/member`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员注册方式
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRegisterType(params: Record<string, any>) {
|
||||
return request.get(`member/registertype`, params)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************** 会员标签 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取会员标签列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberLabelList(params: Record<string, any>) {
|
||||
return request.get(`member/label`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员标签详情
|
||||
* @param label_id 会员标签label_id
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberLabelInfo(label_id: number) {
|
||||
return request.get(`member/label/${label_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会员标签
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addMemberLabel(params: Record<string, any>) {
|
||||
return request.post('member/label', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑会员标签
|
||||
* @param label_id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMemberLabel(params: Record<string, any>) {
|
||||
return request.put(`member/label/${params.label_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会员标签
|
||||
* @param label_id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteMemberLabel(label_id: number) {
|
||||
return request.delete(`member/label/${label_id}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部会员标签
|
||||
* @param label_id 会员标签label_id
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberLabelAll() {
|
||||
return request.get(`member/label/all`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑会员详情
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMemberDetail(params: Record<string, any>) {
|
||||
return request.put(`member/member/modify/${params.member_id}/${params.field}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 会员零钱 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取会员零钱列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMoneyList(params: Record<string, any>) {
|
||||
return request.get(`member/account/money`, {params})
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 会员账户 ****************************************************/
|
||||
|
||||
/**
|
||||
* 账户变动方式
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getChangeTypeList(change_type: string) {
|
||||
return request.get(`member/account/change_type/${change_type}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员积分流水
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getPointList(params: Record<string, any>) {
|
||||
return request.get(`member/account/point`, { params })
|
||||
}
|
||||
/**
|
||||
* 会员余额流水
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getBalanceList(params: Record<string, any>) {
|
||||
return request.get(`member/account/balance`, { params })
|
||||
}
|
||||
/**
|
||||
* 会员积分调整
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function adjustPoint(params: Record<string, any>) {
|
||||
return request.post(`member/account/point`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
/**
|
||||
* 会员余额调整
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function adjustBalance(params: Record<string, any>) {
|
||||
return request.post(`member/account/balance`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 会员相关设置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取登录设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getLoginConfig(params: Record<string, any>) {
|
||||
return request.get(`member/config/login`, params)
|
||||
}
|
||||
/**
|
||||
* 注册登录设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setLoginConfig(params: Record<string, any>) {
|
||||
return request.post(`member/config/login`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提现设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getWithdrawConfig() {
|
||||
return request.get(`member/config/withdraw`)
|
||||
}
|
||||
/**
|
||||
* 设置提现设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setWithdrawConfig(params: Record<string, any>) {
|
||||
return request.post(`member/config/withdraw`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员提现列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getWithdrawList(params: Record<string, any>) {
|
||||
return request.get(`member/withdraw`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员转账方式
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getTransfertype() {
|
||||
return request.get(`member/withdraw/transfertype`)
|
||||
}
|
||||
75
admin/src/api/message.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 消息管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 消息列表
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageList() {
|
||||
return request.get('message/message')
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageInfo(key: string) {
|
||||
return request.get(`message/message/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送记录
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageLog(params: any) {
|
||||
return request.get(`message/log`, { params })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 消息启动与关闭
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMessageStatus(params: Record<string, any>) {
|
||||
return request.post(`message/message/updatestatus`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息修改
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMessage(params: Record<string, any>) {
|
||||
return request.post(`message/message/update`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置列表
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsList() {
|
||||
return request.get('message/message/sms')
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置详情
|
||||
* @param sms_type
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsInfo(sms_type: string) {
|
||||
return request.get(`message/message/sms/${sms_type}`,)
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置修改
|
||||
* @param sms_type
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSms(params: Record<string, any>) {
|
||||
return request.put(`message/message/sms/${params.sms_type}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
29
admin/src/api/order.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 充值订单 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取充值订单列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderList(params: Record<string, any>) {
|
||||
return request.get(`order/recharge`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值订单详情
|
||||
* @param order_id
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderInfo(order_id: number) {
|
||||
return request.get(`order/recharge/${order_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值订单状态列表
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderStatusList() {
|
||||
return request.get(`order/recharge/status`)
|
||||
}
|
||||
18
admin/src/api/personal.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取支付设置
|
||||
* @returns
|
||||
*/
|
||||
export function getUserInfo(type:string) {
|
||||
return request.get(`auth/get`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置支付
|
||||
* @returns
|
||||
*/
|
||||
export function setUserInfo(params: Record<string, any>) {
|
||||
return request.put(`auth/update`, params, { showErrorMessage: true, showSuccessMessage: true });
|
||||
}
|
||||
|
||||
199
admin/src/api/site.ts
Normal file
@ -0,0 +1,199 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//包含站点管理,站点用户管理,站点操作日志
|
||||
|
||||
/***************************************************** 站点管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取站点列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteList(params: Record<string, any>) {
|
||||
return request.get(`site/site`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取站点详情
|
||||
* @param id 站点id
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteInfo(site_id: number) {
|
||||
return request.get(`site/site/${site_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加站点
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addSite(params: Record<string, any>) {
|
||||
return request.post('site/site', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新站点
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSite(params: Record<string, any>) {
|
||||
return request.put(`site/site/${params.site_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部站点状态
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getStatusList() {
|
||||
return request.get(`site/statuslist`)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 站点分组管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取站点分组列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteGroupList(params: Record<string, any>) {
|
||||
return request.get(`site/group`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取站点分组详情
|
||||
* @param id 站点id
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteGroupInfo(site_id: number) {
|
||||
return request.get(`site/group/${site_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加站点分组
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addSiteGroup(params: Record<string, any>) {
|
||||
return request.post('site/group', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新站点分组
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSiteGroup(params: Record<string, any>) {
|
||||
return request.put(`site/group/${params.group_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除站点分组
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function deleteSiteGroup(group_id: number) {
|
||||
return request.delete(`site/group/${group_id}`, { showErrorMessage: true, showSuccessMessage: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部站点分组
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteGroupAll(params: Record<string, any>) {
|
||||
return request.get(`site/group/all`, params)
|
||||
}
|
||||
|
||||
/***************************************************** 当前站点用户 *************************************************/
|
||||
|
||||
/**
|
||||
* 获取站点用户列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getUserList(params: Record<string, any>) {
|
||||
return request.get(`site/user`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取站点用户详情
|
||||
* @param id 站点id
|
||||
* @returns
|
||||
*/
|
||||
export function getUserInfo(uid: number) {
|
||||
return request.get(`site/user/${uid}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用户
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addUser(params: Record<string, any>) {
|
||||
return request.post('site/user', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户
|
||||
* @param uid
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateUser(params: Record<string, any>) {
|
||||
return request.put(`site/user/${params.uid}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param uid
|
||||
* @returns
|
||||
*/
|
||||
export function deleteUser(uid: number) {
|
||||
return request.delete(`site/user/${uid}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 锁定用户
|
||||
* @param uid
|
||||
* @returns
|
||||
*/
|
||||
export function lockUser(uid: number) {
|
||||
return request.put(`site/user/lock/${uid}`)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解锁用户
|
||||
* @param uid
|
||||
* @returns
|
||||
*/
|
||||
export function unlockUser(uid: number) {
|
||||
return request.put(`site/user/unlock/${uid}`)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 操作日志 **************************************************/
|
||||
|
||||
/**
|
||||
* 获取操作日志列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getLogList(params: Record<string, any>) {
|
||||
return request.get(`site/log`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作日志详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getLogInfo(id: number) {
|
||||
return request.get(`site/log/${id}`)
|
||||
}
|
||||
20
admin/src/api/stat.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 统计信息 **************************************************/
|
||||
/**
|
||||
* 获取统计信息
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getStatInfo() {
|
||||
return request.get(`stat/index`)
|
||||
}
|
||||
/**
|
||||
* 获取站点统计信息
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteStatInfo() {
|
||||
return request.get(`stat/siteindex`)
|
||||
}
|
||||
|
||||
367
admin/src/api/sys.ts
Normal file
@ -0,0 +1,367 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 系统整体信息 *************************************************/
|
||||
|
||||
/**
|
||||
* 系统信息
|
||||
* @returns
|
||||
*/
|
||||
export function getInfo() {
|
||||
return request.get('sys/role')
|
||||
}
|
||||
/***************************************************** 用户组 ****************************************************/
|
||||
|
||||
/**
|
||||
* 用户组列表
|
||||
* @returns
|
||||
*/
|
||||
export function getRoleList(params: Record<string, any>) {
|
||||
return request.get('sys/role', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户组详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRoleInfo(roleId: number) {
|
||||
return request.get(`sys/role/${roleId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用户组
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addRole(params: Record<string, any>) {
|
||||
return request.post(`sys/role`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户组
|
||||
* @param role_id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateRole(params: Record<string, any>) {
|
||||
return request.put(`sys/role/${params.role_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户组
|
||||
* @param role_id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteRole(roleId: number) {
|
||||
return request.delete(`sys/role/${roleId}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部分组
|
||||
* @returns
|
||||
*/
|
||||
export function allRole() {
|
||||
return request.get('sys/role/all')
|
||||
}
|
||||
|
||||
/***************************************************** 全部菜单 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取全部菜单
|
||||
* @returns
|
||||
*/
|
||||
export function getMenus(type:string) {
|
||||
return request.get(`sys/menu/${type}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单信息
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function getMenuInfo(menu_key: string) {
|
||||
return request.get(`sys/menu/info/${menu_key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加菜单
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addMenu(params: Record<string, any>) {
|
||||
return request.post('sys/menu', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新菜单
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMenu(params: Record<string, any>) {
|
||||
return request.put(`sys/menu/${params.menu_key}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteMenu(menu_key: string) {
|
||||
return request.delete(`sys/menu/${menu_key}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 站点菜单 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取站点菜单
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteMenus() {
|
||||
return request.get(`site/site/menu`)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 设置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取网站设置
|
||||
* @returns
|
||||
*/
|
||||
export function getWebsite() {
|
||||
return request.get('sys/config/website')
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新网站设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setWebsite(params: Record<string, any>) {
|
||||
return request.put(`sys/config/website`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版权设置
|
||||
* @returns
|
||||
*/
|
||||
export function getCopyright() {
|
||||
return request.get('sys/config/copyright')
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新版权设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setCopyright(params: Record<string, any>) {
|
||||
return request.put(`sys/config/copyright`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件组列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getAttachmentCategoryList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment/category`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加分类
|
||||
* @param params
|
||||
*/
|
||||
export function addAttachmentCategory(params: Record<string, any>) {
|
||||
return request.post(`sys/attachment/category`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateAttachmentCategory(params: Record<string, any>) {
|
||||
return request.put(`sys/attachment/category/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAttachmentCategory(id: number) {
|
||||
return request.delete(`sys/attachment/category/${id}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getAttachmentList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除附件
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAttachment(params: Record<string, any>) {
|
||||
return request.delete(`sys/attachment/del`, { data: params, showErrorMessage: true, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动附件
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function moveAttachment(params: Record<string, any>) {
|
||||
return request.put(`sys/attachment/batchmove`, params)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 地址管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取下级地址列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getAreaListByPid(pid: number = 0) {
|
||||
return request.get(`sys/area/list_by_pid/${pid}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地址树列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getAreatree(level: number = 1) {
|
||||
return request.get(`sys/area/tree/${level}`)
|
||||
}
|
||||
|
||||
/***************************************************** 存储设置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取存储配置列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getStorageList() {
|
||||
return request.get(`sys/storage`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getStorageInfo(type: string) {
|
||||
return request.get(`sys/storage/${type}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改存储
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateStorage(params: Record<string, any>) {
|
||||
return request.put(`sys/storage/${params.storage_type}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 支付设置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取支付设置
|
||||
* @returns
|
||||
*/
|
||||
export function getPayConfig(type:string) {
|
||||
return request.get(`pay/config/${type}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置支付
|
||||
* @returns
|
||||
*/
|
||||
export function setPayConfig(params: Record<string, any>) {
|
||||
return request.put(`pay/config/${params.type}`, params, { showErrorMessage: true, showSuccessMessage: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付列表
|
||||
* @returns
|
||||
*/
|
||||
export function getPayList() {
|
||||
return request.get(`pay/lists`)
|
||||
}
|
||||
|
||||
/***************************************************** 定时任务 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取任务列表
|
||||
* @returns
|
||||
*/
|
||||
export function getCronList(params:any) {
|
||||
return request.get(`sys/cron`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务详情
|
||||
* @returns
|
||||
*/
|
||||
export function getCronInfo(id:string) {
|
||||
return request.get(`sys/cron/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务类型
|
||||
* @returns
|
||||
*/
|
||||
export function getCronType() {
|
||||
return request.get(`sys/cron/type`)
|
||||
}
|
||||
|
||||
/***************************************************** 协议管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取协议列表
|
||||
* @returns
|
||||
*/
|
||||
export function getAgreementList() {
|
||||
return request.get(`sys/agreement`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 协议详情
|
||||
* @returns
|
||||
*/
|
||||
export function getAgreementInfo(key:string) {
|
||||
return request.get(`sys/agreement/${key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新协议
|
||||
* @returns
|
||||
*/
|
||||
export function updateAgreement(params: Record<string, any>) {
|
||||
return request.put(`sys/agreement/${params.key}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 协议详情
|
||||
* @returns
|
||||
*/
|
||||
export function getChannelType() {
|
||||
return request.get(`sys/channel`);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取渠道域名
|
||||
* @returns
|
||||
*/
|
||||
export function getSceneDomain() {
|
||||
return request.get(`sys/scene_domain`);
|
||||
}
|
||||
|
||||
68
admin/src/api/tools.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 代码生成 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取代码生成列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getGenerateTableList(params: Record<string, any>) {
|
||||
return request.get(`generator/generator`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代码生成详情
|
||||
* @param id 代码生成id
|
||||
* @returns
|
||||
*/
|
||||
export function getGenerateTableInfo(id: number) {
|
||||
return request.get(`generator/generator/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加代码生成
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addGenerateTable(params: Record<string, any>) {
|
||||
return request.post('generator/generator', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑代码生成
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateGenerateTable(params: Record<string, any>) {
|
||||
return request.put(`generator/generator/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除代码生成
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteGenerateTable(id: number) {
|
||||
return request.delete(`generator/generator/${id}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码生成
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function generateCreate(params: Record<string, any>) {
|
||||
return request.post(`generator/download`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据表
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
export function generateTable() {
|
||||
return request.get(`generator/table`)
|
||||
}
|
||||
|
||||
43
admin/src/api/user.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//当前接口用户指系统整体用户管理,站内用户添加,编辑,详情,操作日志,请查看站点内部相关接口
|
||||
|
||||
/***************************************************** 用户 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getUserList(params: Record<string, any>) {
|
||||
return request.get(`user/user`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
* @param uid 用户uid
|
||||
* @returns
|
||||
*/
|
||||
export function getUserInfo(uid: number) {
|
||||
return request.get(`user/user/${uid}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用户
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addUser(params: Record<string, any>) {
|
||||
return request.post('user/user', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateUser(params: Record<string, any>) {
|
||||
return request.put(`user/user/${params.uid}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
35
admin/src/api/weapp.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取微信小程序配置
|
||||
* @returns
|
||||
*/
|
||||
export function getWeappConfig() {
|
||||
return request.get('weapp/config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑微信小程序配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setWeappConfig(params: Record<string, any>) {
|
||||
return request.put('weapp/config', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订阅消息列表
|
||||
* @returns
|
||||
*/
|
||||
export function getTemplateList() {
|
||||
return request.get('weapp/template')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取同步
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getBatchAcquisition(params: Record<string, any>) {
|
||||
return request.put('weapp/template/sync', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
66
admin/src/api/wechat.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取微信配置
|
||||
* @returns
|
||||
*/
|
||||
export function getWechatConfig() {
|
||||
return request.get('wechat/config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信配置所需的静态信息
|
||||
* @param uid 用户uid
|
||||
* @returns
|
||||
*/
|
||||
export function getWechatStatic() {
|
||||
return request.get('wechat/static');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑微信配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateWechatConfig(params: Record<string, any>) {
|
||||
return request.put('wechat/config', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信菜单
|
||||
* @returns
|
||||
*/
|
||||
export function getWechatMenu() {
|
||||
return request.get('wechat/menu')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑微信菜单
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateWechatMenu(params: Record<string, any>) {
|
||||
return request.put('wechat/menu', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息模板列表
|
||||
* @returns
|
||||
*/
|
||||
export function getTemplateList() {
|
||||
return request.get('wechat/template')
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取同步
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getBatchAcquisition(params: Record<string, any>) {
|
||||
return request.put('wechat/template/sync', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
admin/src/assets/images/channel/preview.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
admin/src/assets/images/default_headimg.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
admin/src/assets/images/diy/text/style1.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
admin/src/assets/images/diy/text/style2.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
admin/src/assets/images/diy_preview_head.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
admin/src/assets/images/icon_folder.png
Normal file
|
After Width: | Height: | Size: 605 B |
BIN
admin/src/assets/images/icon_preview.png
Normal file
|
After Width: | Height: | Size: 392 B |
BIN
admin/src/assets/images/index/administrator.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
admin/src/assets/images/index/article_list.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
admin/src/assets/images/index/balance.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
admin/src/assets/images/index/fitment.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
admin/src/assets/images/index/member.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
admin/src/assets/images/login_bg.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
admin/src/assets/images/login_logo.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
admin/src/assets/images/logo-square.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
admin/src/assets/images/no_perms.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
admin/src/assets/images/theme_black.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
admin/src/assets/images/theme_white.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
admin/src/assets/images/wechat-menu-head-bg.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
admin/src/assets/images/wechat-menu-head-dark-bg.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
1
admin/src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
187
admin/src/components/diy-link/index.vue
Normal file
@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div>
|
||||
<div @click="show">
|
||||
<slot>
|
||||
<el-input v-model="value.title" :placeholder="t('linkPlaceholder')" readonly>
|
||||
<template #suffix>
|
||||
<div @click.stop="clear">
|
||||
<el-icon v-if="value.name">
|
||||
<Close/>
|
||||
</el-icon>
|
||||
<el-icon v-else>
|
||||
<ArrowRight/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</slot>
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" :title="t('selectLinkTips')" width="40%" :close-on-press-escape="false"
|
||||
:destroy-on-close="true" :close-on-click-modal="false">
|
||||
|
||||
<div class="flex items-start">
|
||||
<el-scrollbar class="w-[140px] border-r h-[350px]">
|
||||
<div v-for="(item,index) in link" :key="index"
|
||||
class="h-[40px] leading-[40px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
|
||||
:class="[ item.name == parentLinkName ? 'bg-primary-light-9 text-primary' : '' ]"
|
||||
@click="changeParentLink(item)">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<el-scrollbar class="pl-4 h-[350px] flex-1">
|
||||
<template v-if="parentLinkName == 'DIY_LINK'">
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkName')">
|
||||
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')"
|
||||
class="w-6/12"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkUrl')">
|
||||
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')"
|
||||
class="w-6/12"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label=" ">
|
||||
<div class="text-sm text-gray-400 select-text">路径必须以“/”开头,例:/pages/index/index</div>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<div class="text-sm text-gray-400 select-text">跳转外部链接“/”开头,例:https://baidu.com</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<div v-else class="flex flex-wrap">
|
||||
<div v-for="(item,index) in childList" :key="index"
|
||||
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
|
||||
:class="[ item.name == selectLink.name ? 'border-primary text-primary' : '' ]"
|
||||
@click="changeChildLink(item)">{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel')}}</el-button>
|
||||
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {t} from '@/lang'
|
||||
import {ref, computed} from 'vue'
|
||||
import {cloneDeep} from 'lodash-es'
|
||||
import {getLink} from '@/api/diy';
|
||||
import {ElMessage} from 'element-plus'
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value: any = computed({
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
const link: any = ref([])
|
||||
|
||||
const parentLinkName = ref('')
|
||||
|
||||
const childList: any = ref([])
|
||||
|
||||
const selectLink: any = ref([])
|
||||
|
||||
const show = () => {
|
||||
// 每次打开时赋值
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value);
|
||||
parentLinkName.value = selectLink.value.parent;
|
||||
}
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
getLink({}).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
link.value = res.data;
|
||||
childList.value = link.value[0].child_list;
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value);
|
||||
} else {
|
||||
selectLink.value = {
|
||||
parent: link.value[0].name
|
||||
};
|
||||
}
|
||||
parentLinkName.value = selectLink.value.parent;
|
||||
}
|
||||
});
|
||||
|
||||
// 选择父级链接
|
||||
const changeParentLink = (item: any) => {
|
||||
childList.value = item.child_list;
|
||||
parentLinkName.value = item.name;
|
||||
}
|
||||
|
||||
// 选择子链接
|
||||
const changeChildLink = (item: any) => {
|
||||
delete item.is_share;
|
||||
Object.assign(selectLink.value, item)
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
value.value = {
|
||||
name: '',
|
||||
parent: '',
|
||||
title: '',
|
||||
url: ''
|
||||
}
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
|
||||
// 自定义链接
|
||||
if (parentLinkName.value === 'DIY_LINK') {
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.name = parentLinkName.value
|
||||
|
||||
if (!selectLink.value.title) {
|
||||
ElMessage({
|
||||
message: t('diyLinkNameNotEmpty'),
|
||||
type: 'warning',
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectLink.value.url) {
|
||||
ElMessage({
|
||||
message: t('diyLinkUrlNotEmpty'),
|
||||
type: 'warning',
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
value.value = cloneDeep(selectLink.value)
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
101
admin/src/components/editor/index.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="border border-color">
|
||||
<toolbar class="border-b border-color" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
||||
<wang-editor :style="{ height, 'overflow-y': 'hidden', width: '100%' }" :defaultConfig="editorConfig" :mode="mode"
|
||||
v-model="content" @onCreated="handleCreated" />
|
||||
<upload-attachment type="image" ref="imageRef" :limit="10" @confirm="imageSelect" />
|
||||
<upload-attachment type="video" ref="videoRef" @confirm="videoSelect" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { shallowRef, computed, onBeforeUnmount, ref } from 'vue'
|
||||
import '@wangeditor/editor/dist/css/style.css'
|
||||
import { IToolbarConfig, IEditorConfig, IDomEditor } from '@wangeditor/editor'
|
||||
import { Editor as WangEditor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { img } from '@/utils/common'
|
||||
|
||||
const editorRef = shallowRef()
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'simple'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '300px'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const imageRef: Record<string, any> | null = ref(null)
|
||||
const videoRef: Record<string, any> | null = ref(null)
|
||||
|
||||
const content = computed({
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
// 工具栏配置
|
||||
const toolbarConfig: Partial<IToolbarConfig> = {
|
||||
excludeKeys: ['group-image', 'insertVideo', 'insertLink'],
|
||||
insertKeys: {
|
||||
index: 16,
|
||||
keys: ['uploadImage', 'uploadVideo']
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑器配置
|
||||
type InsertFnType = (url: string) => void
|
||||
let insertFn: InsertFnType = (url: string) => { }
|
||||
|
||||
const editorConfig: Partial<IEditorConfig> = {
|
||||
MENU_CONF: {
|
||||
uploadImage: {
|
||||
customBrowseAndUpload(insert: InsertFnType) {
|
||||
imageRef.value.showDialog = true
|
||||
insertFn = insert
|
||||
}
|
||||
},
|
||||
uploadVideo: {
|
||||
customBrowseAndUpload(insert: InsertFnType) {
|
||||
videoRef.value.showDialog = true
|
||||
insertFn = insert
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const imageSelect = (data: Record<string, any>) => {
|
||||
data.forEach((item: any) => { insertFn(img(item.url)) })
|
||||
}
|
||||
|
||||
const videoSelect = (data: Record<string, any>) => {
|
||||
insertFn(img(data.url))
|
||||
}
|
||||
|
||||
const handleCreated = (editor: IDomEditor) => {
|
||||
editorRef.value = editor
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件销毁时,也及时销毁编辑器
|
||||
*/
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
42
admin/src/components/icon/index.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { createVNode, resolveComponent, defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Icon',
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'var(--color)'
|
||||
},
|
||||
class: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '16px'
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
let [type, name] = props.name.split(/-(.*)/)
|
||||
|
||||
let style = {
|
||||
color: props.color,
|
||||
fontSize: props.size
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'element':
|
||||
return () => createVNode('el-icon', { class: ['icon el-icon', props.class], style: style }, [createVNode(resolveComponent(name))])
|
||||
break;
|
||||
case 'iconfont':
|
||||
return () => createVNode('i', { class: [name, 'iconfont', props.class], style: style })
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
64
admin/src/components/popover-input/index.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<el-popover placement="top" trigger="click" :width="prop.width" v-model:visible="visible">
|
||||
<el-input v-model="value" :placeholder="prop.placeholder" clearable class="mr-[10px]" :maxlength="prop.maxlength"
|
||||
:show-word-limit="true" />
|
||||
<div class="text-right mt-[15px]">
|
||||
<el-button @click="visible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ t('confirm') }}</el-button>
|
||||
</div>
|
||||
<template #reference>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const prop = defineProps({
|
||||
width: {
|
||||
type: String,
|
||||
default: '350px'
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 10
|
||||
}
|
||||
})
|
||||
|
||||
const value = ref(prop.value)
|
||||
const visible = ref(false)
|
||||
|
||||
watch(visible, () => {
|
||||
if (!visible.value) {
|
||||
value.value = ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
const confirm = () => {
|
||||
if (!/[\S]+/.test(value.value)) {
|
||||
ElMessage.error(prop.placeholder || '不能为空')
|
||||
return
|
||||
}
|
||||
emit('confirm', value.value)
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
174
admin/src/components/select-area/index.vue
Normal file
@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div class="area-component">
|
||||
<!-- 省 -->
|
||||
<el-select
|
||||
:placeholder="t('provincePlaceholder')"
|
||||
v-model="state.province"
|
||||
clearable
|
||||
@change="changeArea('province')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.provinceList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 市 -->
|
||||
<el-select
|
||||
:placeholder="t('cityPlaceholder')"
|
||||
style="margin: 0 10px;"
|
||||
:disabled="!state.province"
|
||||
v-model="state.city"
|
||||
clearable
|
||||
@change="changeArea('city')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.citiesList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 区 -->
|
||||
<el-select
|
||||
:placeholder="t('districtPlaceholder')"
|
||||
:disabled="!state.province || !state.city"
|
||||
v-model="state.area"
|
||||
clearable
|
||||
@change="changeArea('area')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.areasList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onBeforeMount, computed, watch,ref, toRaw,onMounted } from 'vue'
|
||||
import { getAreaListByPid } from '@/api/sys'
|
||||
import { t } from '@/lang'
|
||||
import { da } from 'element-plus/es/locale'
|
||||
|
||||
// 定义数据类型
|
||||
export interface areaType {
|
||||
id: string
|
||||
name: string
|
||||
pid: number
|
||||
children?: areaType[]
|
||||
}
|
||||
|
||||
const prop = defineProps({
|
||||
initData: {
|
||||
type: Object,
|
||||
default: {
|
||||
province : '',
|
||||
city : '',
|
||||
area : ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'areaChange', value: any):void
|
||||
}>()
|
||||
|
||||
const state = reactive({
|
||||
// 用于展示的省市区数据
|
||||
provinceList: [] as areaType[],
|
||||
citiesList: [] as areaType[],
|
||||
areasList: [] as areaType[],
|
||||
// 最终选择的省市区
|
||||
province: "",
|
||||
city: "",
|
||||
area: ""
|
||||
})
|
||||
|
||||
|
||||
onBeforeMount(async ()=>{
|
||||
state.provinceList = (await getAreaListByPid(0)).data
|
||||
})
|
||||
|
||||
watch( () => prop.initData.province, async (val) => {
|
||||
state['province'] = prop.initData['province']
|
||||
state['city'] = prop.initData['city']
|
||||
state['area'] = prop.initData['area']
|
||||
state.citiesList = (await getAreaListByPid(parseInt(state.province))).data
|
||||
state.areasList = (await getAreaListByPid(parseInt(state.city))).data
|
||||
emitsArea();
|
||||
})
|
||||
|
||||
watch(()=>state.area, (val)=>{
|
||||
if(val){
|
||||
emitsArea();
|
||||
}
|
||||
})
|
||||
|
||||
watch(()=>state.province, (val)=>{
|
||||
if(val){
|
||||
emitsArea();
|
||||
}
|
||||
})
|
||||
|
||||
watch(()=>state.city, (val)=>{
|
||||
if(val){
|
||||
emitsArea();
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const emitsArea = () => {
|
||||
const paramsData = {
|
||||
province: {} as areaType,
|
||||
city: {} as areaType,
|
||||
area: {} as areaType
|
||||
}
|
||||
let tmp = state.provinceList.find((item) => item.id === state.province)
|
||||
paramsData.province.name = tmp? tmp.name : ""
|
||||
paramsData.province.id = tmp? tmp.id : ""
|
||||
tmp = state.citiesList.find((item) => item.id === state.city) as any
|
||||
paramsData.city.name = tmp? tmp.name : ""
|
||||
paramsData.city.id = tmp ?tmp.id : ""
|
||||
tmp = state.areasList.find((item) => item.id === state.area) as any
|
||||
paramsData.area.name = tmp ? tmp.name : ""
|
||||
paramsData.area.id = tmp ? tmp.id : ""
|
||||
|
||||
emits('areaChange', paramsData)
|
||||
}
|
||||
|
||||
const changeArea = async (data : any) => {
|
||||
|
||||
if(data == 'province'){
|
||||
state.city = ""
|
||||
state.area = ""
|
||||
if(!state.province) {
|
||||
emitsArea();
|
||||
return false;
|
||||
}
|
||||
state.citiesList = (await getAreaListByPid(parseInt(state.province))).data
|
||||
}
|
||||
if(data == 'city'){
|
||||
state.area = ""
|
||||
if(!state.city) {
|
||||
emitsArea();
|
||||
return false;
|
||||
}
|
||||
state.areasList = (await getAreaListByPid(parseInt(state.city))).data
|
||||
}
|
||||
if(data == 'area'){
|
||||
if(!state.area) {
|
||||
emitsArea();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
75
admin/src/components/select-icon/index.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<el-popover trigger="click" v-model:visible="visible">
|
||||
<template #reference>
|
||||
<slot name="reference"></slot>
|
||||
</template>
|
||||
<div class="flex w-full flex-col">
|
||||
<div class="head flex w-full mb-[10px]">
|
||||
<span>请选择图标</span>
|
||||
<div class="flex justify-end flex-auto">
|
||||
<span class="ml-[10px] cursor-pointer" :class="{ active: type == 'element' }"
|
||||
@click="type = 'element'">element</span>
|
||||
<span class="ml-[10px] cursor-pointer" :class="{ active: type == 'iconfont' }"
|
||||
@click="type = 'iconfont'">iconfont</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon-wrap h-[240px]">
|
||||
<el-scrollbar>
|
||||
<div class="flex flex-wrap" v-show="type == 'element'">
|
||||
<el-button v-for="icon in element" class="w-[35px] h-[35px] icon-item"
|
||||
@click="selectIcon('element-' + icon)">
|
||||
<icon :name="'element-' + icon" />
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="flex flex-wrap" v-show="type == 'iconfont'">
|
||||
<el-button v-for="icon in iconfont" class="w-[35px] h-[35px] icon-item"
|
||||
@click="selectIcon('iconfont-' + icon)">
|
||||
<icon :name="'iconfont-' + icon" />
|
||||
</el-button>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
let type = ref('element')
|
||||
let visible = ref('false')
|
||||
|
||||
// element 图标
|
||||
const element = computed(() => {
|
||||
return Object.keys(ElementPlusIconsVue)
|
||||
})
|
||||
|
||||
// iconfont 图标
|
||||
const iconfont = computed(() => {
|
||||
let iconfile = import.meta.globEager('@/styles/iconfont.css')['/src/styles/iconfont.css'].default
|
||||
let icons = Array.from(iconfile.matchAll(/(icon.*)\:before/g))
|
||||
|
||||
return icons.map(item => {
|
||||
return item[1]
|
||||
})
|
||||
})
|
||||
|
||||
const emit = defineEmits(['select'])
|
||||
|
||||
// 选择图标
|
||||
const selectIcon = (name) => {
|
||||
emit('select', name)
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon-item {
|
||||
margin: 6px 6px 6px 0;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
512
admin/src/components/upload-attachment/attachment.vue
Normal file
@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<div class="flex border-t border-b main-wrap border-color w-full" :class="scene == 'select' ? 'h-[40vh]' : 'h-full'">
|
||||
<!-- 分组 -->
|
||||
<div class="group-wrap w-[180px] p-[15px] h-full border-r border-color flex flex-col">
|
||||
<el-input v-model="categoryParam.name" class="m-0" :placeholder="t('upload.attachmentCategoryPlaceholder')"
|
||||
prefix-icon="Search" @input="getAttachmentCategoryList()" />
|
||||
<div class="group-list flex-1 my-[10px]">
|
||||
<el-scrollbar>
|
||||
<div class="group-item p-[10px] leading-none text-xs rounded cursor-pointer"
|
||||
:class="{ active: attachmentParam.cate_id == 0 }" @click="attachmentParam.cate_id = 0">
|
||||
{{ t('selectPlaceholder') }}
|
||||
</div>
|
||||
<div class="group-item px-[10px] text-xs rounded cursor-pointer flex"
|
||||
v-for="(item, index) in attachmentCategory.data" :key="index"
|
||||
:class="{ active: attachmentParam.cate_id == item.id }">
|
||||
<div class="flex-1 leading-none truncate py-[10px]" @click="attachmentParam.cate_id = item.id">{{
|
||||
item.name }}
|
||||
</div>
|
||||
<div class="leading-none operate py-[10px]" v-if="scene == 'attachment'">
|
||||
<!-- 编辑分组 -->
|
||||
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')"
|
||||
@confirm="updateAttachmentCategory($event, index)" :value="item.name">
|
||||
<span class="text-primary">{{ t('edit') }}</span>
|
||||
</popover-input>
|
||||
<!-- 删除分组 -->
|
||||
<span class="text-danger ml-[5px]" @click="deleteAttachmentCategory(index)">{{ t('delete')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<!-- 添加分组 -->
|
||||
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')" @confirm="addAttachmentCategory">
|
||||
<el-button>{{ t('upload.addAttachmentCategory') }}</el-button>
|
||||
</popover-input>
|
||||
</div>
|
||||
<!-- 素材 -->
|
||||
<div class="attachment-list-wrap flex flex-col p-[15px] flex-1">
|
||||
<el-row :gutter="15" class="h-[32px]">
|
||||
<el-col :span="12">
|
||||
<el-upload v-bind="upload" ref="uploadRef">
|
||||
<el-button type="primary">{{ t('upload.upload' + type) }}</el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
<el-col :span="12" class="text-right">
|
||||
<el-input v-model="attachmentParam.real_name" class="m-0 w-[200px]"
|
||||
:placeholder="t('upload.placeholder' + type + 'Name')" prefix-icon="Search"
|
||||
@input="getAttachmentList()" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="flex-1 my-[15px] h-0" v-loading="attachment.loading">
|
||||
<el-scrollbar>
|
||||
<div class="flex flex-wrap" v-if="attachment.data.length">
|
||||
<div class="attachment-item mr-[10px]" :class="scene == 'select' ? 'w-[100px]' : 'w-[120px]'"
|
||||
v-for="(item, index) in attachment.data" :key="index">
|
||||
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center"
|
||||
:class="scene == 'select' ? 'h-[100px]' : 'h-[120px]'" @click="selectFile(item)">
|
||||
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'"></el-image>
|
||||
<video :src="img(item.url)" v-else></video>
|
||||
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60"
|
||||
v-show="selectedFile[item.att_id]">
|
||||
<icon name="element-Select" color="#fff" size="25px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ item.real_name }}</template>
|
||||
<div class="truncate my-[10px] cursor-pointer text-base flex-1 ">
|
||||
{{ item.real_name }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<!-- 图片操作 -->
|
||||
<el-dropdown :hide-on-click="false" v-if="scene == 'attachment'">
|
||||
<icon name="element-MoreFilled" class="cursor-pointer ml-[10px]" size="14px" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item class="text-center" @click="previewImage(index)"
|
||||
v-if="item.att_type == 'image'">
|
||||
<div class="text-center w-full">{{ t('lookOver') }}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item class="text-center" @click="previewVideo(index)"
|
||||
v-if="item.att_type == 'video'">
|
||||
<div class="text-center w-full">{{ t('lookOver') }}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item class="text-center" @click="moveAttachmentEvent(index)">
|
||||
<div class="text-center w-full">{{ t('upload.move') }}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="deleteAttachmentEvent(index)">
|
||||
<div class="text-center w-full">{{ t('delete') }}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center" v-else>
|
||||
<el-empty :description="t('upload.attachmentEmpty')" :image-size="100" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8" v-if="scene == 'attachment'">
|
||||
<div class="flex items-center">
|
||||
<el-checkbox v-model="selectAll" :label="t('selectAll')" size="large" />
|
||||
<el-button class="ml-[15px]" :disabled="batchOperateDisabled" @click="deleteAttachmentEvent()">{{
|
||||
t('delete') }}</el-button>
|
||||
<el-button :disabled="batchOperateDisabled" @click="moveAttachmentEvent()">{{ t('upload.move')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="scene == 'attachment' ? 16 : 24">
|
||||
<div class="flex h-full justify-end items-center">
|
||||
<el-pagination v-model:current-page="attachment.page" :small="true"
|
||||
v-model:page-size="attachment.limit" :page-sizes="[10, 20, 40, 60]"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="attachment.total"
|
||||
@size-change="getAttachmentList()" @current-change="getAttachmentList" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<template v-if="scene == 'attachment'">
|
||||
<!-- 移动附件分组 -->
|
||||
<el-dialog v-model="moveAttachmentData.visible" :title="t('upload.moveCategory')" width="350px">
|
||||
<el-form label-width="60px">
|
||||
<el-form-item :label="t('upload.moveTo')" style="margin-bottom: 0;">
|
||||
<el-select v-model="moveAttachmentData.cateId" class="input-width">
|
||||
<el-option :label="item.name" :value="item.id" v-for="(item, index) in attachmentCategory.data"
|
||||
:key="index" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="moveAttachmentData.visible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="moveAttachmentData.loading"
|
||||
@click="moveAttachmentData.confirm()">{{
|
||||
t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 图片预览 -->
|
||||
<el-image-viewer :url-list="previewImageList" v-if="imageViewer.show" @close="imageViewer.show = false"
|
||||
:initial-index="imageViewer.index" :zoom-rate="1" />
|
||||
|
||||
<!-- 视频预览 -->
|
||||
<el-dialog v-model="videoViewer.visible" width="50%" align-center :destroy-on-close="true"
|
||||
custom-class="video-preview">
|
||||
<video-player :src="videoViewer.src" width="100%" />
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch, computed, toRaw } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import {
|
||||
getAttachmentCategoryList as attachmentCategoryList,
|
||||
getAttachmentList as attachmentList,
|
||||
addAttachmentCategory as addCategory,
|
||||
updateAttachmentCategory as updateCategory,
|
||||
deleteAttachmentCategory as deleteCategory,
|
||||
deleteAttachment,
|
||||
moveAttachment
|
||||
} from '@/api/sys'
|
||||
import { debounce, img, getToken } from '@/utils/common'
|
||||
import { ElMessage, UploadFile, UploadFiles, ElMessageBox } from 'element-plus'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const prop = defineProps({
|
||||
// 选择数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
// 场景
|
||||
scene: {
|
||||
type: String,
|
||||
default: 'select' // select 选择图片 attachment 素材中心
|
||||
}
|
||||
})
|
||||
|
||||
// 选中的文件
|
||||
const selectedFile: Record<string, any> = reactive({})
|
||||
|
||||
const attachmentCategory: Record<string, any> = reactive({
|
||||
data: []
|
||||
})
|
||||
const attachment: Record<string, any> = reactive({
|
||||
loading: false,
|
||||
page: 1,
|
||||
total: 0,
|
||||
limit: prop.scene == 'select' ? 10 : 20,
|
||||
data: []
|
||||
})
|
||||
const categoryParam = reactive({
|
||||
name: ''
|
||||
})
|
||||
const attachmentParam = reactive({
|
||||
real_name: '',
|
||||
cate_id: 0
|
||||
})
|
||||
|
||||
/**
|
||||
* 查询分组
|
||||
*/
|
||||
const getAttachmentCategoryList = debounce(() => {
|
||||
attachmentCategoryList({
|
||||
type: prop.type,
|
||||
...categoryParam
|
||||
}).then(res => {
|
||||
attachmentCategory.data = res.data
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
})
|
||||
getAttachmentCategoryList()
|
||||
|
||||
/**
|
||||
* 查询图片
|
||||
*/
|
||||
const getAttachmentList = debounce((page: number = 1) => {
|
||||
attachment.loading = true
|
||||
attachment.page = page
|
||||
attachmentList({
|
||||
page: attachment.page,
|
||||
limit: attachment.limit,
|
||||
att_type: prop.type,
|
||||
...attachmentParam
|
||||
}).then(res => {
|
||||
attachment.data = res.data.data
|
||||
attachment.total = res.data.total
|
||||
attachment.loading = false
|
||||
prop.scene == 'attachment' && clearSelected()
|
||||
}).catch(() => {
|
||||
attachment.loading = false
|
||||
})
|
||||
})
|
||||
getAttachmentList()
|
||||
|
||||
watch(() => attachmentParam.cate_id, () => {
|
||||
getAttachmentList()
|
||||
})
|
||||
|
||||
/**
|
||||
* 添加分组
|
||||
*/
|
||||
const addAttachmentCategory = (name: string) => {
|
||||
addCategory({
|
||||
type: prop.type,
|
||||
name
|
||||
}).then(res => {
|
||||
getAttachmentCategoryList(1)
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑分组
|
||||
* @param name
|
||||
* @param index
|
||||
*/
|
||||
const updateAttachmentCategory = (name: string, index: number) => {
|
||||
updateCategory({
|
||||
id: attachmentCategory.data[index].id,
|
||||
name
|
||||
}).then(res => {
|
||||
attachmentCategory.data[index].name = name
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分组
|
||||
*/
|
||||
const deleteAttachmentCategory = (index: number) => {
|
||||
ElMessageBox.confirm(t('upload.deleteCategoryTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
deleteCategory(attachmentCategory.data[index].id).then(() => {
|
||||
attachmentCategory.data.splice(index, 1)
|
||||
}).catch(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const uploadRef = ref<Record<string, any> | null>(null)
|
||||
|
||||
// 上传文件
|
||||
const upload = computed(() => {
|
||||
const headers: Record<string, any> = {}
|
||||
headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
|
||||
headers[import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY] = storage.get('siteId') || 0
|
||||
|
||||
return {
|
||||
action: `${import.meta.env.VITE_APP_BASE_URL}/sys/${prop.type}`,
|
||||
multiple: true,
|
||||
data: {
|
||||
cate_id: attachmentParam.cate_id
|
||||
},
|
||||
headers,
|
||||
onSuccess: (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
if (response.code == 200) {
|
||||
getAttachmentList()
|
||||
uploadRef.value?.handleRemove(uploadFile)
|
||||
} else {
|
||||
uploadFile.status = 'fail'
|
||||
ElMessage({ message: response.msg, type: 'error' })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 全选
|
||||
const selectAll = ref(false)
|
||||
watch(selectAll, () => {
|
||||
if (selectAll.value) {
|
||||
const keys = Object.keys(toRaw(selectedFile))
|
||||
attachment.data.forEach((item: Record<string, any>) => {
|
||||
if (!keys.includes(item.att_id)) selectedFile[item.att_id] = toRaw(item)
|
||||
})
|
||||
} else {
|
||||
clearSelected()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 清空选中
|
||||
*/
|
||||
const clearSelected = () => {
|
||||
const keys = Object.keys(toRaw(selectedFile))
|
||||
if (keys.length) {
|
||||
keys.forEach((key) => { delete selectedFile[key] })
|
||||
selectAll.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择文件
|
||||
*/
|
||||
const selectFile = (data: any) => {
|
||||
if (selectedFile[data.att_id]) delete selectedFile[data.att_id]
|
||||
else if (prop.scene == 'select') {
|
||||
const keys = Object.keys(toRaw(selectedFile))
|
||||
const length = keys.length
|
||||
if (prop.limit == 1 && length == prop.limit) {
|
||||
delete selectedFile[keys[0]]
|
||||
} else if (length >= prop.limit) {
|
||||
ElMessage.info(t('upload.triggerUpperLimit'))
|
||||
return
|
||||
}
|
||||
selectedFile[data.att_id] = toRaw(data)
|
||||
} else {
|
||||
selectedFile[data.att_id] = toRaw(data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除附件
|
||||
* @param index
|
||||
*/
|
||||
const deleteAttachmentEvent = (index: number | null = null) => {
|
||||
const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.data[index].att_id]
|
||||
|
||||
ElMessageBox.confirm(t('upload.deleteAttachmentTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
deleteAttachment({ att_ids: ids }).then(() => {
|
||||
getAttachmentList()
|
||||
}).catch(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动附件
|
||||
*/
|
||||
const moveAttachmentData: Record<string, any> = reactive({
|
||||
cateId: '',
|
||||
loading: false,
|
||||
visible: false
|
||||
})
|
||||
const moveAttachmentEvent = (index: number | null = null) => {
|
||||
const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.data[index].att_id]
|
||||
moveAttachmentData.visible = true
|
||||
moveAttachmentData.cateId = attachmentCategory.data[0].id
|
||||
|
||||
moveAttachmentData.confirm = () => {
|
||||
moveAttachmentData.loading = true
|
||||
moveAttachment({ cate_id: moveAttachmentData.cateId, att_ids: ids }).then(() => {
|
||||
moveAttachmentData.visible = false
|
||||
moveAttachmentData.loading = false
|
||||
getAttachmentList()
|
||||
}).catch(() => {
|
||||
moveAttachmentData.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 批量操作是否可操作
|
||||
const batchOperateDisabled = ref(true)
|
||||
watch(selectedFile, () => {
|
||||
batchOperateDisabled.value = Object.keys(toRaw(selectedFile)).length == 0
|
||||
})
|
||||
|
||||
/**
|
||||
* 查看图片
|
||||
*/
|
||||
const imageViewer = reactive({
|
||||
show: false,
|
||||
index: 0
|
||||
})
|
||||
const previewImage = (index: number) => {
|
||||
imageViewer.show = true
|
||||
imageViewer.index = index
|
||||
}
|
||||
const previewImageList = computed(() => {
|
||||
return toRaw(attachment.data).map((item: Record<string, any>) => { return img(item.url) })
|
||||
})
|
||||
|
||||
/**
|
||||
* 视频预览
|
||||
*/
|
||||
const videoViewer = reactive({
|
||||
visible: false,
|
||||
src: ''
|
||||
})
|
||||
const previewVideo = (index: number) => {
|
||||
videoViewer.visible = true
|
||||
videoViewer.src = img(attachment.data[index].url)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
selectedFile
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.group-list {
|
||||
.group-item {
|
||||
margin-top: 3px;
|
||||
|
||||
.operate {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
|
||||
.operate {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-list-wrap {
|
||||
.attachment-wrap {
|
||||
background: var(--el-border-color-extra-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.video-preview {
|
||||
background: none !important;
|
||||
box-shadow: none !important;
|
||||
|
||||
.el-dialog__headerbtn .el-dialog__close {
|
||||
border-radius: 50%;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background-color: var(--el-text-color-regular);
|
||||
border-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-list {
|
||||
position: absolute !important;
|
||||
z-index: 10;
|
||||
|
||||
.el-upload-list__item {
|
||||
background: #fff !important;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
75
admin/src/components/upload-attachment/index.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<span @click="openDialog" class="cursor-pointer">
|
||||
<slot></slot>
|
||||
</span>
|
||||
<el-dialog v-model="showDialog" :title="t('upload.select' + type)" width="60%" class="attachment-dialog"
|
||||
:destroy-on-close="true">
|
||||
|
||||
<attachment :limit="limit" :type="type" ref="attachmentRef" />
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import attachment from './attachment.vue'
|
||||
|
||||
const prop = defineProps({
|
||||
// 选择数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
}
|
||||
})
|
||||
|
||||
const showDialog = ref(false)
|
||||
const attachmentRef: Record<string, any> | null = ref(null)
|
||||
|
||||
const openDialog = () => {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
/**
|
||||
* 确认选择
|
||||
*/
|
||||
const confirm = () => {
|
||||
showDialog.value = false
|
||||
const files = Object.values(attachmentRef?.value.selectedFile)
|
||||
emit('confirm', prop.limit == 1 ? files[0] ?? null : files)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.attachment-dialog {
|
||||
.el-dialog__body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.el-upload-list {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.el-upload-list__item {
|
||||
background: var(--el-dialog-bg-color);
|
||||
box-shadow: var(--el-dialog-box-shadow);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
admin/src/components/upload-file/index.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<el-upload v-bind="upload" class="w-full upload-file">
|
||||
<slot>
|
||||
<el-input v-model="value" class="w-full" :readonly="true">
|
||||
<template #append>{{ t('upload.root') }}</template>
|
||||
</el-input>
|
||||
</slot>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getToken } from '@/utils/common'
|
||||
import { UploadFile, ElMessage } from 'element-plus'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
api: {
|
||||
type: String,
|
||||
default: 'sys/document'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value = computed({
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const upload: Record<string, any> = {
|
||||
action: `${import.meta.env.VITE_APP_BASE_URL}/${prop.api}`,
|
||||
showFileList: false,
|
||||
headers: {},
|
||||
accept: '.doc,.docx,.xml,.txt,.pem,.zip,.rar,.7z',
|
||||
onSuccess: (response: any, uploadFile: UploadFile) => {
|
||||
value.value = response.data.url
|
||||
ElMessage({
|
||||
message: t('upload.success'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
upload.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
|
||||
upload.headers[import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY] = storage.get('siteId') || 0
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.upload-file .el-upload {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
167
admin/src/components/upload-image/index.vue
Normal file
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap">
|
||||
<template v-if="limit == 1">
|
||||
<div class="rounded cursor-pointer overflow-hidden relative border border-dashed border-color image-wrap mr-[10px]"
|
||||
:style="style">
|
||||
<div class="w-full h-full relative" v-if="images.data.length">
|
||||
<div class="w-full h-full flex items-center justify-center">
|
||||
<el-image :src="img(images.data[0])" fit="contain"></el-image>
|
||||
</div>
|
||||
<div
|
||||
class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60 operation">
|
||||
<icon name="element-ZoomIn" color="#fff" size="18px" class="mr-[10px]" @click="previewImage()" />
|
||||
<icon name="element-Delete" color="#fff" size="18px" @click="removeImage" />
|
||||
</div>
|
||||
</div>
|
||||
<upload-attachment :limit="limit" @confirm="confirmSelect" v-else>
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<icon name="element-Plus" size="20px" color="var(--el-text-color-secondary)" />
|
||||
<div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || t('upload.root') }}</div>
|
||||
</div>
|
||||
</upload-attachment>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="rounded cursor-pointer overflow-hidden relative border border-dashed border-color image-wrap mr-[10px]"
|
||||
:style="style" v-for="(item, index) in images.data" :key="index">
|
||||
<div class="w-full h-full relative">
|
||||
<div class="w-full h-full flex items-center justify-center">
|
||||
<el-image :src="img(item)" fit="contain"></el-image>
|
||||
</div>
|
||||
<div
|
||||
class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60 operation">
|
||||
<icon name="element-ZoomIn" color="#fff" size="18px" class="mr-[10px]"
|
||||
@click="previewImage(index)" />
|
||||
<icon name="element-Delete" color="#fff" size="18px" @click="removeImage(index)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded cursor-pointer overflow-hidden relative border border-dashed border-color" :style="style"
|
||||
v-if="images.data.length < limit">
|
||||
<upload-attachment :limit="limit" @confirm="confirmSelect">
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<icon name="element-Plus" size="20px" color="var(--el-text-color-secondary)" />
|
||||
<div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || t('upload.root') }}</div>
|
||||
</div>
|
||||
</upload-attachment>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<el-image-viewer :url-list="previewImageList" v-if="imageViewer.show" @close="imageViewer.show = false"
|
||||
:initial-index="imageViewer.index" :zoom-rate="1" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, watch, toRaw } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100px'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '100px'
|
||||
},
|
||||
imageText: {
|
||||
type: String
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value = computed({
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const images: Record<string, any> = reactive({
|
||||
data: []
|
||||
})
|
||||
|
||||
let previewImageList: string[] = reactive([])
|
||||
|
||||
const setValue = () => {
|
||||
value.value = toRaw(images.data).toString()
|
||||
previewImageList = toRaw(images.data).map((url: string) => { return img(url) })
|
||||
}
|
||||
|
||||
watch(() => value.value, () => {
|
||||
images.data = [
|
||||
...value.value.split(',').filter((item: string) => { return item })
|
||||
]
|
||||
setValue()
|
||||
}, { immediate: true })
|
||||
|
||||
const style = computed(() => {
|
||||
return {
|
||||
width: prop.width,
|
||||
height: prop.height
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 选择图片
|
||||
*/
|
||||
const confirmSelect = (data: Record<string, any>) => {
|
||||
if (prop.limit == 1) {
|
||||
images.data.splice(0, 1)
|
||||
data && images.data.push(data.url)
|
||||
} else {
|
||||
data.forEach((item: any) => {
|
||||
if (images.data.length < prop.limit) images.data.push(item.url)
|
||||
})
|
||||
}
|
||||
setValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
* @param index
|
||||
*/
|
||||
const removeImage = (index: number = 0) => {
|
||||
images.data.splice(index, 1)
|
||||
setValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看图片
|
||||
*/
|
||||
const imageViewer = reactive({
|
||||
show: false,
|
||||
index: 0
|
||||
})
|
||||
const previewImage = (index: number = 0) => {
|
||||
imageViewer.show = true
|
||||
imageViewer.index = index
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.image-wrap {
|
||||
.operation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.operation {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
163
admin/src/components/upload-video/index.vue
Normal file
@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap">
|
||||
<template v-if="limit == 1">
|
||||
<div class="rounded cursor-pointer relative bg-page video-wrap mr-[10px]" :style="style">
|
||||
<template v-if="videos.data.length">
|
||||
<div class="w-full h-full relative flex items-center overflow-hidden rounded">
|
||||
<video :src="img(videos.data[0])" class="w-full" />
|
||||
<div
|
||||
class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60 operation">
|
||||
<icon name="iconfont-icon24gf-playCircle" color="#fff" size="25px" @click="previewVideo()" />
|
||||
</div>
|
||||
</div>
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="18px" @click="removeVideo"
|
||||
class="absolute z-[2] top-[-9px] right-[-9px]" />
|
||||
</template>
|
||||
<upload-attachment :limit="limit" type="video" @confirm="confirmSelect" v-else>
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)" />
|
||||
</div>
|
||||
</upload-attachment>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="rounded cursor-pointer relative bg-page video-wrap mr-[10px]" :style="style"
|
||||
v-for="(item, index) in videos.data" :key="index">
|
||||
<div class="w-full h-full relative flex items-center overflow-hidden rounded">
|
||||
<video :src="img(item)" class="w-full" />
|
||||
<div
|
||||
class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60 operation">
|
||||
<icon name="iconfont-icon24gf-playCircle" color="#fff" size="25px" @click="previewVideo(index)" />
|
||||
</div>
|
||||
</div>
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="18px" @click="removeVideo(index)"
|
||||
class="absolute z-[2] top-[-9px] right-[-9px]" />
|
||||
</div>
|
||||
<div class="rounded cursor-pointer relative bg-page video-wrap mr-[10px]" :style="style"
|
||||
v-if="videos.data.length < limit">
|
||||
<upload-attachment :limit="limit" type="video" @confirm="confirmSelect">
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)" />
|
||||
</div>
|
||||
</upload-attachment>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 视频预览 -->
|
||||
<el-dialog v-model="videoViewer.visible" width="50%" align-center :destroy-on-close="true"
|
||||
custom-class="video-preview">
|
||||
<video-player :src="videoViewer.src" width="100%" />
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, watch, toRaw } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '200px'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '100px'
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value = computed({
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const videos: Record<string, any> = reactive({
|
||||
data: []
|
||||
})
|
||||
|
||||
watch(() => value.value, () => {
|
||||
videos.data = [
|
||||
...value.value.split(',').filter((item: string) => { return item })
|
||||
]
|
||||
setValue()
|
||||
})
|
||||
|
||||
const style = computed(() => {
|
||||
return {
|
||||
width: prop.width,
|
||||
height: prop.height
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 选择视频
|
||||
*/
|
||||
const confirmSelect = (data: Record<string, any>) => {
|
||||
if (prop.limit == 1) {
|
||||
videos.data.splice(0, 1)
|
||||
data && videos.data.push(data.url)
|
||||
} else {
|
||||
data.forEach((item: any) => {
|
||||
if (videos.data.length < prop.limit) videos.data.push(item.url)
|
||||
})
|
||||
}
|
||||
setValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视频
|
||||
* @param index
|
||||
*/
|
||||
const removeVideo = (index: number = 0) => {
|
||||
videos.data.splice(index, 1)
|
||||
setValue()
|
||||
}
|
||||
|
||||
const setValue = () => {
|
||||
value.value = toRaw(videos.data).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看视频
|
||||
*/
|
||||
const videoViewer = reactive({
|
||||
visible: false,
|
||||
src: ''
|
||||
})
|
||||
const previewVideo = (index: number = 0) => {
|
||||
videoViewer.visible = true
|
||||
videoViewer.src = img(videos.data[index])
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.video-preview {
|
||||
background: none !important;
|
||||
box-shadow: none !important;
|
||||
|
||||
.el-dialog__headerbtn .el-dialog__close {
|
||||
border-radius: 50%;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background-color: var(--el-text-color-regular);
|
||||
border-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
10
admin/src/components/video-player/index.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<video-play />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import 'vue3-video-play/dist/style.css'
|
||||
import videoPlay from 'vue3-video-play'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
3
admin/src/lang/en/403.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"tips": "Your account permissions are insufficient. Please contact the administrator to add permissions!"
|
||||
}
|
||||
21
admin/src/lang/en/auth.menu.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"menuName": "Menu name",
|
||||
"menuType": "Type",
|
||||
"authId": "Permission ID",
|
||||
"menuTypeDir": "Dir",
|
||||
"menuTypeMenu": "Menu",
|
||||
"menuTypeButton": "Button",
|
||||
"menuDeleteTips": "Are you sure you want to delete this menu?",
|
||||
"addMenu": "Add menu",
|
||||
"updateMenu": "Update menu",
|
||||
"routePath": "Route path",
|
||||
"viewPath": "Component path",
|
||||
"parentMenu": "Parent menu",
|
||||
"menuIcon": "Menu Icon",
|
||||
"menuNamePlaceholder": "Please enter a menu name",
|
||||
"routePathPlaceholder": "Please enter routing path",
|
||||
"viewPathPlaceholder": "Please enter the component path",
|
||||
"authIdPlaceholder": "Please enter Permission id",
|
||||
"selectIconPlaceholder": "Please select the menu icon",
|
||||
"topLevel": "top-level"
|
||||
}
|
||||
38
admin/src/lang/en/common.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"createTime": "Create Time",
|
||||
"sort": "Sort",
|
||||
"status": "Status",
|
||||
"operation": "Operation",
|
||||
"statusNormal": "Normal",
|
||||
"statusDeactivate": "Deactivate",
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"warning": "Warning",
|
||||
"isShow": "Show or not",
|
||||
"show": "show",
|
||||
"hidden": "hidden",
|
||||
"icon": "Icon",
|
||||
"layout": {
|
||||
"layoutSetting": "Layout configuration",
|
||||
"darkMode": "Dark mode",
|
||||
"themeColor": "Theme color"
|
||||
},
|
||||
"axios": {
|
||||
"unknownError": "Unknown Error",
|
||||
"400": "Wrong request ",
|
||||
"401": "Please login again",
|
||||
"403": "Access denied",
|
||||
"404": "Request error, the resource was not found",
|
||||
"405": "Request method not allowed",
|
||||
"408": "Request timeout",
|
||||
"500": "Server side error",
|
||||
"501": "Network not implemented",
|
||||
"502": "Network error",
|
||||
"503": "Service unavailable",
|
||||
"504": "Network Timeout",
|
||||
"505": "The http version does not support the request",
|
||||
"timeout": "Network request timeout!"
|
||||
}
|
||||
}
|
||||
25
admin/src/lang/en/index.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"todayData": "today's data",
|
||||
"memberNumb": "number of member",
|
||||
"numberOfSites": "number of sites",
|
||||
"numberOfVisitors": "number of visitors",
|
||||
"commonlyUsedFunction": "commonly used function",
|
||||
"articleList": "article list",
|
||||
"memberManagement": "member management",
|
||||
"balanceAccount": "balance account",
|
||||
"administrator": "administrator",
|
||||
"WebDecoration": "website decoration",
|
||||
"accessMessage": "access message",
|
||||
"memberDistribution": "membership distribution",
|
||||
"systemInfo": "system environment",
|
||||
"os": "os",
|
||||
"phpVersions": "php version number",
|
||||
"productionEnvironment": "production environment",
|
||||
"versionsInfo": "version information",
|
||||
"versions": "current version",
|
||||
"frame": "framework based",
|
||||
"channel": "access channel",
|
||||
"serviceSupport": "service support",
|
||||
"officialWbsite": "official website",
|
||||
"pageView": "page view"
|
||||
}
|
||||
7
admin/src/lang/en/login.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Niushop Vite Management side",
|
||||
"login": "Login",
|
||||
"logging": "Logging",
|
||||
"userPlaceholder": "Please enter your account number",
|
||||
"passwordPlaceholder": "Please enter your password"
|
||||
}
|
||||
26
admin/src/lang/en/member.member.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"channel":"logon mode",
|
||||
"nickname":"Name of member",
|
||||
"mobile":"mobile",
|
||||
"createTime":"creation time",
|
||||
"updateTime":"Update time",
|
||||
"addMember":"add member",
|
||||
"updateMember":"edit member",
|
||||
"nickNamePlaceholder":"Please enter the member name",
|
||||
"mobilePlaceholder":"Please enter your mobile phone number",
|
||||
"channelPlaceholder":"Please select a registration type",
|
||||
"memberDeleteTips" : "Are you sure you want to delete this member?",
|
||||
"detail": "detail",
|
||||
"edit": "edit",
|
||||
"startDate": "start time",
|
||||
"endDate": "end time",
|
||||
"essentialInfo": "essential information",
|
||||
"accountInfo": "account information",
|
||||
"registeredSource": "registered source",
|
||||
"memberLabel": "Member label",
|
||||
"urserName": "user name",
|
||||
"point": "point",
|
||||
"balance": "balance",
|
||||
"growth": "growth"
|
||||
|
||||
}
|
||||
14
admin/src/lang/en/user.center.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"headImg": "head",
|
||||
"realName": "name",
|
||||
"originalPassword": "original password",
|
||||
"password": "new password",
|
||||
"passwordCopy": "confirm password",
|
||||
"passwordTip": "This parameter is mandatory when changing the password. Leave a blank if you do not change the password",
|
||||
"realNamePlaceholder": "Please enter the user name",
|
||||
"headImgPlaceholder": "Please enter the user profile picture",
|
||||
"originalPasswordPlaceholder": "Please enter the original password",
|
||||
"passwordPlaceholder": "Please enter a new password",
|
||||
"save": "save",
|
||||
"cancel": "cancel"
|
||||
}
|
||||
21
admin/src/lang/i18n.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { createI18n } from "vue-i18n"
|
||||
|
||||
import Language from "./language"
|
||||
import zhCn from "./zh-cn/common.json";
|
||||
import en from "./en/common.json"
|
||||
|
||||
//创建实例
|
||||
let i18n = createI18n({
|
||||
datetimeFormats: {},
|
||||
numberFormats: {},
|
||||
globalInjection: true, //是否全局注入
|
||||
messages: {
|
||||
"zh-cn": zhCn,
|
||||
en
|
||||
}
|
||||
});
|
||||
|
||||
const language = new Language(i18n);
|
||||
|
||||
export { language };
|
||||
export default i18n;
|
||||
20
admin/src/lang/index.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import i18n, { language } from "./i18n"
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const t = (message: string) => {
|
||||
const path = useAppStore().route
|
||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
||||
const key = `${file}.${message}`
|
||||
return i18n.global.t(key) != key ? i18n.global.t(key) : i18n.global.t(message)
|
||||
}
|
||||
|
||||
export { language, t }
|
||||
|
||||
export default {
|
||||
install(app: any) {
|
||||
//注册i18n
|
||||
app.use(i18n);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
58
admin/src/lang/language.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
class Language {
|
||||
private i18n: any;
|
||||
private loadLocale: Array<string> = []; //已加载的语言
|
||||
|
||||
constructor(i18n: any) {
|
||||
this.i18n = i18n
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param locale 设置语言
|
||||
*/
|
||||
public setI18nLanguage(locale: string) {
|
||||
if (this.i18n.mode === 'legacy') {
|
||||
this.i18n.global.locale = locale
|
||||
} else {
|
||||
this.i18n.global.locale = locale
|
||||
}
|
||||
let html = document.querySelector('html')
|
||||
html && html.setAttribute('lang', locale)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载语言包
|
||||
* @param path
|
||||
* @param locale
|
||||
* @returns
|
||||
*/
|
||||
public async loadLocaleMessages(path: string, locale: string) {
|
||||
try {
|
||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
||||
|
||||
if (this.loadLocale.includes(`${locale}/${file}`)) {
|
||||
return nextTick()
|
||||
}
|
||||
this.loadLocale.push(`${locale}/${file}`)
|
||||
|
||||
// 引入语言包文件
|
||||
const messages = await import(`./${locale}/${file}.json`)
|
||||
|
||||
let data: Record<string, string> = {}
|
||||
Object.keys(messages.default).forEach(key => {
|
||||
data[`${file}.${key}`] = messages.default[key]
|
||||
})
|
||||
|
||||
this.i18n.global.mergeLocaleMessage(locale, data)
|
||||
this.setI18nLanguage(locale)
|
||||
return nextTick()
|
||||
} catch {
|
||||
this.setI18nLanguage(locale)
|
||||
return nextTick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Language
|
||||
3
admin/src/lang/zh-cn/403.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"tips": "您的账号权限不足,请联系管理员添加权限!"
|
||||
}
|
||||
18
admin/src/lang/zh-cn/article.category.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"siteId":"站点ID",
|
||||
"name":"栏目名称",
|
||||
"sort":"排序",
|
||||
"isShow":"是否显示",
|
||||
"siteIdPlaceholder":"请输入站点ID",
|
||||
"namePlaceholder":"请输入栏目名称",
|
||||
"sortPlaceholder":"请输入排序",
|
||||
"isShowPlaceholder":"是否显示",
|
||||
"addArticleCategory":"添加栏目",
|
||||
"updateArticleCategory":"编辑栏目",
|
||||
"articleCategoryDeleteTips" : "确定要删除该栏目吗?",
|
||||
"nameMax":"名称不能超过20个字符",
|
||||
"sortNumber":"排序号必须是数字",
|
||||
"sortBetween":"排序号不能超过10000",
|
||||
"show":"显示",
|
||||
"hide":"不显示"
|
||||
}
|
||||
35
admin/src/lang/zh-cn/article.edit.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"categoryName":"文章栏目",
|
||||
"title":"文章标题",
|
||||
"intro":"简介",
|
||||
"summary":"文章摘要",
|
||||
"image":"文章图片",
|
||||
"author":"作者",
|
||||
"content":"文章内容",
|
||||
"visit":"实际浏览量",
|
||||
"visitVirtual":"虚拟浏览量",
|
||||
"isShow":"是否显示",
|
||||
"sort":"排序",
|
||||
"categoryIdPlaceholder":"请选择文章栏目",
|
||||
"titlePlaceholder":"请输入文章标题",
|
||||
"introPlaceholder":"请输入简介",
|
||||
"summaryPlaceholder":"请输入文章摘要",
|
||||
"imagePlaceholder":"请上传文章图片",
|
||||
"authorPlaceholder":"请输入作者",
|
||||
"contentPlaceholder":"请输入文章内容",
|
||||
"visitPlaceholder":"请输入实际浏览量",
|
||||
"visitVirtualPlaceholder":"请输入虚拟浏览量",
|
||||
"isShowPlaceholder":"是否显示",
|
||||
"sortPlaceholder":"请输入排序",
|
||||
"addArticle":"添加文章",
|
||||
"updateArticle":"编辑文章",
|
||||
"titleMax":"文章标题不能超过20个字符",
|
||||
"introMax":"文章简介不能超过50个字符",
|
||||
"summaryMax":"文章摘要不能超过50个字符",
|
||||
"imageMax":"图片路径太长",
|
||||
"authorMax":"文章作者不能超过20个字符",
|
||||
"isShowNumber":"是否显示必须是数字",
|
||||
"isShowBetween":"是否显示只能是0或者1",
|
||||
"sortNumber":"排序号必须是数字",
|
||||
"sortBetween":"排序号需要在0-10000之间"
|
||||
}
|
||||
20
admin/src/lang/zh-cn/article.list.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"categoryName":"栏目",
|
||||
"title":"标题",
|
||||
"intro":"简介",
|
||||
"summary":"摘要",
|
||||
"image":"封面",
|
||||
"author":"作者",
|
||||
"content":"文章内容",
|
||||
"visit":"实际浏览量",
|
||||
"visitVirtual":"虚拟浏览量",
|
||||
"isShow":"是否显示",
|
||||
"sort":"排序",
|
||||
"createTime":"创建时间",
|
||||
"updateTime":"更新时间",
|
||||
"addArticle":"添加文章",
|
||||
"updateArticle":"编辑文章",
|
||||
"titlePlaceholder":"请输入文章标题",
|
||||
"categoryIdPlaceholder":"请选择文章栏目",
|
||||
"articleDeleteTips" : "确定要删除该文章吗?"
|
||||
}
|
||||
19
admin/src/lang/zh-cn/auth.log.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"ip":"登录IP",
|
||||
"username":"管理员姓名",
|
||||
"url":"链接",
|
||||
"detail": "详情",
|
||||
"params":"参数",
|
||||
"type":"请求方式",
|
||||
"createTime":"操作时间",
|
||||
"ipPlaceholder":"请输入登录IP",
|
||||
"uidPlaceholder":"请输入管理员id",
|
||||
"usernamePlaceholder":"请输入管理员姓名",
|
||||
"urlPlaceholder":"请输入链接",
|
||||
"paramsPlaceholder":"请输入参数",
|
||||
"typePlaceholder":"请输入请求方式",
|
||||
"createTimePlaceholder":"请输入操作时间",
|
||||
"addSysUserLog":"添加管理员操作记录表",
|
||||
"updateSysUserLog":"编辑管理员操作记录表",
|
||||
"sys_user_logDeleteTips":"确定要删除该管理员操作记录表吗?"
|
||||
}
|
||||
25
admin/src/lang/zh-cn/auth.menu.admin.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"menuName": "菜单名称",
|
||||
"menuType": "类型",
|
||||
"authId": "权限标识",
|
||||
"menuTypeDir": "目录",
|
||||
"menuTypeMenu": "菜单",
|
||||
"menuTypeButton": "按钮",
|
||||
"menuDeleteTips": "确定要删除该菜单吗?",
|
||||
"addMenu": "添加菜单",
|
||||
"updateMenu": "编辑菜单",
|
||||
"routePath": "路由路径",
|
||||
"viewPath": "组件路径",
|
||||
"parentMenu": "父级菜单",
|
||||
"menuIcon": "菜单图标",
|
||||
"sort":"权重",
|
||||
"menuKey":"菜单标识",
|
||||
"menuNamePlaceholder": "请输入菜单名称",
|
||||
"menuKeyPlaceholder": "请输入菜单标识",
|
||||
"menuKeyValidata":"菜单标识只能使用字母数字下划线并且开头不能为数字",
|
||||
"routePathPlaceholder": "请输入路由路径",
|
||||
"viewPathPlaceholder": "请输入组件路径",
|
||||
"authIdPlaceholder": "请输入权限标识",
|
||||
"selectIconPlaceholder": "请选择菜单图标",
|
||||
"topLevel": "顶级"
|
||||
}
|
||||
25
admin/src/lang/zh-cn/auth.menu.site.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"menuName": "菜单名称",
|
||||
"menuType": "类型",
|
||||
"authId": "权限标识",
|
||||
"menuTypeDir": "目录",
|
||||
"menuTypeMenu": "菜单",
|
||||
"menuTypeButton": "按钮",
|
||||
"menuDeleteTips": "确定要删除该菜单吗?",
|
||||
"addMenu": "添加菜单",
|
||||
"updateMenu": "编辑菜单",
|
||||
"routePath": "路由路径",
|
||||
"viewPath": "组件路径",
|
||||
"parentMenu": "父级菜单",
|
||||
"menuIcon": "菜单图标",
|
||||
"sort":"权重",
|
||||
"menuKey":"菜单标识",
|
||||
"menuNamePlaceholder": "请输入菜单名称",
|
||||
"menuKeyPlaceholder": "请输入菜单标识",
|
||||
"menuKeyValidata":"菜单标识只能使用字母数字下划线并且开头不能为数字",
|
||||
"routePathPlaceholder": "请输入路由路径",
|
||||
"viewPathPlaceholder": "请输入组件路径",
|
||||
"authIdPlaceholder": "请输入权限标识",
|
||||
"selectIconPlaceholder": "请选择菜单图标",
|
||||
"topLevel": "顶级"
|
||||
}
|
||||
10
admin/src/lang/zh-cn/auth.role.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"addRole": "新增角色",
|
||||
"updateRole": "编辑角色",
|
||||
"roleName": "角色名称",
|
||||
"roleDeleteTips": "确定要删除该角色吗?",
|
||||
"roleNamePlaceholder": "请输入角色名称",
|
||||
"rulesPlaceholder": "请选择权限",
|
||||
"checkStrictly": "父子级不关联",
|
||||
"permission": "权限"
|
||||
}
|
||||
20
admin/src/lang/zh-cn/auth.user.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"addUser": "新增管理员",
|
||||
"updateUser": "编辑管理员",
|
||||
"userRealName": "姓名",
|
||||
"lastLoginTime": "最后登录时间",
|
||||
"lastLoginIP": "最后登录IP",
|
||||
"accountNumberPlaceholder": "请输入账号",
|
||||
"passwordPlaceholder": "请输入密码",
|
||||
"confirmPasswordPlaceholder": "请再次确认密码",
|
||||
"userRealNamePlaceholder": "请输入姓名",
|
||||
"confirmPasswordError": "两次输入的密码不一致",
|
||||
"userRoleName": "角色",
|
||||
"administrator":"超级管理员",
|
||||
"userRolePlaceholder": "请选择角色",
|
||||
"lock":"锁定",
|
||||
"unlock":"解锁",
|
||||
"status":"用户状态",
|
||||
"userUnlockTips":"确定要解锁该管理员吗?",
|
||||
"userLockTips":"确定要锁定该管理员吗?"
|
||||
}
|
||||
34
admin/src/lang/zh-cn/channel.aliapp.config.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"aliappSet": "小程序设置",
|
||||
"aliappName": "小程序名称",
|
||||
"aliappOriginal": "APPID",
|
||||
"aliappQrcode": "小程序二维码",
|
||||
"aliappQrcodeTips": "建议尺寸上传430px*430px宽高的二维码",
|
||||
"aliappAppid": "应用私钥",
|
||||
"aliappAppsecret": "开发者密码",
|
||||
"downloadUrl": "downloadFile合法域名",
|
||||
"aliappInfo": "小程序信息",
|
||||
"aliappDevelopInfo": "开发设置",
|
||||
"theServerSetting": "接口内容加密设置",
|
||||
"functionSetting": "服务器配置信息",
|
||||
"encryptionType": "消息加解密方式",
|
||||
"compatibleMode": "兼容模式",
|
||||
"safeMode": "安全模式(推荐)",
|
||||
"aliappNamePlaceholder": "请输入小程序名称",
|
||||
"aliappOriginalPlaceholder": "请输入APPID",
|
||||
"appidPlaceholder": "请输入应用私钥",
|
||||
"tokenPlaceholder": "请输入Token",
|
||||
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
|
||||
"countersignType": "接口加签方式",
|
||||
"certificate": "证书",
|
||||
"publicKey": "应用公钥证书",
|
||||
"alipayPublicKey": "支付宝公钥证书",
|
||||
"alipayWithCrt": "支付宝根证书",
|
||||
"publicKeyTips": "上传appCertPublicKey_***.crt文件",
|
||||
"alipayPublicKeyTips": "上传alipayCertPublicKey_RSA2.crt文件",
|
||||
"alipayWithCrtTips": "上传alipayRootCert.crt文件",
|
||||
"AESKey": "AES秘钥",
|
||||
"serveWhiteList": "服务器域名白名单",
|
||||
"AESKeyPlaceholder": "请输入AES秘钥"
|
||||
|
||||
}
|
||||
6
admin/src/lang/zh-cn/channel.h5.config.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"isOpen": "是否开启",
|
||||
"h5DomainName": "h5域名",
|
||||
"H5Info": "h5配置信息"
|
||||
|
||||
}
|
||||
4
admin/src/lang/zh-cn/channel.pc.config.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"pcInfo": "电脑端信息",
|
||||
"preview": "预览图"
|
||||
}
|
||||
34
admin/src/lang/zh-cn/channel.weapp.config.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"weappName": "小程序名称",
|
||||
"weappOriginal": "小程序原始ID",
|
||||
"weappQrcode": "小程序二维码",
|
||||
"weappQrcodeTips": "建议尺寸上传430px*430px宽高的二维码",
|
||||
"weappAppid": "开发者ID",
|
||||
"weappAppidTips": "开发者ID是小程序开发识别码,配合开发者密码可调用小程序的接口能力。",
|
||||
"weappAppsecret": "开发者密码",
|
||||
"weappAppsecretTips": "开发者密码是校验小程序开发者身份的密码,具有极高的安全性",
|
||||
"businessDomain": "业务域名",
|
||||
"requestUrl": "request合法域名",
|
||||
"socketUrl": "socket合法域名",
|
||||
"uploadUrl": "uploadFile合法域名",
|
||||
"downloadUrl": "downloadFile合法域名",
|
||||
"weappInfo": "小程序信息",
|
||||
"weappDevelopInfo": "小程序开发信息",
|
||||
"theServerSetting": "消息推送配置",
|
||||
"functionSetting": "服务器域名设置",
|
||||
"tokenTips": "必须为英文或数字,长度为3-32字符。",
|
||||
"encodingAESKeyTips": "消息加密密钥由43位字符组成,可随机修改,字符范围为A-Z,a-z,0-9。",
|
||||
"encryptionType": "消息加解密方式",
|
||||
"cleartextMode": "明文模式",
|
||||
"compatibleMode": "兼容模式",
|
||||
"safeMode": "安全模式(推荐)",
|
||||
"weappNamePlaceholder": "请输入小程序名称",
|
||||
"weappOriginalPlaceholder": "请输入小程序原始ID",
|
||||
"appidPlaceholder": "请输入开发者ID",
|
||||
"appSecretPlaceholder": "请输入开发者密码",
|
||||
"tokenPlaceholder": "请输入Token",
|
||||
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
|
||||
"cleartextModeTips": "明文模式下,不使用消息体加解密功能,安全系数较低",
|
||||
"compatibleModeTips": "兼容模式下,明文、密文将共存,方便开发者调试和维护",
|
||||
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高"
|
||||
}
|
||||
19
admin/src/lang/zh-cn/channel.weapp.message.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "类型",
|
||||
"response": "回复内容",
|
||||
"isStart": "是否启用",
|
||||
"serialNumber": "编号",
|
||||
"operation": "操作",
|
||||
"operationTip": "温馨提示",
|
||||
"operationTipOne": "请在小程序的服务类目中添加类目:一级类目:商业服务 二级类目:软件/建站/技术开发",
|
||||
"operationTipTwo": "小程序最多支持50个消息模板获取时请注意小程序剩余模板数量是否充足",
|
||||
"buyerNews": "买家消息",
|
||||
"sellerMessage": "卖家消息",
|
||||
"started": "启用",
|
||||
"closed": "禁用",
|
||||
"close": "关闭",
|
||||
"open": "开启",
|
||||
"regain": "重新获取",
|
||||
"batchAcquisition": "一键获取"
|
||||
|
||||
}
|
||||
33
admin/src/lang/zh-cn/channel.wechat.config.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"wechatName": "公众号名称",
|
||||
"wechatOriginal": "公众号原始ID",
|
||||
"wechatQrcode": "公众号二维码",
|
||||
"wechatQrcodeTips": "建议尺寸上传430px*430px宽高的二维码",
|
||||
"wechatAppid": "开发者ID",
|
||||
"wechatAppidTips": "开发者ID是公众号开发识别码,配合开发者密码可调用公众号的接口能力。",
|
||||
"wechatAppsecret": "开发者密码",
|
||||
"wechatAppsecretTips": "开发者密码是校验公众号开发者身份的密码,具有极高的安全性",
|
||||
"businessDomain": "业务域名",
|
||||
"jsSecureDomain": "JS接口安全域名",
|
||||
"webAuthDomain": "网页授权域名",
|
||||
"wechatInfo": "公众号信息",
|
||||
"wechatDevelopInfo": "公众号开发信息",
|
||||
"theServerSetting": "消息推送配置",
|
||||
"functionSetting": "功能设置",
|
||||
"functionSettingTips" : "在微信公众平台中,点击 设置与开发>公众号设置>功能设置,设置业务域名 JS接口安全域名 网页授权域名",
|
||||
"tokenTips": "必须为英文或数字,长度为3-32字符。",
|
||||
"encodingAESKeyTips": "消息加密密钥由43位字符组成,可随机修改,字符范围为A-Z,a-z,0-9。",
|
||||
"encryptionType": "消息加解密方式",
|
||||
"cleartextMode": "明文模式",
|
||||
"compatibleMode": "兼容模式",
|
||||
"safeMode": "安全模式(推荐)",
|
||||
"wechatNamePlaceholder": "请输入公众号名称",
|
||||
"wechatOriginalPlaceholder": "请输入公众号原始ID",
|
||||
"appidPlaceholder": "请输入开发者ID",
|
||||
"appSecretPlaceholder": "请输入开发者密码",
|
||||
"tokenPlaceholder": "请输入Token",
|
||||
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
|
||||
"cleartextModeTips": "明文模式下,不使用消息体加解密功能,安全系数较低",
|
||||
"compatibleModeTips": "兼容模式下,明文、密文将共存,方便开发者调试和维护",
|
||||
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高"
|
||||
}
|
||||
20
admin/src/lang/zh-cn/channel.wechat.menu.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"menuNameInfo": "菜单信息",
|
||||
"subMenuNameInfo": "子菜单信息",
|
||||
"menuNameTips": "仅支持中英文和数字,字数不超过4个汉字或8个字母。",
|
||||
"subMenuNameTips": "仅支持中英文和数字,字数不超过8个汉字或16个字母。",
|
||||
"menuName": "名称",
|
||||
"deleteMemu": "删除菜单",
|
||||
"deleteMemuTips": "删除后,菜单下设置的内容全部将被删除",
|
||||
"messageType": "消息类型",
|
||||
"skipWebpage": "跳转网页",
|
||||
"skipWeapp": "跳转小程序",
|
||||
"webpageUrl": "网页链接",
|
||||
"weappAppid": "小程序Appid",
|
||||
"weappPage": "小程序页面路径",
|
||||
"menuNamePlaceholder": "请输入菜单名称",
|
||||
"webpageUrlPlaceholder": "请输入网页链接",
|
||||
"weappAppidPlaceholder": "请输入小程序Appid",
|
||||
"weappPagePlaceholder": "请输入小程序页面路径",
|
||||
"menusEmptyTips": "空菜单,不能保存与发布。"
|
||||
}
|
||||
23
admin/src/lang/zh-cn/channel.wechat.message.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "类型",
|
||||
"messageType": "消息类型",
|
||||
"isStart": "是否启用",
|
||||
"serialNumber": "编号",
|
||||
"operation": "操作",
|
||||
"operationTip": "温馨提示",
|
||||
"operationTipOne": "请将公众平台模板消息所在行业选择为:消费品/消费品,其他/其他,所选行业不一致将会导致模板消息不可用。",
|
||||
"operationTipTwo": "公众平台模板消息所在行业选择一个月只能修改一次,请谨慎选择。",
|
||||
"operationTipThree": "公众号最多支持25个模板消息获取时请注意公众号剩余模板数量是否充足",
|
||||
"operationTipFour": "所需跳转到的小程序必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏",
|
||||
"buyerNews": "买家消息",
|
||||
"sellerMessage": "卖家消息",
|
||||
"started": "启用",
|
||||
"closed": "禁用",
|
||||
"close": "关闭",
|
||||
"open": "开启",
|
||||
"response": "回复内容",
|
||||
"regain": "重新获取",
|
||||
"batchAcquisition": "一键获取",
|
||||
"id": "id"
|
||||
|
||||
}
|
||||
100
admin/src/lang/zh-cn/common.json
Normal file
@ -0,0 +1,100 @@
|
||||
{
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"info": "详情",
|
||||
"createTime": "创建时间",
|
||||
"sort": "排序",
|
||||
"status": "状态",
|
||||
"operation": "操作",
|
||||
"more": "更多",
|
||||
"statusNormal": "正常",
|
||||
"statusDeactivate": "停用",
|
||||
"startUsing": "启用",
|
||||
"confirm": "确认",
|
||||
"save": "保存",
|
||||
"back": "返回",
|
||||
"cancel": "取消",
|
||||
"search": "搜索",
|
||||
"reset": "重置",
|
||||
"warning": "提示",
|
||||
"isShow": "是否显示",
|
||||
"show": "显示",
|
||||
"hidden": "隐藏",
|
||||
"icon": "图标",
|
||||
"userName": "用户名",
|
||||
"headImg": "头像",
|
||||
"accountNumber": "账号",
|
||||
"password": "密码",
|
||||
"confirmPassword": "确认密码",
|
||||
"image": "图片",
|
||||
"video": "视频",
|
||||
"rename": "重命名",
|
||||
"lookOver": "查看",
|
||||
"selectAll": "全选",
|
||||
"yes": "是",
|
||||
"no": "否",
|
||||
"copy": "复制",
|
||||
"copySuccess": "复制成功",
|
||||
"notSupportCopy": "浏览器不支持一键复制,请手动进行复制",
|
||||
"selectPlaceholder": "全部",
|
||||
"provincePlaceholder": "请选择省",
|
||||
"cityPlaceholder": "请选择市",
|
||||
"districtPlaceholder": "请选择区/县",
|
||||
"emptyData": "暂无数据",
|
||||
"upload": {
|
||||
"root": "上传",
|
||||
"selectimage": "选择图片",
|
||||
"selectvideo": "选择视频",
|
||||
"uploadimage": "上传图片",
|
||||
"uploadvideo": "上传视频",
|
||||
"addAttachmentCategory": "添加分组",
|
||||
"attachmentCategoryPlaceholder": "请输入分组名称",
|
||||
"attachmentEmpty": "暂无附件,请点击上传按钮上传",
|
||||
"deleteCategoryTips": "确定要删除该分组吗?",
|
||||
"deleteAttachmentTips": "确定要删除所选附件吗?如所选附件已被使用删除将会受到影响,请谨慎操作!",
|
||||
"move": "移动",
|
||||
"moveCategory": "移动分组",
|
||||
"moveTo": "移动至",
|
||||
"placeholderimageName": "请输入图片名称",
|
||||
"placeholdervideoName": "请输入视频名称",
|
||||
"success": "上传成功",
|
||||
"triggerUpperLimit": "可选数量已达上限"
|
||||
},
|
||||
"tabs": {
|
||||
"closeLeft": "关闭左侧",
|
||||
"closeRight": "关闭右侧",
|
||||
"closeOther": "关闭其他"
|
||||
},
|
||||
"layout": {
|
||||
"layoutSetting": "主题设置",
|
||||
"darkMode": "黑暗模式",
|
||||
"sidebarMode": "主题风格",
|
||||
"themeColor": "主题颜色"
|
||||
},
|
||||
"axios": {
|
||||
"unknownError": "未知错误",
|
||||
"400": "错误的请求",
|
||||
"401": "请重新登录",
|
||||
"403": "拒绝访问",
|
||||
"404": "请求错误,未找到该资源",
|
||||
"405": "请求方法未允许",
|
||||
"408": "请求超时",
|
||||
"500": "服务器端出错",
|
||||
"501": "网络未实现",
|
||||
"502": "网络错误",
|
||||
"503": "服务不可用",
|
||||
"504": "网络超时",
|
||||
"505": "http版本不支持该请求",
|
||||
"timeout": "网络请求超时!"
|
||||
},
|
||||
"linkPlaceholder": "请选择跳转链接",
|
||||
"selectLinkTips": "链接选择",
|
||||
"diyLinkName": "链接名称",
|
||||
"diyLinkNamePlaceholder": "请输入链接名称",
|
||||
"diyLinkNameNotEmpty": "链接名称不能为空",
|
||||
"diyLinkUrl": "跳转路径",
|
||||
"diyLinkUrlPlaceholder": "请输入跳转路径",
|
||||
"diyLinkUrlNotEmpty": "跳转路径不能为空",
|
||||
"returnToPreviousPage": "返回",
|
||||
"preview": "预览"
|
||||
}
|
||||
88
admin/src/lang/zh-cn/decorate.edit.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"pageSet": "页面设置",
|
||||
"pageContent": "页面内容",
|
||||
"pageName": "页面名称",
|
||||
"pageNamePlaceholder": "请输入页面名称",
|
||||
"pageBgColor": "页面颜色",
|
||||
"warmPrompt": "温馨提示",
|
||||
"leavePageTitleTips": "确定离开此页面?",
|
||||
"leavePageContentTips": "系统可能不会保存您所做的更改。",
|
||||
"decorating": "正在装修",
|
||||
"moveUpComponent": "上移",
|
||||
"moveDownComponent": "下移",
|
||||
"copyComponent": "复制",
|
||||
"delComponent": "删除",
|
||||
"resetComponent": "重置",
|
||||
"tabbar": "底部导航",
|
||||
"tabbarSwitchTips": "此处控制当前页面底部导航菜单是否显示",
|
||||
"link": "链接地址",
|
||||
"delComponentTips": "确定要删除吗?",
|
||||
"notCopy": "无法复制",
|
||||
"componentCanOnlyAdd": "组件只能添加",
|
||||
"piece": "个",
|
||||
"resetComponentTips": "确认要重置组件默认数据吗?",
|
||||
"image": "图片上传",
|
||||
"imageUpload": "图片上传",
|
||||
"imageSet": "图片设置",
|
||||
"imageAdsTips": "建议上传尺寸相同的图片,推荐尺寸750*350",
|
||||
"addImageAd": "添加图片",
|
||||
"imageUrlTip": "请上传图片",
|
||||
"articleData": "文章数据",
|
||||
"dataSources": "数据来源",
|
||||
"defaultSources": "默认",
|
||||
"manualSelectionSources": "手动选择",
|
||||
"articleNum": "文章数量",
|
||||
"selectPlaceholder": "请选择",
|
||||
"selectArticleTips": "文章选择",
|
||||
"articleTitle": "标题",
|
||||
"articleImage": "封面",
|
||||
"articleCategoryName": "栏目",
|
||||
"articleSummary": "摘要",
|
||||
"selected": "已选",
|
||||
"selectArticleTip": "请选择文章",
|
||||
"graphicNavModeTitle": "导航模式",
|
||||
"layoutMode": "排版模式",
|
||||
"layoutModeHorizontal": "横排",
|
||||
"layoutModeVertical": "竖排",
|
||||
"graphicNavSelectMode": "选择模式",
|
||||
"graphicNavModeGraphic": "图文导航",
|
||||
"graphicNavModeImg": "图片导航",
|
||||
"graphicNavModeText": "文字导航",
|
||||
"graphicNavImageSet": "图片设置",
|
||||
"graphicNavImageSize": "图片大小",
|
||||
"graphicNavAroundRadius": "图片圆角",
|
||||
"graphicNavShowStyle": "展示风格",
|
||||
"graphicNavStyleFixed": "固定显示",
|
||||
"graphicNavStyleSingleSlide": "单行滑动",
|
||||
"graphicNavStylePageSlide": "分页滑动",
|
||||
"graphicNavRowCount": "每行数量",
|
||||
"graphicNavPageCount": "每行数量",
|
||||
"graphicNavSetLabel": "导航设置",
|
||||
"line": "行",
|
||||
"graphicNavTips": "建议上传尺寸相同的图片,推荐尺寸60*60",
|
||||
"graphicNavTitle": "标题",
|
||||
"graphicNavTitlePlaceholder": "请输入标题",
|
||||
"addGraphicNav": "添加导航",
|
||||
"blankHeightSet": "高度设置",
|
||||
"blankHeight": "空白高度",
|
||||
"titleStyle": "标题样式",
|
||||
"selectStyle": "风格选择",
|
||||
"titleContent": "标题内容",
|
||||
"title": "标题名称",
|
||||
"titlePlaceholder": "请输入标题",
|
||||
"textAlign": "对齐方式",
|
||||
"textAlignLeft": "居左",
|
||||
"textAlignCenter": "居中",
|
||||
"textFontSize": "文字大小",
|
||||
"textFontWeight": "文字粗细",
|
||||
"fontWeightBold": "加粗",
|
||||
"fontWeightNormal": "常规",
|
||||
"textColor": "文字颜色",
|
||||
"subTitleContent": "标题内容",
|
||||
"subTitle": "副标题",
|
||||
"subTitlePlaceholder": "请输入副标题",
|
||||
"moreContent": "“更多”按钮内容",
|
||||
"more": "文字",
|
||||
"morePlaceholder": "请输入文字",
|
||||
"moreIsShow": "是否显示"
|
||||
}
|
||||
10
admin/src/lang/zh-cn/diy.index.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"decorate": "装修",
|
||||
"preview": "预览",
|
||||
"weapp": "微信小程序",
|
||||
"wechat": "微信公众号",
|
||||
"link": "链接",
|
||||
"copy": "复制",
|
||||
"copySuccess": "复制成功",
|
||||
"weappNotSet": "小程序未配置"
|
||||
}
|
||||
34
admin/src/lang/zh-cn/diy.list.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"title": "页面名称",
|
||||
"typeName": "页面类型",
|
||||
"addPageTips": "创建新页面",
|
||||
"pageTypePlaceholder": "请选择页面类型",
|
||||
"nameMax": "名称不能超过12个字符",
|
||||
"status": "状态",
|
||||
"updateTime": "更新时间",
|
||||
"use": "使用",
|
||||
"isUse": "使用中",
|
||||
"unused": "未使用",
|
||||
"all": "全部",
|
||||
"basicRoute": "基础页面",
|
||||
"diyPage": "自定义页面",
|
||||
"wapUrl": "wap链接",
|
||||
"weappUrl": "小程序链接",
|
||||
"shareLink": "分享链接",
|
||||
"copy": "复制",
|
||||
"copySuccess": "复制成功",
|
||||
"titlePlaceholder": "请输入页面名称",
|
||||
"addDiyPage": "添加页面",
|
||||
"diyPageDeleteTips": "确定要删除该自定义页面吗?",
|
||||
"promote": "推广",
|
||||
"share": "分享",
|
||||
"shareSet": "分享设置",
|
||||
"sharePage": "分享页面",
|
||||
"wechat": "微信公众号",
|
||||
"weapp": "微信小程序",
|
||||
"shareTitle": "分享标题",
|
||||
"shareTitlePlaceholder": "请输入分享标题",
|
||||
"shareDesc": "分享描述",
|
||||
"shareDescPlaceholder": "请输入分享描述",
|
||||
"shareImageUrl": "分享图片"
|
||||
}
|
||||
57
admin/src/lang/zh-cn/diy.tabbar.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"siteId":"站点id",
|
||||
"title":"页面名称",
|
||||
"name":"页面标识",
|
||||
"type":"页面类型",
|
||||
"value":"页面数据,json格式",
|
||||
"isDefault":"是否默认页面,1:是,0:否",
|
||||
"visitCount":"访问量",
|
||||
"siteIdPlaceholder":"请输入站点id",
|
||||
"titlePlaceholder":"请输入页面名称",
|
||||
"namePlaceholder":"请输入页面标识",
|
||||
"typePlaceholder":"请输入页面类型",
|
||||
"valuePlaceholder":"请输入页面数据,json格式",
|
||||
"isDefaultPlaceholder":"请输入是否默认页面,1:是,0:否",
|
||||
"visitCountPlaceholder":"请输入访问量",
|
||||
"createTimePlaceholder":"请输入创建时间",
|
||||
"updateTimePlaceholder":"请输入更新时间",
|
||||
"addDiyPage":"添加自定义页面",
|
||||
"updateDiyPage":"编辑自定义页面",
|
||||
"diyPageDeleteTips":"确定要删除该自定义页面吗?",
|
||||
"leastTwoNav":"至少添加2个导航",
|
||||
"pleaseUpload":"请上传第[",
|
||||
"pleaseEnter":"请输入第[",
|
||||
"pleaseChoose":"请选择第[",
|
||||
"navIcon":"]个图标",
|
||||
"navSelectIcon":"]个选中图标",
|
||||
"navTitle":"]个导航标题",
|
||||
"navLink":"]个导航链接",
|
||||
"backgroundColor":"背景颜色",
|
||||
"imageText":"图文",
|
||||
"image":"图片",
|
||||
"text":"文字",
|
||||
"textColor":"文字颜色",
|
||||
"textSelectColor":"文字选中颜色",
|
||||
"reset":"重置",
|
||||
"navType":"导航类型",
|
||||
"styleSet":"样式设置",
|
||||
"addnav":"添加导航",
|
||||
"linkPlaceholder":"请选择链接",
|
||||
"navLinkOne":"导航链接",
|
||||
"navTitleOne":"导航标题",
|
||||
"titleContent":"请输入标题内容",
|
||||
"navIconOne":"导航图标",
|
||||
"navImage":"导航图片",
|
||||
"bottomNav":"底部导航",
|
||||
"bottomNavHint":"设置至少添加2个导航,最多添加5个导航",
|
||||
"selectLinkTips":"选择链接",
|
||||
"selectLinkConfirm":"确定",
|
||||
"uploadImgUnselected":"未选中",
|
||||
"uploadImgSelected":"选中"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
19
admin/src/lang/zh-cn/finance.recharge.detail.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"orderInfo":"订单详情",
|
||||
"orderDiscountMoney":"优惠金额",
|
||||
"ip":"下单IP",
|
||||
"payTime":"支付时间",
|
||||
"remark":"商家留言",
|
||||
"memberMessage":"买家留言",
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间"
|
||||
}
|
||||
14
admin/src/lang/zh-cn/finance.recharge.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择"
|
||||
}
|
||||
24
admin/src/lang/zh-cn/finance.withdrawal.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"applyTime":"申请时间",
|
||||
"withdrawalStatus":"提现状态",
|
||||
"actualTransferAmount":"实际转账金额",
|
||||
"withdrawalCommission":"提现手续费",
|
||||
"applicationForWithdrawalAmount":"申请提现金额",
|
||||
"withdrawalMethod":"提现方式",
|
||||
"memberInfo":"会员信息",
|
||||
"toBeTransferred":"待转账",
|
||||
"transferred":"已转账",
|
||||
"turnDown":"拒绝"
|
||||
}
|
||||
32
admin/src/lang/zh-cn/index.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"todayData": "今日数据",
|
||||
"memberNumb": "会员数量",
|
||||
"orderMoney": "订单金额",
|
||||
"numberOfSites": "站点数量",
|
||||
"numberOfVisitors": "访客数量",
|
||||
"commonlyUsedFunction": "常用功能",
|
||||
"articleList": "文章列表",
|
||||
"memberManagement": "会员管理",
|
||||
"balanceAccount": "余额账户",
|
||||
"administrator": "管理员",
|
||||
"WebDecoration": "网站装修",
|
||||
"accessMessage": "访问消息",
|
||||
"memberDistribution": "会员分布",
|
||||
"systemInfo": "系统环境",
|
||||
"os": "操作系统",
|
||||
"phpVersions": "PHP版本号",
|
||||
"productionEnvironment": "生产环境",
|
||||
"versionsInfo": "版本信息",
|
||||
"versions": "当前版本",
|
||||
"frame": "基于框架",
|
||||
"channel": "获取渠道",
|
||||
"serviceSupport": "服务支持",
|
||||
"officialWbsite": "官网",
|
||||
"pageView": "访问量",
|
||||
"siteInfo":"站点信息",
|
||||
"siteName":"站点名称",
|
||||
"groupName":"站点套餐",
|
||||
"expireTime":"过期时间",
|
||||
"permanent":"永久",
|
||||
"statusName":"站点状态"
|
||||
}
|
||||
9
admin/src/lang/zh-cn/login.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"siteTitle": "Niucloud Admin",
|
||||
"siteDesc": "基于thinkphp6+elementplus+typescript等技术的多端saas通用管理框架,采用restful的api接口设计,前后端完全分离,同时支持多语言开发。",
|
||||
"logging": "登录中",
|
||||
"platform": "管理端",
|
||||
"login" : "登录",
|
||||
"userPlaceholder": "请输入您的账号",
|
||||
"passwordPlaceholder": "请输入您的密码"
|
||||
}
|
||||