mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-03-17 11:13:42 +00:00
0.2.1
This commit is contained in:
parent
ed7ae681bf
commit
9bc5f0f3bd
@ -1,7 +1,7 @@
|
|||||||
NODE_ENV = 'development'
|
NODE_ENV = 'development'
|
||||||
|
|
||||||
# api请求地址
|
# api请求地址
|
||||||
VITE_APP_BASE_URL='/adminapi/'
|
VITE_APP_BASE_URL=''
|
||||||
|
|
||||||
# 图片服务器地址
|
# 图片服务器地址
|
||||||
VITE_IMG_DOMAIN=''
|
VITE_IMG_DOMAIN=''
|
||||||
|
|||||||
1
admin/components.d.ts
vendored
1
admin/components.d.ts
vendored
@ -51,6 +51,7 @@ declare module '@vue/runtime-core' {
|
|||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||||
|
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||||
ElResult: typeof import('element-plus/es')['ElResult']
|
ElResult: typeof import('element-plus/es')['ElResult']
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
ElRow: typeof import('element-plus/es')['ElRow']
|
||||||
|
|||||||
@ -19,6 +19,8 @@ const route = useRoute()
|
|||||||
// 初始化设置语言
|
// 初始化设置语言
|
||||||
const systemStore = useSystemStore()
|
const systemStore = useSystemStore()
|
||||||
const locale = computed(() => (systemStore.lang === 'zh-cn' ? zhCn : en))
|
const locale = computed(() => (systemStore.lang === 'zh-cn' ? zhCn : en))
|
||||||
|
// 查询website信息
|
||||||
|
systemStore.getWebsiteInfo()
|
||||||
|
|
||||||
const toggleDark = useToggle(useDark())
|
const toggleDark = useToggle(useDark())
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,14 @@ import request from '@/utils/request'
|
|||||||
export function getDiyPageList(params: Record<string, any>) {
|
export function getDiyPageList(params: Record<string, any>) {
|
||||||
return request.get(`diy/diy`, {params})
|
return request.get(`diy/diy`, {params})
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取自定义页面分页列表,轮播搜索组件用
|
||||||
|
* @param params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getDiyPageListByCarouselSearch(params: Record<string, any>) {
|
||||||
|
return request.get(`diy/carousel_search`, {params})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取自定义页面列表
|
* 获取自定义页面列表
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export function getModuleVersion() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function downloadVersion(params: Record<string, any>) {
|
export function downloadVersion(params: Record<string, any>) {
|
||||||
return request.post(`addon/download/${params.addon}`, params, { showSuccessMessage: true })
|
return request.post(`addon/download/${params.addon}`, params, { timeout: 0, showSuccessMessage: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -159,7 +159,7 @@ export function getWebsite() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取网站设置
|
* 获取网站设置 (未登录状态调用)
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getWebConfig() {
|
export function getWebConfig() {
|
||||||
|
|||||||
@ -59,6 +59,83 @@ export function getBatchAcquisition(params: Record<string, any>) {
|
|||||||
return request.put('wechat/template/sync', params, {showSuccessMessage: true})
|
return request.put('wechat/template/sync', params, {showSuccessMessage: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询关键字回复列表
|
||||||
|
*/
|
||||||
|
export function getKeywordsReplyList(params: Record<string, any>) {
|
||||||
|
return request.get('wechat/reply/keywords', { params })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改关键字回复
|
||||||
|
*/
|
||||||
|
export function editKeywordsReply(params: Record<string, any>) {
|
||||||
|
return request.put(`wechat/reply/keywords/${params.id}`, params, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改关键字回复
|
||||||
|
*/
|
||||||
|
export function addKeywordsReply(params: Record<string, any>) {
|
||||||
|
return request.post('wechat/reply/keywords', params, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询关键字回复信息
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export function getKeywordsReplyInfo(id: number) {
|
||||||
|
return request.get(`wechat/reply/keywords/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改关键字回复
|
||||||
|
*/
|
||||||
|
export function delKeywordsReply(id: number) {
|
||||||
|
return request.delete(`wechat/reply/keywords/${id}`, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认回复
|
||||||
|
*/
|
||||||
|
export function getDefaultReply() {
|
||||||
|
return request.get('wechat/reply/default')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置默认回复
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export function setDefaultReply(params: Record<string, any>) {
|
||||||
|
return request.put('wechat/reply/default', params, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取关注回复
|
||||||
|
*/
|
||||||
|
export function getSubscribeReply() {
|
||||||
|
return request.get('wechat/reply/subscribe')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置关注回复
|
||||||
|
*/
|
||||||
|
export function setSubscribeReply(params: Record<string, any>) {
|
||||||
|
return request.put('wechat/reply/subscribe', params, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询素材列表
|
||||||
|
*/
|
||||||
|
export function getMediaList(params: Record<string, any>) {
|
||||||
|
return request.get('wechat/media', { params })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步素材库
|
||||||
|
*/
|
||||||
|
export function syncNews() {
|
||||||
|
return request.get('wechat/sync/news')
|
||||||
|
}
|
||||||
|
|||||||
BIN
admin/src/app/assets/images/logo.png
Normal file
BIN
admin/src/app/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
81
admin/src/app/components/user-info-edit/index.vue
Normal file
81
admin/src/app/components/user-info-edit/index.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="t('accountSettings')"
|
||||||
|
width="500"
|
||||||
|
>
|
||||||
|
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
|
||||||
|
<el-form-item :label="t('headImg')">
|
||||||
|
<upload-image v-model="saveInfo.head_img" :limit="1" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('userName')">
|
||||||
|
<span>{{saveInfo.username}}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('realName')">
|
||||||
|
<el-input v-model="saveInfo.real_name" :placeholder="t('realNamePlaceholder')" clearable class="input-width" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<el-button type="primary" @click="submitForm(formRef)" :loading="loading">{{ t('save') }}</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import type { FormInstance } from 'element-plus'
|
||||||
|
|
||||||
|
import { getUserInfo, setUserInfo } from '@/app/api/personal'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
// 提交信息
|
||||||
|
const saveInfo = reactive({})
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const loading = ref(true)
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
/**
|
||||||
|
* 获取用户信息
|
||||||
|
*/
|
||||||
|
const getUserInfoFn = () => {
|
||||||
|
|
||||||
|
getUserInfo().then(res => {
|
||||||
|
loading.value = false
|
||||||
|
const data = res.data
|
||||||
|
saveInfo.head_img = data.head_img
|
||||||
|
saveInfo.real_name = data.real_name
|
||||||
|
saveInfo.username = data.username
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getUserInfoFn()
|
||||||
|
const open = ()=>{
|
||||||
|
dialogVisible.value = true
|
||||||
|
getUserInfoFn()
|
||||||
|
}
|
||||||
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (loading.value || !formEl) return
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
loading.value = true
|
||||||
|
setUserInfo(saveInfo).then((res: any) => {
|
||||||
|
loading.value = false
|
||||||
|
dialogVisible.value = false
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -6,6 +6,9 @@
|
|||||||
"menuTypeMenu": "菜单",
|
"menuTypeMenu": "菜单",
|
||||||
"menuTypeButton": "按钮",
|
"menuTypeButton": "按钮",
|
||||||
"menuDeleteTips": "删除菜单会删除当前菜单以及该菜单下所有子菜单,是否确认删除?",
|
"menuDeleteTips": "删除菜单会删除当前菜单以及该菜单下所有子菜单,是否确认删除?",
|
||||||
|
"initializeMenu":"重置菜单",
|
||||||
|
"initializeMenuTipsOne":"重置菜单会将应用或插件的dict目录下的菜单配置文件中,菜单配置更新到数据库一般用做开发者修改了dict菜单配置文件后,同步到数据库操作。",
|
||||||
|
"initializeMenuTipsTwo":"如果用户手动调整过以下菜单项,通常不允诛进行本项操作,操作会重置为原始菜单。 请谨慎使用!",
|
||||||
"addMenu": "添加菜单",
|
"addMenu": "添加菜单",
|
||||||
"updateMenu": "编辑菜单",
|
"updateMenu": "编辑菜单",
|
||||||
"routePath": "路由路径",
|
"routePath": "路由路径",
|
||||||
|
|||||||
@ -7,6 +7,9 @@
|
|||||||
"menuTypeButton": "按钮",
|
"menuTypeButton": "按钮",
|
||||||
"menuDeleteTips": "确定要删除该菜单吗?",
|
"menuDeleteTips": "确定要删除该菜单吗?",
|
||||||
"addMenu": "添加菜单",
|
"addMenu": "添加菜单",
|
||||||
|
"initializeMenu":"重置菜单",
|
||||||
|
"initializeMenuTipsOne":"重置菜单会将应用或插件的dict目录下的菜单配置文件中,菜单配置更新到数据库一般用做开发者修改了dict菜单配置文件后,同步到数据库操作。",
|
||||||
|
"initializeMenuTipsTwo":"如果用户手动调整过以下菜单项,通常不允诛进行本项操作,操作会重置为原始菜单。 请谨慎使用!",
|
||||||
"updateMenu": "编辑菜单",
|
"updateMenu": "编辑菜单",
|
||||||
"routePath": "路由路径",
|
"routePath": "路由路径",
|
||||||
"viewPath": "组件路径",
|
"viewPath": "组件路径",
|
||||||
|
|||||||
@ -15,5 +15,6 @@
|
|||||||
"customMenu": "自定义菜单",
|
"customMenu": "自定义菜单",
|
||||||
"wechatAccessBtn": "查看审核进度",
|
"wechatAccessBtn": "查看审核进度",
|
||||||
"clickAccess2":"扫描二维码进入微信公众号",
|
"clickAccess2":"扫描二维码进入微信公众号",
|
||||||
"wechatTemplate": "模板消息"
|
"wechatTemplate": "模板消息",
|
||||||
|
"reply": "自动回复"
|
||||||
}
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"ruleName": "规则名称",
|
||||||
|
"ruleNameTips": "规则名不能为空且最多60个字",
|
||||||
|
"ruleNamePlaceholder": "请输入规则名称",
|
||||||
|
"keywordPlaceholder": "请输入关键字",
|
||||||
|
"contentPlaceholder": "请选择回复内容",
|
||||||
|
"allMatching": "全匹配",
|
||||||
|
"fuzzyMatching": "模糊匹配",
|
||||||
|
"keyword": "关键字",
|
||||||
|
"content": "回复内容",
|
||||||
|
"replyMethod": "回复方式",
|
||||||
|
"replyMethodAll": "全部回复",
|
||||||
|
"replyMethodRand": "随机回复一条",
|
||||||
|
"addReplyContent": "添加回复内容"
|
||||||
|
}
|
||||||
@ -19,5 +19,6 @@
|
|||||||
"wechatAccessFlow": "接入流程",
|
"wechatAccessFlow": "接入流程",
|
||||||
"customMenu": "自定义菜单",
|
"customMenu": "自定义菜单",
|
||||||
"wechatTemplate": "模板消息",
|
"wechatTemplate": "模板消息",
|
||||||
"menusEmptyTips": "空菜单,不能保存与发布。"
|
"menusEmptyTips": "空菜单,不能保存与发布。",
|
||||||
|
"reply": "自动回复"
|
||||||
}
|
}
|
||||||
12
admin/src/app/lang/zh-cn/channel.wechat.reply.json
Normal file
12
admin/src/app/lang/zh-cn/channel.wechat.reply.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"title": "自动回复",
|
||||||
|
"wechatAccessFlow": "接入流程",
|
||||||
|
"wechatSet": "公众号配置",
|
||||||
|
"customMenu": "自定义菜单",
|
||||||
|
"wechatTemplate": "模板消息",
|
||||||
|
"reply": "自动回复",
|
||||||
|
"keywordReply": "关键词回复",
|
||||||
|
"defaultReply": "默认回复",
|
||||||
|
"subscribeReply": "关注回复",
|
||||||
|
"replyDeleteTips": "确定要删除该条回复吗?"
|
||||||
|
}
|
||||||
@ -21,5 +21,5 @@
|
|||||||
"wechatAccessFlow": "接入流程",
|
"wechatAccessFlow": "接入流程",
|
||||||
"customMenu": "自定义菜单",
|
"customMenu": "自定义菜单",
|
||||||
"wechatTemplate": "模板消息",
|
"wechatTemplate": "模板消息",
|
||||||
"id": "id"
|
"reply": "自动回复"
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"copyrightEdit":"版权设置",
|
"copyrightEdit":"基础设置",
|
||||||
"putOnRecordEdit":"备案设置",
|
"putOnRecordEdit":"备案设置",
|
||||||
|
|
||||||
"companyName": "公司名称",
|
"companyName": "公司名称",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"buyerNotice": "会员消息",
|
"buyerNotice": "会员消息",
|
||||||
"sellerNotice":"平台消息",
|
"sellerNotice":"商家消息",
|
||||||
"sms":"短信",
|
"sms":"短信",
|
||||||
"weapp":"微信小程序",
|
"weapp":"微信小程序",
|
||||||
"wechat":"微信公众号",
|
"wechat":"微信公众号",
|
||||||
@ -18,5 +18,6 @@
|
|||||||
"weappTempKey" : "模板编号",
|
"weappTempKey" : "模板编号",
|
||||||
"smsId":"短信模版ID",
|
"smsId":"短信模版ID",
|
||||||
"smsIdPlaceholder":"短信模版ID",
|
"smsIdPlaceholder":"短信模版ID",
|
||||||
"noticeType":"消息类型"
|
"noticeType":"消息类型",
|
||||||
|
"addon": "所属应用"
|
||||||
}
|
}
|
||||||
@ -25,14 +25,10 @@
|
|||||||
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
|
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[46px] ml-[40px] flex flex-wrap">
|
<div class="mt-[46px] ml-[40px] flex flex-wrap">
|
||||||
<span class="text-[14px] mr-[84px]">授权域名<em
|
<span class="text-[14px] mr-[84px]">授权域名<em class="ml-[12px] text-[12px]">{{ authinfo.site_address || '--' }}</em></span>
|
||||||
class="ml-[12px] text-[12px]">{{ authinfo.site_address || '--'
|
|
||||||
}}</em></span>
|
|
||||||
<span class="text-[14px] flex items-center">
|
<span class="text-[14px] flex items-center">
|
||||||
<span>授权码</span>
|
<span>授权码</span>
|
||||||
<em class="ml-[12px] mr-[10px] text-[12px]">{{ authinfo.auth_code ? (isCheck
|
<em class="ml-[12px] mr-[10px] text-[12px]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
|
||||||
?
|
|
||||||
authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
|
|
||||||
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
|
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
|
||||||
<View />
|
<View />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -43,8 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 flex-wrap justify-end relative">
|
<div class="flex flex-1 flex-wrap justify-end relative">
|
||||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
|
||||||
@click="authCodeApproveFn">授权码认证</el-button>
|
|
||||||
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click"
|
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click"
|
||||||
class="mt-[8px]">
|
class="mt-[8px]">
|
||||||
<div class="px-[18px] py-[8px]">
|
<div class="px-[18px] py-[8px]">
|
||||||
@ -52,8 +47,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="flex justify-end mt-[36px]">
|
<div class="flex justify-end mt-[36px]">
|
||||||
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
||||||
<el-button class="w-[100px] !h-[48px]" plain
|
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
|
||||||
@click="getAuthCodeDialog.hide()">关闭</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
@ -67,14 +61,12 @@
|
|||||||
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<el-form-item prop="auth_code">
|
<el-form-item prop="auth_code">
|
||||||
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')"
|
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
|
||||||
class="input-width" clearable size="large" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<el-form-item prop="auth_secret">
|
<el-form-item prop="auth_secret">
|
||||||
<el-input v-model="formData.auth_secret" clearable
|
<el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
|
||||||
:placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -82,8 +74,7 @@
|
|||||||
|
|
||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
|
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
|
||||||
@click="save(formRef)">{{
|
@click="save(formRef)">{{ t('confirm') }}</el-button>
|
||||||
t('confirm') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[10px] text-right">
|
<div class="mt-[10px] text-right">
|
||||||
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
||||||
@ -201,12 +192,10 @@ const save = async (formEl: FormInstance | undefined) => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
saveLoading.value = true
|
saveLoading.value = true
|
||||||
|
|
||||||
setAuthinfo(formData)
|
setAuthinfo(formData).then(() => {
|
||||||
.then(() => {
|
|
||||||
saveLoading.value = false
|
saveLoading.value = false
|
||||||
checkAppMange()
|
checkAppMange()
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
saveLoading.value = false
|
saveLoading.value = false
|
||||||
authCodeApproveDialog.value = false
|
authCodeApproveDialog.value = false
|
||||||
})
|
})
|
||||||
|
|||||||
@ -6,15 +6,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="appList.length">
|
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="appList.length">
|
||||||
<div v-for="(item, index) in appList" :key="index + 'b'">
|
<div v-for="(item, index) in appList" :key="index + 'b'">
|
||||||
<div
|
<div class="relative app-item cursor-pointer px-4 mr-4 mt-[20px] bg-[#f7f7f7] border-[1px] hover:border-primary">
|
||||||
class="relative app-item cursor-pointer px-4 mr-4 mt-[20px] bg-[#f7f7f7] border-[1px] hover:border-primary">
|
|
||||||
<div @click="toLink(item.key)" class="flex py-5 items-center">
|
<div @click="toLink(item.key)" class="flex py-5 items-center">
|
||||||
<div class="flex justify-center items-center">
|
<div class="flex justify-center items-center">
|
||||||
<el-image class="w-[40px] h-[40px]" :src="img(item.icon)" fit="contain">
|
<el-image class="w-[40px] h-[40px]" :src="img(item.icon)" fit="contain">
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
<img class="w-[50px] h-[50px]"
|
<img class="w-[50px] h-[50px]" src="@/app/assets/images/index/app_default.png" />
|
||||||
src="@/app/assets/images/index/app_default.png" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pt-[64px] px-[90px] app-store" v-loading="loading">
|
<div class="app-store" v-loading="loading">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div v-if="info[activeName] && !loading">
|
<div v-if="info[activeName] && !loading">
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
<div class="flex justify-between items-center h-[32px]">
|
||||||
<span class="text-[26px] text-[#222] font-600">{{ t('localAppText') }}</span>
|
<span class="text-[16px] text-[#222] font-600">{{ t('localAppText') }}</span>
|
||||||
<div class="w-[247px]">
|
<div class="w-[247px]">
|
||||||
<el-input :placeholder="t('search')" v-model="searchName" @keyup.enter="query">
|
<el-input :placeholder="t('search')" v-model="searchName" @keyup.enter="query">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
@ -13,7 +14,7 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[24px]">
|
<div class="flex mt-[16px]">
|
||||||
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'installed' }"
|
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'installed' }"
|
||||||
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
|
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
|
||||||
@click="activeName = 'installed'">
|
@click="activeName = 'installed'">
|
||||||
@ -42,8 +43,7 @@
|
|||||||
<img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt="">
|
<img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt="">
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
<div
|
<div class="flex flex-col justify-center h-[54px] pl-[20px] text-[#222] font-500 text-[13px]">
|
||||||
class="flex flex-col justify-center h-[54px] pl-[20px] text-[#222] font-500 text-[13px]">
|
|
||||||
<div class="w-[236px] truncate leading-[18px]">{{ row.title }}</div>
|
<div class="w-[236px] truncate leading-[18px]">{{ row.title }}</div>
|
||||||
<div class="w-[236px] truncate leading-[18px] mt-[6px]">{{ row.version }}</div>
|
<div class="w-[236px] truncate leading-[18px] mt-[6px]">{{ row.version }}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -72,8 +72,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('type')" align="left" min-width="100">
|
<el-table-column :label="t('type')" align="left" min-width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon')
|
<span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon') }}</span>
|
||||||
}}</span>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="" :label="t('author')" align="left" min-width="100">
|
<el-table-column prop="" :label="t('author')" align="left" min-width="100">
|
||||||
@ -83,22 +82,14 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="150">
|
<el-table-column :label="t('operation')" fixed="right" align="right" width="150">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{
|
<el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{ t('detail') }}</el-button>
|
||||||
t('detail') }}</el-button>
|
<el-button class="!text-[13px]" v-if="row.install_info && Object.keys(row.install_info)?.length" type="primary" link @click="uninstallAddonFn(row.key)">{{ t('unload') }}</el-button>
|
||||||
<el-button class="!text-[13px]" v-if="row.install_info && Object.keys(row.install_info)?.length"
|
<el-button class="!text-[13px]" v-else-if="row.is_download && row.install_info <= 0" type="primary" link @click="installAddonFn(row.key)">{{ t('install') }}</el-button>
|
||||||
type="primary" link @click="uninstallAddonFn(row.key)">{{ t('unload') }}</el-button>
|
<el-button class="!text-[13px]" v-else :loading="downloading == row.key" :disabled="downloading != ''" type="primary" link @click.stop="downEvent(row)">{{ t('down') }}</el-button>
|
||||||
|
|
||||||
<el-button class="!text-[13px]" v-else-if="row.is_download && row.install_info <= 0"
|
|
||||||
type="primary" link @click="installAddonFn(row.key)">{{ t('install')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button class="!text-[13px]" v-else :loading="downloading == row.key"
|
|
||||||
:disabled="downloading != ''" type="primary" link @click.stop="downEvent(row)">{{
|
|
||||||
t('down') }}</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-empty class="mx-auto overview-empty"
|
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading && activeName == 'installed'">
|
||||||
v-if="!localList.installed.length && !loading && activeName == 'installed'">
|
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
@ -108,8 +99,7 @@
|
|||||||
<p class="flex items-center">{{ t('installed-empty') }}</p>
|
<p class="flex items-center">{{ t('installed-empty') }}</p>
|
||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</el-empty>
|
||||||
<el-empty class="mx-auto overview-empty"
|
<el-empty class="mx-auto overview-empty" v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
|
||||||
v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
|
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
@ -123,21 +113,17 @@
|
|||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</el-empty>
|
||||||
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'"
|
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'" class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
||||||
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
|
||||||
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
||||||
<div class="flex flex-1 flex-wrap justify-center relative">
|
<div class="flex flex-1 flex-wrap justify-center relative">
|
||||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
|
||||||
@click="authCodeApproveFn">授权码认证</el-button>
|
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" class="mt-[8px]">
|
||||||
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click"
|
|
||||||
class="mt-[8px]">
|
|
||||||
<div class="px-[18px] py-[8px]">
|
<div class="px-[18px] py-[8px]">
|
||||||
<p class="leading-[32px] text-[14px]">
|
<p class="leading-[32px] text-[14px]">
|
||||||
您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
||||||
<div class="flex justify-end mt-[36px]">
|
<div class="flex justify-end mt-[36px]">
|
||||||
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
||||||
<el-button class="w-[100px] !h-[48px]" plain
|
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
|
||||||
@click="getAuthCodeDialog.hide()">关闭</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
@ -153,22 +139,19 @@
|
|||||||
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<el-form-item prop="auth_code">
|
<el-form-item prop="auth_code">
|
||||||
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')"
|
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
|
||||||
class="input-width" clearable size="large" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<el-form-item prop="auth_secret">
|
<el-form-item prop="auth_secret">
|
||||||
<el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')"
|
<el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
|
||||||
class="input-width" size="large" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
|
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
|
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t('confirm') }}</el-button>
|
||||||
@click="save(formRef)">{{ t('confirm') }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[10px] text-right">
|
<div class="mt-[10px] text-right">
|
||||||
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
||||||
@ -200,8 +183,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 安装弹窗 -->
|
<!-- 安装弹窗 -->
|
||||||
<el-dialog v-model="installShowDialog" :title="t('addonInstall')" width="850px" :close-on-click-modal="false"
|
<el-dialog v-model="installShowDialog" :title="t('addonInstall')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false" :before-close="installShowDialogClose">
|
||||||
:close-on-press-escape="false" :before-close="installShowDialogClose">
|
|
||||||
<el-steps :space="200" :active="installStep" finish-status="success" align-center>
|
<el-steps :space="200" :active="installStep" finish-status="success" align-center>
|
||||||
<el-step :title="t('envCheck')" class="flex-1" />
|
<el-step :title="t('envCheck')" class="flex-1" />
|
||||||
<el-step :title="t('installProgress')" class="flex-1" />
|
<el-step :title="t('installProgress')" class="flex-1" />
|
||||||
@ -224,8 +206,7 @@
|
|||||||
<span>{{ t('status') }}</span>
|
<span>{{ t('status') }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="pb-[10px] items pl-[15px]"
|
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
|
||||||
v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<span>{{ item.dir }}</span>
|
<span>{{ item.dir }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -241,8 +222,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="pb-[10px] items pl-[15px]"
|
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_write" :key="index">
|
||||||
v-for="(item, index) in installCheckResult.dir.is_write" :key="index">
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<span>{{ item.dir }}</span>
|
<span>{{ item.dir }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -265,21 +245,16 @@
|
|||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<el-tooltip effect="dark" :content="t('installTips')" placement="top">
|
<el-tooltip effect="dark" :content="t('installTips')" placement="top">
|
||||||
<el-button type="default" :disabled="!installCheckResult.is_pass || cloudInstalling"
|
<el-button type="default" :disabled="!installCheckResult.is_pass || cloudInstalling"
|
||||||
:loading="localInstalling" @click="handleInstall">{{
|
:loading="localInstalling" @click="handleInstall">{{ t('localInstall') }}</el-button>
|
||||||
t('localInstall')
|
|
||||||
}}</el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip effect="dark" :content="t('cloudInstallTips')" placement="top">
|
<el-tooltip effect="dark" :content="t('cloudInstallTips')" placement="top">
|
||||||
<el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling"
|
<el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling"
|
||||||
:loading="cloudInstalling" @click="handleCloudInstall">{{
|
:loading="cloudInstalling" @click="handleCloudInstall">{{ t('cloudInstall') }}</el-button>
|
||||||
t('cloudInstall')
|
|
||||||
}}</el-button>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="installStep == 2" class="h-[50vh] mt-[20px]">
|
<div v-show="installStep == 2" class="h-[50vh] mt-[20px]">
|
||||||
<terminal name="my-terminal" :context="currAddon" :init-log="null" :show-header="false"
|
<terminal name="my-terminal" :context="currAddon" :init-log="null" :show-header="false" :show-log-time="true" />
|
||||||
:show-log-time="true" />
|
|
||||||
</div>
|
</div>
|
||||||
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
|
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
|
||||||
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
|
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
|
||||||
@ -290,8 +265,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog v-model="uninstallShowDialog" :title="t('addonUninstall')" width="850px"
|
<el-dialog v-model="uninstallShowDialog" :title="t('addonUninstall')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false">
|
||||||
:close-on-click-modal="false" :close-on-press-escape="false">
|
|
||||||
<el-scrollbar max-height="50vh">
|
<el-scrollbar max-height="50vh">
|
||||||
<div class="min-h-[150px]">
|
<div class="min-h-[150px]">
|
||||||
<div class="bg-[#fff] my-3" v-if="uninstallCheckResult.dir">
|
<div class="bg-[#fff] my-3" v-if="uninstallCheckResult.dir">
|
||||||
@ -308,8 +282,7 @@
|
|||||||
<span>{{ t('status') }}</span>
|
<span>{{ t('status') }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="pb-[10px] items pl-[15px]"
|
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in uninstallCheckResult.dir.is_readable" :key="index">
|
||||||
v-for="(item, index) in uninstallCheckResult.dir.is_readable" :key="index">
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<span>{{ item.dir }}</span>
|
<span>{{ item.dir }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -325,8 +298,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="pb-[10px] items pl-[15px]"
|
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in uninstallCheckResult.dir.is_write" :key="index">
|
||||||
v-for="(item, index) in uninstallCheckResult.dir.is_write" :key="index">
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<span>{{ item.dir }}</span>
|
<span>{{ item.dir }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -348,6 +320,7 @@
|
|||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -74,8 +74,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('menuShortName')">
|
<el-form-item :label="t('menuShortName')">
|
||||||
<el-input v-model="formData.menu_short_name" :placeholder="t('menuShortNamePlaceholder')"
|
<el-input v-model="formData.menu_short_name" :placeholder="t('menuShortNamePlaceholder')" class="input-width" />
|
||||||
class="input-width" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('sort')">
|
<el-form-item :label="t('sort')">
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
|
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
v-loading="loading">
|
|
||||||
|
|
||||||
<el-form-item :label="t('accountNumber')" v-if="!formData.uid" prop="uid">
|
<el-form-item :label="t('accountNumber')" v-if="!formData.uid" prop="uid">
|
||||||
<el-select :model-value="uid" :placeholder="t('accountNumberPlaceholder')" class="input-width" filterable
|
<el-select :model-value="uid" :placeholder="t('accountNumberPlaceholder')" class="input-width" filterable clearable :allow-create="true" @change="selectUser" :default-first-option="true">
|
||||||
clearable :allow-create="true" @change="selectUser" :default-first-option="true">
|
|
||||||
<el-option v-for="item in userList" :key="item.uid" :label="item.username" :value="item.uid">
|
<el-option v-for="item in userList" :key="item.uid" :label="item.username" :value="item.uid">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<el-avatar :src="img(item.head_img)" size="small" class="mr-[10px]" v-if="item.head_img" />
|
<el-avatar :src="img(item.head_img)" size="small" class="mr-[10px]" v-if="item.head_img" />
|
||||||
@ -17,8 +15,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('accountNumber')" prop="username" v-else>
|
<el-form-item :label="t('accountNumber')" prop="username" v-else>
|
||||||
<el-input v-model="formData.username" :placeholder="t('accountNumberPlaceholder')" clearable
|
<el-input v-model="formData.username" :placeholder="t('accountNumberPlaceholder')" clearable :disabled="formData.uid" class="input-width" maxlength="10" show-word-limit />
|
||||||
:disabled="formData.uid" class="input-width" maxlength="10" show-word-limit />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div v-if="needAddUserInfo">
|
<div v-if="needAddUserInfo">
|
||||||
@ -27,26 +24,22 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('userRealName')" prop="real_name">
|
<el-form-item :label="t('userRealName')" prop="real_name">
|
||||||
<el-input v-model="formData.real_name" :placeholder="t('userRealNamePlaceholder')" clearable
|
<el-input v-model="formData.real_name" :placeholder="t('userRealNamePlaceholder')" clearable class="input-width" maxlength="10" show-word-limit />
|
||||||
class="input-width" maxlength="10" show-word-limit />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div v-if="!formData.uid">
|
<div v-if="!formData.uid">
|
||||||
<el-form-item :label="t('password')" prop="password">
|
<el-form-item :label="t('password')" prop="password">
|
||||||
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password"
|
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password" :show-password="true" clearable class="input-width" />
|
||||||
:show-password="true" clearable class="input-width" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
|
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
|
||||||
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')"
|
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')" type="password" :show-password="true" clearable class="input-width" />
|
||||||
type="password" :show-password="true" clearable class="input-width" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item :label="t('userRoleName')" prop="role_ids" v-if="!formData.userrole.is_admin">
|
<el-form-item :label="t('userRoleName')" prop="role_ids" v-if="!formData.userrole.is_admin">
|
||||||
<el-select v-model="formData.role_ids" :placeholder="t('userRolePlaceholder')" class="input-width" multiple
|
<el-select v-model="formData.role_ids" :placeholder="t('userRolePlaceholder')" class="input-width" multiple collapse-tags collapse-tags-tooltip>
|
||||||
collapse-tags collapse-tags-tooltip>
|
|
||||||
<el-option :label="item.role_name" :value="item.role_id" v-for="(item, index) in roles" :key="index" />
|
<el-option :label="item.role_name" :value="item.role_id" v-for="(item, index) in roles" :key="index" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -2,6 +2,9 @@
|
|||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-[16px]">
|
||||||
<el-form :inline="true" :model="sysUserLogTableData.searchParam" ref="searchFormRef">
|
<el-form :inline="true" :model="sysUserLogTableData.searchParam" ref="searchFormRef">
|
||||||
<el-form-item :label="t('ip')" prop="ip">
|
<el-form-item :label="t('ip')" prop="ip">
|
||||||
<el-input v-model="sysUserLogTableData.searchParam.ip" :placeholder="t('ipPlaceholder')" />
|
<el-input v-model="sysUserLogTableData.searchParam.ip" :placeholder="t('ipPlaceholder')" />
|
||||||
@ -57,7 +60,10 @@ import { t } from '@/lang'
|
|||||||
import { getLogList } from '@/app/api/site'
|
import { getLogList } from '@/app/api/site'
|
||||||
import UserLogDetail from '@/app/views/auth/components/user-log-detail.vue'
|
import UserLogDetail from '@/app/views/auth/components/user-log-detail.vue'
|
||||||
import { FormInstance } from 'element-plus'
|
import { FormInstance } from 'element-plus'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const pageName = route.meta.title
|
||||||
const sysUserLogTableData = reactive({
|
const sysUserLogTableData = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
|||||||
@ -3,9 +3,15 @@
|
|||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center mb-[20px]">
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
|
<div class="flex items-center">
|
||||||
<el-button type="primary" class="w-[100px]" @click="addEvent">
|
<el-button type="primary" class="w-[100px]" @click="addEvent">
|
||||||
{{ t('addMenu') }}
|
{{ t('addMenu') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button class="w-[100px]" @click="refreshMenu">
|
||||||
|
{{ t('initializeMenu') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading">
|
<el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading">
|
||||||
@ -47,8 +53,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref,h } from 'vue'
|
||||||
import { getMenus, deleteMenu } from '@/app/api/sys'
|
import { getMenus, deleteMenu,menuRefresh } from '@/app/api/sys'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||||
@ -74,6 +80,27 @@ const getMenuList = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
getMenuList()
|
getMenuList()
|
||||||
|
// 重置菜单
|
||||||
|
const refreshMenu = () => {
|
||||||
|
ElMessageBox.confirm(h('div', null, [
|
||||||
|
h('p', null, t('initializeMenuTipsOne')),
|
||||||
|
h('p', null, t('initializeMenuTipsTwo')),
|
||||||
|
]), t('warning'),
|
||||||
|
{
|
||||||
|
confirmButtonText: t('confirm'),
|
||||||
|
cancelButtonText: t('cancel'),
|
||||||
|
// type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
menusTableData.loading = true
|
||||||
|
menuRefresh({}).then(res => {
|
||||||
|
menusTableData.loading = false
|
||||||
|
}).catch(() => {
|
||||||
|
menusTableData.loading = false
|
||||||
|
})
|
||||||
|
}).catch(()=>{})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加菜单
|
* 添加菜单
|
||||||
|
|||||||
@ -2,9 +2,12 @@
|
|||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-[16px]">
|
||||||
<el-form :inline="true" :model="roleTableData.searchParam" ref="searchFormRef">
|
<el-form :inline="true" :model="roleTableData.searchParam" ref="searchFormRef">
|
||||||
<el-form-item :label="t('roleName')" prop="seach">
|
<el-form-item :label="t('roleName')" prop="search">
|
||||||
<el-input v-model="roleTableData.searchParam.seach" class="w-[240px]" :placeholder="t('roleNamePlaceholder')" />
|
<el-input v-model="roleTableData.searchParam.search" class="w-[240px]" :placeholder="t('roleNamePlaceholder')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="loadRoleList()">{{ t('search') }}</el-button>
|
<el-button type="primary" @click="loadRoleList()">{{ t('search') }}</el-button>
|
||||||
@ -51,7 +54,10 @@ import { t } from '@/lang'
|
|||||||
import { getRoleList, deleteRole } from '@/app/api/sys'
|
import { getRoleList, deleteRole } from '@/app/api/sys'
|
||||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||||
import EditRole from '@/app/views/auth/components/edit-role.vue'
|
import EditRole from '@/app/views/auth/components/edit-role.vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const pageName = route.meta.title
|
||||||
const roleTableData = reactive({
|
const roleTableData = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
@ -59,7 +65,7 @@ const roleTableData = reactive({
|
|||||||
loading: true,
|
loading: true,
|
||||||
data: [],
|
data: [],
|
||||||
searchParam: {
|
searchParam: {
|
||||||
seach: ''
|
search: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -80,7 +86,7 @@ const loadRoleList = (page: number = 1) => {
|
|||||||
getRoleList({
|
getRoleList({
|
||||||
page: roleTableData.page,
|
page: roleTableData.page,
|
||||||
limit: roleTableData.limit,
|
limit: roleTableData.limit,
|
||||||
role_name: roleTableData.searchParam.seach
|
role_name: roleTableData.searchParam.search
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
roleTableData.loading = false
|
roleTableData.loading = false
|
||||||
roleTableData.data = res.data.data
|
roleTableData.data = res.data.data
|
||||||
|
|||||||
@ -3,20 +3,23 @@
|
|||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
|
<div class="flex items-center">
|
||||||
<el-button type="primary" class="w-[100px]" @click="addEvent">
|
<el-button type="primary" class="w-[100px]" @click="addEvent">
|
||||||
{{ t('addMenu') }}
|
{{ t('addMenu') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button class="w-[100px]" @click="refreshMenu">
|
||||||
|
{{ t('initializeMenu') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-tabs v-model="active">
|
<el-tabs v-model="active">
|
||||||
<el-tab-pane :label="t('system')" name="system">
|
<el-tab-pane :label="t('system')" name="system">
|
||||||
<el-table :data="menusTableData.system" row-key="menu_key" size="large"
|
<el-table :data="menusTableData.system" row-key="menu_key" size="large" v-loading="menusTableData.loading">
|
||||||
v-loading="menusTableData.loading">
|
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
|
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')"
|
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')" min-width="150" />
|
||||||
min-width="150" />
|
|
||||||
<el-table-column :label="t('icon')" width="100" align="center">
|
<el-table-column :label="t('icon')" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<icon v-if="row.icon" :name="row.icon" size="18px" />
|
<icon v-if="row.icon" :name="row.icon" size="18px" />
|
||||||
@ -33,28 +36,24 @@
|
|||||||
<el-table-column :label="t('status')" min-width="120" align="center">
|
<el-table-column :label="t('status')" min-width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
|
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
|
||||||
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate')
|
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate') }}</el-tag>
|
||||||
}}</el-tag>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||||
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete')
|
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete') }}</el-button>
|
||||||
}}</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="t('application')" name="application">
|
<el-tab-pane :label="t('application')" name="application">
|
||||||
<el-table :data="menusTableData.application" row-key="menu_key" size="large"
|
<el-table :data="menusTableData.application" row-key="menu_key" size="large" v-loading="menusTableData.loading">
|
||||||
v-loading="menusTableData.loading">
|
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
|
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')"
|
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')" min-width="150" />
|
||||||
min-width="150" />
|
|
||||||
<el-table-column :label="t('icon')" width="100" align="center">
|
<el-table-column :label="t('icon')" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<icon v-if="row.icon" :name="row.icon" size="18px" />
|
<icon v-if="row.icon" :name="row.icon" size="18px" />
|
||||||
@ -71,16 +70,14 @@
|
|||||||
<el-table-column :label="t('status')" min-width="120" align="center">
|
<el-table-column :label="t('status')" min-width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
|
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
|
||||||
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate')
|
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate') }}</el-tag>
|
||||||
}}</el-tag>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||||
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete')
|
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete') }}</el-button>
|
||||||
}}</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -93,8 +90,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref,h } from 'vue'
|
||||||
import { getMenus, deleteMenu } from '@/app/api/sys'
|
import { getMenus, deleteMenu,menuRefresh } from '@/app/api/sys'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||||
@ -129,7 +126,27 @@ const getMenuList = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
getMenuList()
|
getMenuList()
|
||||||
|
// 重置菜单
|
||||||
|
const refreshMenu = () => {
|
||||||
|
ElMessageBox.confirm(h('div', null, [
|
||||||
|
h('p', null, t('initializeMenuTipsOne')),
|
||||||
|
h('p', null, t('initializeMenuTipsTwo')),
|
||||||
|
]), t('warning'),
|
||||||
|
{
|
||||||
|
confirmButtonText: t('confirm'),
|
||||||
|
cancelButtonText: t('cancel'),
|
||||||
|
// type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
menusTableData.loading = true
|
||||||
|
menuRefresh({}).then(res => {
|
||||||
|
menusTableData.loading = false
|
||||||
|
}).catch(() => {
|
||||||
|
menusTableData.loading = false
|
||||||
|
})
|
||||||
|
}).catch(()=>{})
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 添加菜单
|
* 添加菜单
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-[16px]">
|
||||||
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef">
|
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef">
|
||||||
<el-form-item :label="t('accountNumber')" prop="seach">
|
<el-form-item :label="t('accountNumber')" prop="seach">
|
||||||
<el-input v-model="userTableData.searchParam.seach" class="input-width"
|
<el-input v-model="userTableData.searchParam.seach" class="input-width" :placeholder="t('accountNumberPlaceholder')" />
|
||||||
:placeholder="t('accountNumberPlaceholder')" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="loadUserList()">{{ t('search') }}</el-button>
|
<el-button type="primary" @click="loadUserList()">{{ t('search') }}</el-button>
|
||||||
@ -56,10 +58,8 @@
|
|||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div v-if="row.is_admin != 1">
|
<div v-if="row.is_admin != 1">
|
||||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||||
<el-button type="primary" link @click="lockEvent(row.uid)" v-if="row.status">{{
|
<el-button type="primary" link @click="lockEvent(row.uid)" v-if="row.status">{{ t('lock') }}</el-button>
|
||||||
t('lock') }}</el-button>
|
<el-button type="primary" link @click="unlockEvent(row.uid)" v-else>{{ t('unlock') }}</el-button>
|
||||||
<el-button type="primary" link @click="unlockEvent(row.uid)" v-else>{{ t('unlock')
|
|
||||||
}}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-button link disabled>{{ t('adminDisabled') }}</el-button>
|
<el-button link disabled>{{ t('adminDisabled') }}</el-button>
|
||||||
@ -89,7 +89,10 @@ import EditUser from '@/app/views/auth/components/edit-user.vue'
|
|||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import type { FormInstance } from 'element-plus'
|
import type { FormInstance } from 'element-plus'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const pageName = route.meta.title
|
||||||
const userTableData = reactive({
|
const userTableData = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
|||||||
@ -100,15 +100,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 1">
|
<template #icon v-else-if="active == 1">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">1</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
1</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -118,9 +115,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<span class="text-[#999]">{{ t("weappAttest") }}</span>
|
<span class="text-[#999]">{{ t("weappAttest") }}</span>
|
||||||
<div class="mt-[20px] mb-[40px] h-[32px]">
|
<div class="mt-[20px] mb-[40px] h-[32px]">
|
||||||
<el-button type="primary"
|
<el-button type="primary" @click="linkEvent('https://open.alipay.com/develop/manage')">{{ t("clickAccess") }}</el-button>
|
||||||
@click="linkEvent('https://open.alipay.com/develop/manage')">{{ t("clickAccess")
|
|
||||||
}}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
@ -131,15 +126,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 2">
|
<template #icon v-else-if="active == 2">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">2</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
2</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -149,8 +141,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<span class="text-[#999]">{{ t("emplace") }}</span>
|
<span class="text-[#999]">{{ t("emplace") }}</span>
|
||||||
<div class="mt-[20px] mb-[40px] h-[32px]">
|
<div class="mt-[20px] mb-[40px] h-[32px]">
|
||||||
<el-button type="primary" plain
|
<el-button type="primary" plain @click="router.push('/channel/aliapp/config')">{{ t("weappSettingBtn") }}</el-button>
|
||||||
@click="router.push('/channel/aliapp/config')">{{ t("weappSettingBtn") }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
@ -161,15 +152,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 3">
|
<template #icon v-else-if="active == 3">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">3</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
3</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -191,15 +179,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 4">
|
<template #icon v-else-if="active == 4">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">4</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
4</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
|
|||||||
@ -13,8 +13,7 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('aliappSet') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('aliappSet') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('aliappName')">
|
<el-form-item :label="t('aliappName')">
|
||||||
<el-input v-model="formData.name" :placeholder="t('aliappNamePlaceholder')" class="input-width"
|
<el-input v-model="formData.name" :placeholder="t('aliappNamePlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('aliappQrcode')">
|
<el-form-item :label="t('aliappQrcode')">
|
||||||
@ -28,13 +27,11 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('aliappDevelopInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('aliappDevelopInfo') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('aliappOriginal')">
|
<el-form-item :label="t('aliappOriginal')">
|
||||||
<el-input v-model="formData.private_key" :placeholder="t('aliappOriginalPlaceholder')"
|
<el-input v-model="formData.private_key" :placeholder="t('aliappOriginalPlaceholder')" class="input-width" clearable />
|
||||||
class="input-width" clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('aliappAppid')">
|
<el-form-item :label="t('aliappAppid')">
|
||||||
<el-input v-model="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width"
|
<el-input v-model="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('countersignType')">
|
<el-form-item :label="t('countersignType')">
|
||||||
@ -67,8 +64,7 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
||||||
|
|
||||||
<el-form-item label="AESKey">
|
<el-form-item label="AESKey">
|
||||||
<el-input v-model="formData.aes_key" :placeholder="t('AESKeyPlaceholder')" class="input-width"
|
<el-input v-model="formData.aes_key" :placeholder="t('AESKeyPlaceholder')" class="input-width" show-word-limit clearable />
|
||||||
show-word-limit clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
|||||||
@ -12,13 +12,10 @@
|
|||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsOne1') }}--<el-button link
|
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsOne1') }}--<el-button link type="primary" @click="linkEvent">{{ t('alipayCourseTipsOne2') }}</el-button>, {{ t('alipayCourseTipsOne3') }}</p>
|
||||||
type="primary" @click="linkEvent">{{ t('alipayCourseTipsOne2') }}</el-button>, {{
|
|
||||||
t('alipayCourseTipsOne3') }}</p>
|
|
||||||
<div class="w-[100%] mt-[10px]">
|
<div class="w-[100%] mt-[10px]">
|
||||||
<img class="w-[100%]" src="@/app/assets/images/setting/alipay1.png" />
|
<img class="w-[100%]" src="@/app/assets/images/setting/alipay1.png" />
|
||||||
</div>
|
</div>
|
||||||
@ -33,8 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[40px]">
|
<div class="flex mt-[40px]">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsTwo2') }}</p>
|
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsTwo2') }}</p>
|
||||||
@ -71,8 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[40px]">
|
<div class="flex mt-[40px]">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<!-- <span class="text-primary">{{ t('alipayCourseTipsThree2') }}</span> -->
|
<!-- <span class="text-primary">{{ t('alipayCourseTipsThree2') }}</span> -->
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
|
<div class="flex ml-[18px] justify-between items-center pt-[20px]">
|
||||||
<span class="text-page-title">{{pageName}}</span>
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container" v-loading="loading">
|
<div class="main-container bg-[#fff] rounded-[4px]" v-loading="loading">
|
||||||
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
|
<div class="flex pl-[18px] justify-between items-center pt-[20px]">
|
||||||
<span class="text-page-title">{{pageName}}</span>
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form">
|
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form">
|
||||||
|
|||||||
@ -20,15 +20,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 1">
|
<template #icon v-else-if="active == 1">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">1</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
1</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -38,8 +35,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<span class="text-[#999]">{{ t("weappAttest") }}</span>
|
<span class="text-[#999]">{{ t("weappAttest") }}</span>
|
||||||
<div class="mt-[20px] mb-[40px] h-[32px]">
|
<div class="mt-[20px] mb-[40px] h-[32px]">
|
||||||
<el-button type="primary"
|
<el-button type="primary" @click="linkEvent('https://mp.weixin.qq.com/')">{{ t("clickAccess") }}</el-button>
|
||||||
@click="linkEvent('https://mp.weixin.qq.com/')">{{ t("clickAccess") }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
@ -50,15 +46,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 2">
|
<template #icon v-else-if="active == 2">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">2</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
2</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -68,8 +61,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<span class="text-[#999]">{{ t("emplace") }}</span>
|
<span class="text-[#999]">{{ t("emplace") }}</span>
|
||||||
<div class="mt-[20px] mb-[40px] h-[32px]">
|
<div class="mt-[20px] mb-[40px] h-[32px]">
|
||||||
<el-button type="primary" plain
|
<el-button type="primary" plain @click="router.push('/channel/weapp/config')">{{ t("weappSettingBtn") }}</el-button>
|
||||||
@click="router.push('/channel/weapp/config')">{{ t("weappSettingBtn") }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
@ -80,15 +72,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 3">
|
<template #icon v-else-if="active == 3">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">3</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
3</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
@ -98,8 +87,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
|
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
|
||||||
<div class="mt-[20px] mb-[40px] h-[32px]">
|
<div class="mt-[20px] mb-[40px] h-[32px]">
|
||||||
<el-button type="primary" plain
|
<el-button type="primary" plain @click="router.push('/channel/weapp/code')">{{ t("weappRelease") }}</el-button>
|
||||||
@click="router.push('/channel/weapp/code')">{{ t("weappRelease") }}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
@ -110,15 +98,12 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else-if="active == 4">
|
<template #icon v-else-if="active == 4">
|
||||||
<div
|
<div class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
||||||
class="w-[24px] h-[24px] box-border rounded-full bg-color1 flex items-center justify-center">
|
|
||||||
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
<div class="h-[12px] w-[12px] bg-color rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon v-else>
|
<template #icon v-else>
|
||||||
<div
|
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">4</div>
|
||||||
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
|
|
||||||
4</div>
|
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p class="text-[14px] text-[#303133] font-[700]">
|
<p class="text-[14px] text-[#303133] font-[700]">
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container min-h-[300px] p-5">
|
<div class="main-container min-h-[300px] p-5 bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex justify-between items-center mb-[20px]">
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -85,7 +85,6 @@ import { AnyObject } from '@/types/global'
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
// const activeNames = ref('1')
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const weappTableData:{
|
const weappTableData:{
|
||||||
page: number,
|
page: number,
|
||||||
|
|||||||
@ -8,19 +8,16 @@
|
|||||||
<span class="adorn">|</span>
|
<span class="adorn">|</span>
|
||||||
<span class="right">{{ pageName }}</span>
|
<span class="right">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" label-width="170px" ref="formRef" :rules="formRules" class="page-form"
|
<el-form :model="formData" label-width="170px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
v-loading="loading">
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<h3 class="panel-title !text-sm">{{ t('weappInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('weappInfo') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('weappName')" prop="weapp_name">
|
<el-form-item :label="t('weappName')" prop="weapp_name">
|
||||||
<el-input v-model.trim="formData.weapp_name" :placeholder="t('weappNamePlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.weapp_name" :placeholder="t('weappNamePlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('weappOriginal')" prop="weapp_original">
|
<el-form-item :label="t('weappOriginal')" prop="weapp_original">
|
||||||
<el-input v-model.trim="formData.weapp_original" :placeholder="t('weappOriginalPlaceholder')"
|
<el-input v-model.trim="formData.weapp_original" :placeholder="t('weappOriginalPlaceholder')" class="input-width" clearable />
|
||||||
class="input-width" clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('weappQrcode')" prop="qr_code">
|
<el-form-item :label="t('weappQrcode')" prop="qr_code">
|
||||||
@ -34,14 +31,12 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('weappDevelopInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('weappDevelopInfo') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('weappAppid')" prop="app_id">
|
<el-form-item :label="t('weappAppid')" prop="app_id">
|
||||||
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
<div class="form-tip">{{ t('weappAppidTips') }}</div>
|
<div class="form-tip">{{ t('weappAppidTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('weappAppsecret')" prop="app_secret">
|
<el-form-item :label="t('weappAppsecret')" prop="app_secret">
|
||||||
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
<div class="form-tip">{{ t('weappAppsecretTips') }}</div>
|
<div class="form-tip">{{ t('weappAppsecretTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -63,8 +58,7 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
||||||
|
|
||||||
<el-form-item label="URL">
|
<el-form-item label="URL">
|
||||||
<el-input :model-value="formData.serve_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="formData.serve_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(formData.serve_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(formData.serve_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
@ -72,8 +66,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Token" prop="token">
|
<el-form-item label="Token" prop="token">
|
||||||
<el-input v-model.trim="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width" maxlength="32" show-word-limit clearable />
|
||||||
maxlength="32" show-word-limit clearable />
|
|
||||||
<div class="form-tip">{{ t('tokenTips') }}</div>
|
<div class="form-tip">{{ t('tokenTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -101,32 +94,28 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item :label="t('requestUrl')">
|
<el-form-item :label="t('requestUrl')">
|
||||||
<el-input :model-value="formData.request_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="formData.request_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('socketUrl')">
|
<el-form-item :label="t('socketUrl')">
|
||||||
<el-input :model-value="formData.socket_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="formData.socket_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(formData.socket_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(formData.socket_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('uploadUrl')">
|
<el-form-item :label="t('uploadUrl')">
|
||||||
<el-input :model-value="formData.upload_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="formData.upload_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(formData.upload_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(formData.upload_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('downloadUrl')">
|
<el-form-item :label="t('downloadUrl')">
|
||||||
<el-input :model-value="formData.download_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="formData.download_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(formData.download_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(formData.download_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -12,12 +12,10 @@
|
|||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}<el-button link type="primary"
|
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}<el-button link type="primary" @click="linkEvent">{{ t("writingTipsOne2") }}</el-button>,{{ t('writingTipsOne3') }}</p>
|
||||||
@click="linkEvent">{{ t("writingTipsOne2") }}</el-button>,{{ t('writingTipsOne3') }}</p>
|
|
||||||
<div class="w-[100%] mt-[10px]">
|
<div class="w-[100%] mt-[10px]">
|
||||||
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_1.png" />
|
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_1.png" />
|
||||||
</div>
|
</div>
|
||||||
@ -25,8 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[40px]">
|
<div class="flex mt-[40px]">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
|
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
|
||||||
@ -37,12 +34,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[40px]">
|
<div class="flex mt-[40px]">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span class="text-primary">{{
|
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span class="text-primary">{{ t('writingTipsThree2') }}</span></p>
|
||||||
t('writingTipsThree2') }}</span></p>
|
|
||||||
<div class="w-[100%] mt-[10px]">
|
<div class="w-[100%] mt-[10px]">
|
||||||
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_3.png" />
|
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_3.png" />
|
||||||
</div>
|
</div>
|
||||||
@ -50,8 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[40px]">
|
<div class="flex mt-[40px]">
|
||||||
<div class="min-w-[60px]">
|
<div class="min-w-[60px]">
|
||||||
<span
|
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">4</span>
|
||||||
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">4</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="flex items-center text-[14px]">{{ t('writingTipsFour1') }}<span class="text-primary">URL /
|
<p class="flex items-center text-[14px]">{{ t('writingTipsFour1') }}<span class="text-primary">URL /
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container p-5">
|
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex justify-between items-center mb-[20px]">
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -49,8 +49,7 @@
|
|||||||
|
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="200">
|
<el-table-column :label="t('operation')" fixed="right" align="right" width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="infoSwitch(row)">{{ row.is_weapp == 1 ? t('close') :
|
<el-button type="primary" link @click="infoSwitch(row)">{{ row.is_weapp == 1 ? t('close') : t('open') }}</el-button>
|
||||||
t('open') }}</el-button>
|
|
||||||
<el-button type="primary" link @click="batchAcquisitionFn(row)">{{ t('regain') }}</el-button>
|
<el-button type="primary" link @click="batchAcquisitionFn(row)">{{ t('regain') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
||||||
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
||||||
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
||||||
|
<el-tab-pane :label="t('reply')" name="/channel/wechat/reply" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="p-[20px]">
|
<div class="p-[20px]">
|
||||||
<p class="text-[16px] mb-[20px]">{{ t("wechatInlet") }}</p>
|
<p class="text-[16px] mb-[20px]">{{ t("wechatInlet") }}</p>
|
||||||
|
|||||||
63
admin/src/app/views/channel/wechat/components/news-card.vue
Normal file
63
admin/src/app/views/channel/wechat/components/news-card.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="attachment-item text-sm mr-[10px] mb-[10px] w-[280px] rounded-lg overflow-hidden border border-color" v-if="data">
|
||||||
|
<div class="relative" @mouseover="hover = true" @mouseout="hover = false">
|
||||||
|
<div class="w-full h-[130px] relative">
|
||||||
|
<el-image :src="data.value.news_item[0].thumb_url" class="w-full h-full"/>
|
||||||
|
<div class="absolute left-0 bottom-0 p-[10px] w-full truncate text-white leading-none" v-if="data.value.news_item.length > 1">
|
||||||
|
{{ data.value.news_item[0].title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="data.value.news_item.length > 1">
|
||||||
|
<template v-for="(newsItem, newsIndex) in data.value.news_item">
|
||||||
|
<div class="px-[15px] py-[10px] flex" :class="{'border-b border-color' : newsIndex < data.value.news_item.length - 1 }" v-if="newsIndex > 0">
|
||||||
|
<div class="flex-1 w-0 truncate">
|
||||||
|
{{ newsItem.title }}
|
||||||
|
</div>
|
||||||
|
<div class="w-[50px] h-[50px] ml-[10px]">
|
||||||
|
<el-image :src="newsItem.thumb_url" class="w-full h-full"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="px-[15px] py-[10px]" v-else>
|
||||||
|
{{ data.value.news_item[0].title }}
|
||||||
|
</div>
|
||||||
|
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60 cursor-pointer" @click="data = null" v-show="hover && props.mode == 'select'">
|
||||||
|
<icon name="element-Delete" color="#fff" size="40px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'select'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const hover = ref(false)
|
||||||
|
const data = computed({
|
||||||
|
get () {
|
||||||
|
return props.modelValue
|
||||||
|
},
|
||||||
|
set (value) {
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const meta = document.createElement('meta')
|
||||||
|
meta.content = 'same-origin'
|
||||||
|
meta.name = 'referrer'
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(meta)
|
||||||
|
</script>
|
||||||
294
admin/src/app/views/channel/wechat/components/reply-form.vue
Normal file
294
admin/src/app/views/channel/wechat/components/reply-form.vue
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
<template>
|
||||||
|
<div class="border border-br-light rounded">
|
||||||
|
<div class="py-[10px] px-[30px] flex text-sm border-0 border-b border-br-light text-tx-regular">
|
||||||
|
<div class="pr-[25px] cursor-pointer flex items-center" :class="{'text-primary': formData.msgtype == 'text'}"
|
||||||
|
@click="switchMsgType('text')">
|
||||||
|
<icon name="iconfont-iconxingzhuang-wenzi" size="18" class="mr-[5px]"/>
|
||||||
|
文本
|
||||||
|
</div>
|
||||||
|
<div class="pr-[25px] cursor-pointer flex items-center" :class="{'text-primary': formData.msgtype == 'image'}"
|
||||||
|
@click="switchMsgType('image')">
|
||||||
|
<icon name="iconfont-icontupian" size="18px" class="mr-[5px]"/>
|
||||||
|
图片
|
||||||
|
</div>
|
||||||
|
<div class="pr-[25px] cursor-pointer flex items-center" :class="{'text-primary': formData.msgtype == 'video'}"
|
||||||
|
@click="switchMsgType('video')">
|
||||||
|
<icon name="iconfont-iconshipin1" size="18" class="mr-[5px]"/>
|
||||||
|
视频
|
||||||
|
</div>
|
||||||
|
<div class="pr-[25px] cursor-pointer flex items-center" :class="{'text-primary': formData.msgtype == 'mpnewsarticle'}"
|
||||||
|
@click="switchMsgType('mpnewsarticle')">
|
||||||
|
<icon name="iconfont-icontuwendaohang2" size="13px" class="mr-[5px]"/>
|
||||||
|
图文
|
||||||
|
</div>
|
||||||
|
<div class="pr-[25px] cursor-pointer flex items-center" :class="{'text-primary': formData.msgtype == 'miniprogrampage'}"
|
||||||
|
@click="switchMsgType('miniprogrampage')">
|
||||||
|
<icon name="iconfont-iconxiaochengxu" size="14px" class="mr-[5px]"/>
|
||||||
|
小程序卡片
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-[20px] px-[30px] h-[350px]">
|
||||||
|
<div v-if="formData.msgtype == 'text'">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.text.content" :rows="5" type="textarea" placeholder="" maxlength="600" :show-word-limit="true"
|
||||||
|
resize="none"
|
||||||
|
input-style="box-shadow: none;height:300px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="formData.msgtype == 'image'" class="flex w-full h-full justify-center items-center image-media">
|
||||||
|
<div class="w-full h-full" v-if="formData.image.url">
|
||||||
|
<upload-image :limit="1" width="150px" height="150px" v-model="formData.image.url"/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex w-full h-full justify-center items-center image-media">
|
||||||
|
<div class="flex flex-1 h-full border border-br-light cursor-pointer select-media">
|
||||||
|
<select-wechat-media type="image" @success="setImageMedia">
|
||||||
|
<div class="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">从素材库选择</div>
|
||||||
|
</div>
|
||||||
|
</select-wechat-media>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 h-full ml-[20px] border border-br-light cursor-pointer">
|
||||||
|
<upload-media type="image" class="w-full h-full flex items-center justify-center" @success="setImageMedia">
|
||||||
|
<div class="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">上传图片</div>
|
||||||
|
</div>
|
||||||
|
</upload-media>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="formData.msgtype == 'video'" class="flex w-full h-full justify-center items-center video-media">
|
||||||
|
<div class="w-full h-full" v-if="formData.video.url">
|
||||||
|
<upload-video :limit="1" width="150px" height="150px" v-model="formData.video.url"/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex w-full h-full justify-center items-center video-media">
|
||||||
|
<div class="flex flex-1 h-full border border-br-light cursor-pointer select-media">
|
||||||
|
<select-wechat-media type="video" @success="setVideoMedia">
|
||||||
|
<div class="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">从素材库选择</div>
|
||||||
|
</div>
|
||||||
|
</select-wechat-media>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 h-full ml-[20px] border border-br-light cursor-pointer">
|
||||||
|
<upload-media type="video" class="w-full h-full flex items-center justify-center" @success="setVideoMedia">
|
||||||
|
<div class="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">上传视频</div>
|
||||||
|
</div>
|
||||||
|
</upload-media>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="formData.msgtype == 'mpnewsarticle'" class="flex w-full h-full justify-center items-center image-media">
|
||||||
|
<div class="w-full h-full" v-if="formData.mpnewsarticle">
|
||||||
|
<news-card v-model="formData.mpnewsarticle"/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex w-full h-full justify-center items-center image-media">
|
||||||
|
<div class="flex flex-1 h-full border border-br-light cursor-pointer select-media">
|
||||||
|
<select-wechat-media type="news" @success="setNewsMedia">
|
||||||
|
<div class="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">从素材库选择</div>
|
||||||
|
</div>
|
||||||
|
</select-wechat-media>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="formData.msgtype == 'miniprogrampage'">
|
||||||
|
<el-form :model="formData.miniprogrampage" label-width="140px" class="page-form" ref="formRef" :rules="formRules">
|
||||||
|
<el-form-item label="小程序APPID" prop="appid">
|
||||||
|
<el-input v-model="formData.miniprogrampage.appid" class="input-width"/>
|
||||||
|
<div class="form-tip">小程序需已经与公众号关联</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="小程序卡片标题" prop="title">
|
||||||
|
<el-input v-model="formData.miniprogrampage.title" class="input-width"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="小程序的页面路径" prop="pagepath">
|
||||||
|
<el-input v-model="formData.miniprogrampage.pagepath" class="input-width"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="小程序卡片图片" prop="thumb_media_url">
|
||||||
|
<upload-image :limit="1" width="100px" height="100px" v-model="formData.miniprogrampage.thumb_media_url" v-if="formData.miniprogrampage.thumb_media_url"/>
|
||||||
|
<select-wechat-media type="image" @success="setWeappImageMedia" v-else>
|
||||||
|
<div class="rounded cursor-pointer overflow-hidden relative border border-solid border-color image-wrap mr-[10px] w-[100px] h-[100px]">
|
||||||
|
<div class="w-full h-full flex items-center justify-center flex-col content-wrap">
|
||||||
|
<icon name="element-Plus" size="20px" color="var(--el-text-color-secondary)" />
|
||||||
|
<div class="leading-none text-xs mt-[10px] text-secondary">{{ t('upload.root') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</select-wechat-media>
|
||||||
|
<div class="form-tip">小程序卡片图片建议大小为520*416</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, reactive, ref, watch } from 'vue'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import UploadMedia from '@/app/views/channel/wechat/components/upload-media.vue'
|
||||||
|
import SelectWechatMedia from '@/app/views/channel/wechat/components/select-wechat-media.vue'
|
||||||
|
import Test from '@/utils/test'
|
||||||
|
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||||
|
import NewsCard from '@/app/views/channel/wechat/components/news-card.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
msgtype: 'text',
|
||||||
|
text: {
|
||||||
|
content: ''
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
media_id: '',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
video: {
|
||||||
|
media_id: '',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
miniprogrampage: {
|
||||||
|
appid: '',
|
||||||
|
title: '',
|
||||||
|
pagepath: '',
|
||||||
|
thumb_media_url: '',
|
||||||
|
thumb_media_id: ''
|
||||||
|
},
|
||||||
|
mpnewsarticle: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const value = computed({
|
||||||
|
get () {
|
||||||
|
return props.modelValue
|
||||||
|
},
|
||||||
|
set (value) {
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => value.value, (nval, oval) => {
|
||||||
|
if ((!oval || !Object.keys(oval).length) && Object.keys(nval).length) {
|
||||||
|
formData.value = value.value
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
watch(() => formData.value, () => {
|
||||||
|
value.value = formData.value
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
const switchMsgType = (type: string) => {
|
||||||
|
formData.value.msgtype = type
|
||||||
|
}
|
||||||
|
|
||||||
|
const setImageMedia = (data: any) => {
|
||||||
|
formData.value.image.media_id = data.media_id
|
||||||
|
formData.value.image.url = data.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const setVideoMedia = (data: any) => {
|
||||||
|
formData.value.video.media_id = data.media_id
|
||||||
|
formData.value.video.url = data.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const setWeappImageMedia = (data: any) => {
|
||||||
|
formData.value.miniprogrampage.thumb_media_id = data.media_id
|
||||||
|
formData.value.miniprogrampage.thumb_media_url = data.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const setNewsMedia = (data: any) => {
|
||||||
|
formData.value.mpnewsarticle = {
|
||||||
|
article_id: data.media_id,
|
||||||
|
value: data.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const formRules = reactive<FormRules>({
|
||||||
|
appid: [
|
||||||
|
{ required: true, message: '请填写小程序appid', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
title: [
|
||||||
|
{ required: true, message: '请填写小程序卡片标题', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
pagepath: [
|
||||||
|
{ required: true, message: '请填写小程序卡片跳转页面', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
thumb_media_url: [
|
||||||
|
{ required: true, message: '请上传小程序卡片封面', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证数据
|
||||||
|
*/
|
||||||
|
const verify = async () => {
|
||||||
|
let verify = true
|
||||||
|
switch (formData.value.msgtype) {
|
||||||
|
case 'text':
|
||||||
|
if (Test.empty(formData.value.text.content)) {
|
||||||
|
ElMessage({ message: '请输入回复内容', type: 'warning' })
|
||||||
|
verify = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'image':
|
||||||
|
if (Test.empty(formData.value.image.url)) {
|
||||||
|
ElMessage({ message: '请上传回复图片', type: 'warning' })
|
||||||
|
verify = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'video':
|
||||||
|
if (Test.empty(formData.value.video.url)) {
|
||||||
|
ElMessage({ message: '请上传回复视频', type: 'warning' })
|
||||||
|
verify = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'miniprogrampage':
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
verify = valid
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'mpnewsarticle':
|
||||||
|
if (Test.empty(formData.value.mpnewsarticle)) {
|
||||||
|
ElMessage({ message: '请选择图文', type: 'warning' })
|
||||||
|
verify = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return verify
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
verify
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.image-media, .video-media) {
|
||||||
|
.el-upload {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.select-media) {
|
||||||
|
& > div {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,219 @@
|
|||||||
|
<template>
|
||||||
|
<div @click="openDialog">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDialog" :title="t('upload.select' + type)" width="60%" class="attachment-dialog"
|
||||||
|
:destroy-on-close="true">
|
||||||
|
<div class="flex border-t border-b main-wrap border-color w-full h-[40vh]">
|
||||||
|
<!-- 素材 -->
|
||||||
|
<div class="attachment-list-wrap flex flex-col p-[15px] flex-1 overflow-hidden">
|
||||||
|
<el-row :gutter="15" class="h-[32px]">
|
||||||
|
<el-col :span="10">
|
||||||
|
<div class="flex" v-if="prop.type != 'news'">
|
||||||
|
<upload-media :type="prop.type" @success="getAttachmentList()">
|
||||||
|
<el-button type="primary">{{ t('upload.upload' + type) }}</el-button>
|
||||||
|
</upload-media>
|
||||||
|
</div>
|
||||||
|
<div class="flex" v-else>
|
||||||
|
<el-button type="primary" :loading="syncLoading" @click="syncWechatNews">{{ syncLoading ? '同步中' : '同步微信图文'}}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="flex-1 my-[15px] h-0" v-loading="attachment.loading">
|
||||||
|
<el-scrollbar>
|
||||||
|
<!-- 素材管理 -->
|
||||||
|
<div v-if="attachment.data.length">
|
||||||
|
<div class="flex flex-wrap" v-if="prop.type != 'news'">
|
||||||
|
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data"
|
||||||
|
:key="index" @click="selectedFile = item">
|
||||||
|
<div
|
||||||
|
class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
|
||||||
|
<el-image :src="img(item.value)" fit="contain" v-if="type == 'image'"
|
||||||
|
:preview-src-list="item.image_list" />
|
||||||
|
<video :src="img(item.value)" v-else-if="type == 'video'"></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.id == item.id">
|
||||||
|
<icon name="element-Select" color="#fff" size="40px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative" ref="waterfallContainerRef" v-else>
|
||||||
|
<div ref="waterfallItemRef" class="absolute attachment-item mr-[10px] mb-[10px] w-[280px] rounded-lg overflow-hidden border border-color" v-for="(item, index) in attachment.data"
|
||||||
|
:style="{ left: listPosition[index] ? listPosition[index].left : '', top: listPosition[index] ? listPosition[index].top : '' }"
|
||||||
|
:key="index" @click="selectedFile = item">
|
||||||
|
<div class="relative">
|
||||||
|
<div class="w-full h-[130px] relative">
|
||||||
|
<el-image :src="item.value.news_item[0].thumb_url" class="w-full h-full"/>
|
||||||
|
<div class="absolute left-0 bottom-0 p-[10px] w-full truncate text-white leading-none" v-if="item.value.news_item.length > 1">
|
||||||
|
{{ item.value.news_item[0].title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="item.value.news_item.length > 1">
|
||||||
|
<template v-for="(newsItem, newsIndex) in item.value.news_item">
|
||||||
|
<div class="px-[15px] py-[10px] flex" :class="{'border-b border-color' : newsIndex < item.value.news_item.length - 1 }" v-if="newsIndex > 0">
|
||||||
|
<div class="flex-1 w-0 truncate">
|
||||||
|
{{ newsItem.title }}
|
||||||
|
</div>
|
||||||
|
<div class="w-[50px] h-[50px] ml-[10px]">
|
||||||
|
<el-image :src="newsItem.thumb_url" class="w-full h-full"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="px-[15px] py-[10px]" v-else>
|
||||||
|
{{ item.value.news_item[0].title }}
|
||||||
|
</div>
|
||||||
|
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60" v-show="selectedFile.id == item.id">
|
||||||
|
<icon name="element-Select" color="#fff" size="40px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-center" v-else>
|
||||||
|
<el-empty v-if="!attachment.loading"
|
||||||
|
:description="t('upload.mediaEmpty')"
|
||||||
|
:image-size="100" />
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col span="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, 30, 40, 60]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper" :total="attachment.total"
|
||||||
|
@size-change="getAttachmentList()" @current-change="getAttachmentList" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 { reactive, ref, nextTick } from 'vue'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import UploadMedia from './upload-media.vue'
|
||||||
|
import { img, debounce } from '@/utils/common'
|
||||||
|
import { getMediaList, syncNews } from '@/app/api/wechat'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'image'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const showDialog = ref(false)
|
||||||
|
|
||||||
|
const openDialog = () => {
|
||||||
|
prop.type == 'news' && waterfall()
|
||||||
|
showDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachment: Record<string, any> = reactive({
|
||||||
|
loading: true,
|
||||||
|
page: 1,
|
||||||
|
total: 0,
|
||||||
|
limit: 10,
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询素材
|
||||||
|
*/
|
||||||
|
const getAttachmentList = (page: number = 1) => {
|
||||||
|
attachment.loading = true
|
||||||
|
attachment.page = page
|
||||||
|
getMediaList({
|
||||||
|
page: attachment.page,
|
||||||
|
limit: attachment.limit,
|
||||||
|
type: prop.type
|
||||||
|
}).then(res => {
|
||||||
|
attachment.data = res.data.data
|
||||||
|
attachment.total = res.data.total
|
||||||
|
attachment.loading = false
|
||||||
|
prop.type == 'news' && waterfall()
|
||||||
|
}).catch(() => {
|
||||||
|
attachment.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getAttachmentList()
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
const selectedFile: Record<string, any> = ref({})
|
||||||
|
|
||||||
|
const confirm = () => {
|
||||||
|
emits('success', selectedFile.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncLoading = ref(false)
|
||||||
|
const syncWechatNews = () => {
|
||||||
|
if (syncLoading.value) return
|
||||||
|
syncLoading.value = true
|
||||||
|
|
||||||
|
syncNews().then(() => {
|
||||||
|
syncLoading.value = false
|
||||||
|
getAttachmentList()
|
||||||
|
}).catch(() => {
|
||||||
|
syncLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = document.createElement('meta')
|
||||||
|
meta.content = 'same-origin'
|
||||||
|
meta.name = 'referrer'
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(meta)
|
||||||
|
|
||||||
|
// 瀑布流计算
|
||||||
|
const waterfallContainerRef = ref(null)
|
||||||
|
const waterfallItemRef = ref([])
|
||||||
|
const listPosition = ref([])
|
||||||
|
const waterfall = debounce(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
const containerWidth = waterfallContainerRef.value.clientWidth
|
||||||
|
const column = parseInt(containerWidth / 292)
|
||||||
|
const heights = []
|
||||||
|
const positions = []
|
||||||
|
|
||||||
|
waterfallItemRef.value.forEach((item, i) => {
|
||||||
|
if (i < column) {
|
||||||
|
const position = {}
|
||||||
|
position.top = '0px'
|
||||||
|
if (i % column == 0) {
|
||||||
|
position.left = item.clientWidth * i + "px"
|
||||||
|
} else {
|
||||||
|
position.left = item.clientWidth * i + (i % column * 10) + "px"
|
||||||
|
}
|
||||||
|
positions[i] = position
|
||||||
|
heights[i] = item.clientHeight + 10
|
||||||
|
} else {
|
||||||
|
let minHeight = Math.min(...heights) // 找到第一列的最小高度
|
||||||
|
let minIndex = heights.findIndex(item => item ===
|
||||||
|
minHeight) // 找到最小高度的索引
|
||||||
|
let position = {}
|
||||||
|
position.top = minHeight + 10 + "px"
|
||||||
|
position.left = positions[minIndex].left
|
||||||
|
positions[i] = position
|
||||||
|
heights[minIndex] += item.clientHeight + 10
|
||||||
|
}
|
||||||
|
})
|
||||||
|
listPosition.value = positions
|
||||||
|
})
|
||||||
|
}, 800)
|
||||||
|
|
||||||
|
// 重新布局,以适应窗口变化
|
||||||
|
window.addEventListener('resize', () => waterfall())
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<el-upload v-bind="upload" ref="uploadRef">
|
||||||
|
<slot></slot>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts' setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { getToken } from '@/utils/common'
|
||||||
|
import storage from '@/utils/storage'
|
||||||
|
import { ElMessage, UploadFile, UploadFiles } from 'element-plus'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'image'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
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}/wechat/media/${prop.type}`,
|
||||||
|
multiple: true,
|
||||||
|
headers,
|
||||||
|
accept: prop.type == 'image' ? '.bmp,.png,.jpeg,.jpg,.gif' : '.mp4',
|
||||||
|
onSuccess: (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||||
|
if (response.code >= 1) {
|
||||||
|
emits('success', response.data)
|
||||||
|
uploadRef.value?.handleRemove(uploadFile)
|
||||||
|
} else {
|
||||||
|
uploadFile.status = 'fail'
|
||||||
|
uploadRef.value?.handleRemove(uploadFile)
|
||||||
|
ElMessage({ message: response.msg, type: 'error' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -9,19 +9,16 @@
|
|||||||
<span class="right">{{ pageName }}</span>
|
<span class="right">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form"
|
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
v-loading="loading">
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<h3 class="panel-title !text-sm">{{ t('wechatInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('wechatInfo') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('wechatName')" prop="wechat_name">
|
<el-form-item :label="t('wechatName')" prop="wechat_name">
|
||||||
<el-input v-model.trim="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('wechatOriginal')" prop="wechat_original">
|
<el-form-item :label="t('wechatOriginal')" prop="wechat_original">
|
||||||
<el-input v-model.trim="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')"
|
<el-input v-model.trim="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')" class="input-width" clearable />
|
||||||
class="input-width" clearable />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('wechatQrcode')" prop="qr_code">
|
<el-form-item :label="t('wechatQrcode')" prop="qr_code">
|
||||||
@ -35,14 +32,12 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('wechatDevelopInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('wechatDevelopInfo') }}</h3>
|
||||||
|
|
||||||
<el-form-item :label="t('wechatAppid')" prop="app_id">
|
<el-form-item :label="t('wechatAppid')" prop="app_id">
|
||||||
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
<div class="form-tip">{{ t('wechatAppidTips') }}</div>
|
<div class="form-tip">{{ t('wechatAppidTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('wechatAppsecret')" prop="app_secret">
|
<el-form-item :label="t('wechatAppsecret')" prop="app_secret">
|
||||||
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
|
||||||
clearable />
|
|
||||||
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
|
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -52,8 +47,7 @@
|
|||||||
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
|
||||||
|
|
||||||
<el-form-item label="URL">
|
<el-form-item label="URL">
|
||||||
<el-input :model-value="wechatStatic.serve_url" placeholder="Please input" class="input-width"
|
<el-input :model-value="wechatStatic.serve_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(wechatStatic.serve_url)">{{ t('copy') }}</div>
|
<div class="cursor-pointer" @click="copyEvent(wechatStatic.serve_url)">{{ t('copy') }}</div>
|
||||||
</template>
|
</template>
|
||||||
@ -61,14 +55,12 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Token" prop="token">
|
<el-form-item label="Token" prop="token">
|
||||||
<el-input v-model.trim="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width"
|
<el-input v-model.trim="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width" maxlength="32" show-word-limit clearable />
|
||||||
maxlength="32" show-word-limit clearable />
|
|
||||||
<div class="form-tip">{{ t('tokenTips') }}</div>
|
<div class="form-tip">{{ t('tokenTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="EncodingAESKey" prop="encoding_aes_key">
|
<el-form-item label="EncodingAESKey" prop="encoding_aes_key">
|
||||||
<el-input v-model.trim="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')"
|
<el-input v-model.trim="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')" class="input-width" maxlength="43" show-word-limit clearable />
|
||||||
class="input-width" maxlength="43" show-word-limit clearable />
|
|
||||||
<div class="form-tip">{{ t('encodingAESKeyTips') }}</div>
|
<div class="form-tip">{{ t('encodingAESKeyTips') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -94,8 +86,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('businessDomain')">
|
<el-form-item :label="t('businessDomain')">
|
||||||
<el-input :model-value="wechatStatic.business_domain" placeholder="Please input" class="input-width"
|
<el-input :model-value="wechatStatic.business_domain" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
||||||
</div>
|
</div>
|
||||||
@ -104,8 +95,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('jsSecureDomain')">
|
<el-form-item :label="t('jsSecureDomain')">
|
||||||
<el-input :model-value="wechatStatic.js_secure_domain" placeholder="Please input" class="input-width"
|
<el-input :model-value="wechatStatic.js_secure_domain" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
||||||
</div>
|
</div>
|
||||||
@ -114,8 +104,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('webAuthDomain')">
|
<el-form-item :label="t('webAuthDomain')">
|
||||||
<el-input :model-value="wechatStatic.web_auth_domain" placeholder="Please input" class="input-width"
|
<el-input :model-value="wechatStatic.web_auth_domain" placeholder="Please input" class="input-width" :readonly="true">
|
||||||
:readonly="true">
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
178
admin/src/app/views/channel/wechat/keyword_reply_edit.vue
Normal file
178
admin/src/app/views/channel/wechat/keyword_reply_edit.vue
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main-container">
|
||||||
|
<div class="detail-head">
|
||||||
|
<div class="left" @click="router.push({ path: '/channel/wechat/reply' })">
|
||||||
|
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
|
||||||
|
<span class="ml-[1px]">{{ t('returnToPreviousPage') }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="adorn">|</span>
|
||||||
|
<span class="right">{{ pageName }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
|
|
||||||
|
<el-form-item :label="t('ruleName')" prop="name">
|
||||||
|
<el-input v-model.trim="formData.name" :placeholder="t('ruleNamePlaceholder')" class="input-width" clearable maxlength="60"/>
|
||||||
|
<div class="form-tip">{{ t('ruleNameTips') }}</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="t('keyword')" prop="keyword">
|
||||||
|
<el-input v-model.trim="formData.keyword" :placeholder="t('keywordPlaceholder')" class="input-width" clearable >
|
||||||
|
<template #prepend>
|
||||||
|
<el-select v-model="formData.matching_type" placeholder="Select" style="width: 115px">
|
||||||
|
<el-option :label="t('allMatching')" value="full" />
|
||||||
|
<el-option :label="t('fuzzyMatching')" value="like" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="t('content')" prop="content">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex items-center" v-for="(item, index) in formData.content">
|
||||||
|
<div class="w-[300px] bg-page p-[10px] mr-[10px] mb-[10px] rounded leading-none" v-if="item.msgtype == 'text'">
|
||||||
|
{{ item.text.content }}
|
||||||
|
</div>
|
||||||
|
<div class="w-[300px] bg-page p-[10px] mr-[10px] mb-[10px] rounded" v-if="item.msgtype == 'image'">
|
||||||
|
<upload-image :limit="1" width="120px" height="120px" v-model="item.image.url"/>
|
||||||
|
</div>
|
||||||
|
<div class="w-[300px] bg-page p-[10px] mr-[10px] mb-[10px] rounded" v-if="item.msgtype == 'video'">
|
||||||
|
<upload-video :limit="1" width="120px" height="120px" v-model="item.video.url"/>
|
||||||
|
</div>
|
||||||
|
<div class="w-[300px] bg-page p-[10px] mr-[10px] mb-[10px] rounded" v-if="item.msgtype == 'mpnewsarticle'">
|
||||||
|
<news-card v-model="item.mpnewsarticle" mode="show"/>
|
||||||
|
</div>
|
||||||
|
<div class="w-[300px] bg-page p-[10px] mr-[10px] mb-[10px] rounded" v-if="item.msgtype == 'miniprogrampage'">
|
||||||
|
小程序卡片【{{ item.miniprogrampage.appid }}】
|
||||||
|
</div>
|
||||||
|
<icon name="element-Delete" class="cursor-pointer" @click="removeContent(index)"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-[10px]">
|
||||||
|
<el-button type="primary" @click="showDialog = true">{{ t('addReplyContent') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="t('replyMethod')" prop="reply_method">
|
||||||
|
<el-radio-group v-model="formData.reply_method">
|
||||||
|
<el-radio label="all">{{ t('replyMethodAll') }}</el-radio>
|
||||||
|
<el-radio label="rand">{{ t('replyMethodRand') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="fixed-footer-wrap">
|
||||||
|
<div class="fixed-footer">
|
||||||
|
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="showDialog" :title="t('addReplyContent')" width="60%"
|
||||||
|
:destroy-on-close="true">
|
||||||
|
<reply-form v-model="replyContent" ref="ReplyRef"/>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="addReplyContent">{{ t('confirm') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import { getKeywordsReplyInfo, editKeywordsReply, addKeywordsReply } from '@/app/api/wechat'
|
||||||
|
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import ReplyForm from '@/app/views/channel/wechat/components/reply-form.vue'
|
||||||
|
import NewsCard from '@/app/views/channel/wechat/components/news-card.vue'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const pageName = route.meta.title
|
||||||
|
const showDialog = ref(false)
|
||||||
|
|
||||||
|
const formData = reactive<Record<string, string>>({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
keyword: '',
|
||||||
|
content: [],
|
||||||
|
matching_type: 'full',
|
||||||
|
reply_method: 'all'
|
||||||
|
})
|
||||||
|
|
||||||
|
const replyContent = ref({})
|
||||||
|
const ReplyRef = ref(null)
|
||||||
|
|
||||||
|
const addReplyContent = () => {
|
||||||
|
ReplyRef.value?.verify().then(res => {
|
||||||
|
if (res) {
|
||||||
|
formData.content.push(replyContent.value)
|
||||||
|
replyContent.value = {}
|
||||||
|
showDialog.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeContent = (index: number) => {
|
||||||
|
formData.content.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const formRules = reactive<FormRules>({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: t('ruleNamePlaceholder'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
keyword: [
|
||||||
|
{ required: true, message: t('keywordPlaceholder'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
|
if (!formData.content.length) callback(new Error(t('contentPlaceholder')))
|
||||||
|
callback()
|
||||||
|
}, trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
if (route.query.id) {
|
||||||
|
getKeywordsReplyInfo(route.query.id).then(({ data }) => {
|
||||||
|
Object.keys(formData).forEach((key: string) => {
|
||||||
|
if (data[key] != undefined) formData[key] = data[key]
|
||||||
|
})
|
||||||
|
loading.value = false
|
||||||
|
}).catch()
|
||||||
|
} else {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存
|
||||||
|
*/
|
||||||
|
const save = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (loading.value || !formEl) return
|
||||||
|
|
||||||
|
await formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const api = formData.id ? editKeywordsReply : addKeywordsReply
|
||||||
|
loading.value = true
|
||||||
|
api(formData).then(() => {
|
||||||
|
loading.value = false
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container p-5">
|
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex justify-between items-center mb-[20px]">
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -7,6 +7,7 @@
|
|||||||
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
||||||
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
||||||
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
||||||
|
<el-tab-pane :label="t('reply')" name="/channel/wechat/reply" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="flex" v-loading="loading">
|
<div class="flex" v-loading="loading">
|
||||||
<div class="preview-wrap w-[300px] h-[550px] mr-[16px] bg-overlay rounded-md flex flex-col justify-between border border-color">
|
<div class="preview-wrap w-[300px] h-[550px] mr-[16px] bg-overlay rounded-md flex flex-col justify-between border border-color">
|
||||||
|
|||||||
@ -1,8 +1,183 @@
|
|||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div class="w-full p-5 bg-body">
|
||||||
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
|
<span class="text-page-title">{{ t('title') }}</span>
|
||||||
|
</div>
|
||||||
|
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
|
||||||
|
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
||||||
|
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
||||||
|
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
||||||
|
<el-tab-pane :label="t('reply')" name="/channel/wechat/reply" />
|
||||||
|
</el-tabs>
|
||||||
|
<div class="py-[20px]">
|
||||||
|
<el-radio-group v-model="replyType" style="margin-bottom: 30px">
|
||||||
|
<el-radio-button label="keyword">{{ t('keywordReply') }}</el-radio-button>
|
||||||
|
<el-radio-button label="default">{{ t('defaultReply') }}</el-radio-button>
|
||||||
|
<el-radio-button label="subscribe">{{ t('subscribeReply') }}</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<div v-show="replyType == 'keyword'">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<el-button type="primary" @click="addKeywordsReply">新建回复</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-[10px]">
|
||||||
|
<el-table :data="replyTableData.data" size="large" v-loading="replyTableData.loading">
|
||||||
|
<template #empty>
|
||||||
|
<span>{{ !replyTableData.loading ? t('emptyData') : '' }}</span>
|
||||||
|
</template>
|
||||||
|
<el-table-column prop="name" label="规则名称" min-width="120" />
|
||||||
|
<el-table-column prop="keyword" label="关键字" min-width="120" />
|
||||||
|
<el-table-column label="匹配规则" min-width="150" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.matching_type == 'full' ? '全匹配' : '模糊匹配' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="回复方式" min-width="150" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.reply_method == 'all' ? '全部回复' : '随机回复一条' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" link @click="editKeywordsReply(row)">{{ t('edit') }}</el-button>
|
||||||
|
<el-button type="primary" link @click="deleteKeyword(row)">{{ t('delete') }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="mt-[16px] flex justify-end">
|
||||||
|
<el-pagination v-model:current-page="replyTableData.page" v-model:page-size="replyTableData.limit"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper" :total="replyTableData.total"
|
||||||
|
@size-change="loadKeywordsReplyList()" @current-change="loadKeywordsReplyList" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="replyType == 'default'">
|
||||||
|
<reply-form v-model="defaultReply" ref="defaultReplyRef"/>
|
||||||
|
<div class="mt-[20px]">
|
||||||
|
<el-button type="primary" :loading="loading" @click="save()">{{ t('save') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="replyType == 'subscribe'">
|
||||||
|
<reply-form v-model="subscribeReply" ref="subscribeReplyRef"/>
|
||||||
|
<div class="mt-[20px]">
|
||||||
|
<el-button type="primary" :loading="loading" @click="save()">{{ t('save') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import {
|
||||||
|
getKeywordsReplyList,
|
||||||
|
getDefaultReply,
|
||||||
|
getSubscribeReply,
|
||||||
|
setDefaultReply,
|
||||||
|
setSubscribeReply,
|
||||||
|
delKeywordsReply
|
||||||
|
} from '@/app/api/wechat'
|
||||||
|
import ReplyForm from '@/app/views/channel/wechat/components/reply-form.vue'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const activeName = ref('/channel/wechat/reply')
|
||||||
|
const replyType = ref('keyword')
|
||||||
|
|
||||||
|
const addKeywordsReply = () => {
|
||||||
|
router.push('/channel/wechat/keyword_reply_edit')
|
||||||
|
}
|
||||||
|
|
||||||
|
const editKeywordsReply = (row: Object) => {
|
||||||
|
router.push('/channel/wechat/keyword_reply_edit?id=' + row.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除菜单
|
||||||
|
*/
|
||||||
|
const deleteKeyword = (row: Object) => {
|
||||||
|
ElMessageBox.confirm(t('replyDeleteTips'), t('warning'),
|
||||||
|
{
|
||||||
|
confirmButtonText: t('confirm'),
|
||||||
|
cancelButtonText: t('cancel'),
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
delKeywordsReply(row.id).then(() => {
|
||||||
|
loadKeywordsReplyList()
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleClick = (val: any) => {
|
||||||
|
router.push({ path: activeName.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultReply = ref({})
|
||||||
|
const subscribeReply = ref({})
|
||||||
|
|
||||||
|
getDefaultReply().then(({ data }) => {
|
||||||
|
data.length != 0 && (defaultReply.value = data.content)
|
||||||
|
}).catch()
|
||||||
|
|
||||||
|
getSubscribeReply().then(({ data }) => {
|
||||||
|
data.length != 0 && (subscribeReply.value = data.content)
|
||||||
|
}).catch()
|
||||||
|
|
||||||
|
const defaultReplyRef = ref(null)
|
||||||
|
const subscribeReplyRef = ref(null)
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
let verify = true,
|
||||||
|
api,
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
switch (replyType.value) {
|
||||||
|
case 'default':
|
||||||
|
await defaultReplyRef.value?.verify().then(res => {
|
||||||
|
verify = res
|
||||||
|
})
|
||||||
|
api = setDefaultReply
|
||||||
|
data = defaultReply.value
|
||||||
|
break
|
||||||
|
case 'subscribe':
|
||||||
|
await subscribeReplyRef.value?.verify().then(res => {
|
||||||
|
verify = res
|
||||||
|
})
|
||||||
|
api = setSubscribeReply
|
||||||
|
data = subscribeReply.value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (verify) {
|
||||||
|
api({content: data}).then(() => {}).catch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const replyTableData = reactive({
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
total: 0,
|
||||||
|
loading: true,
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadKeywordsReplyList = (page: number = 1) => {
|
||||||
|
replyTableData.loading = true
|
||||||
|
replyTableData.page = page
|
||||||
|
|
||||||
|
getKeywordsReplyList({
|
||||||
|
page: replyTableData.page,
|
||||||
|
limit: replyTableData.limit
|
||||||
|
}).then(res => {
|
||||||
|
replyTableData.loading = false
|
||||||
|
replyTableData.data = res.data.data
|
||||||
|
replyTableData.total = res.data.total
|
||||||
|
}).catch(() => {
|
||||||
|
replyTableData.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loadKeywordsReplyList()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container p-5">
|
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex justify-between items-center mb-[20px]">
|
<div class="flex justify-between items-center mb-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -7,6 +7,7 @@
|
|||||||
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
|
||||||
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
<el-tab-pane :label="t('customMenu')" name="/channel/wechat/menu" />
|
||||||
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
<el-tab-pane :label="t('wechatTemplate')" name="/channel/wechat/message" />
|
||||||
|
<el-tab-pane :label="t('reply')" name="/channel/wechat/reply" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
|
|||||||
@ -247,7 +247,7 @@ import { ElTable } from 'element-plus'
|
|||||||
import Sortable from 'sortablejs'
|
import Sortable from 'sortablejs'
|
||||||
import { range } from 'lodash-es'
|
import { range } from 'lodash-es'
|
||||||
|
|
||||||
import { getDiyPageList } from '@/app/api/diy'
|
import { getDiyPageListByCarouselSearch } from '@/app/api/diy'
|
||||||
|
|
||||||
const diyStore = useDiyStore()
|
const diyStore = useDiyStore()
|
||||||
diyStore.editComponent.ignore = ['componentBgColor','componentBgUrl','marginTop','marginBottom','topRounded','bottomRounded','pageBgColor','marginBoth'] // 忽略公共属性
|
diyStore.editComponent.ignore = ['componentBgColor','componentBgUrl','marginTop','marginBottom','topRounded','bottomRounded','pageBgColor','marginBoth'] // 忽略公共属性
|
||||||
@ -394,7 +394,6 @@ const diyPageTable = reactive({
|
|||||||
loading: true,
|
loading: true,
|
||||||
data: [],
|
data: [],
|
||||||
searchParam: {
|
searchParam: {
|
||||||
type: 'DIY_PAGE' // todo 数据筛选,要考虑只能查询 微页面类型的数据
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const diyPageTableRef = ref<InstanceType<typeof ElTable>>()
|
const diyPageTableRef = ref<InstanceType<typeof ElTable>>()
|
||||||
@ -406,7 +405,7 @@ const loadDiyPageList = (page: number = 1) => {
|
|||||||
diyPageTable.loading = true
|
diyPageTable.loading = true
|
||||||
diyPageTable.page = page
|
diyPageTable.page = page
|
||||||
|
|
||||||
getDiyPageList({
|
getDiyPageListByCarouselSearch({
|
||||||
page: diyPageTable.page,
|
page: diyPageTable.page,
|
||||||
limit: diyPageTable.limit,
|
limit: diyPageTable.limit,
|
||||||
...diyPageTable.searchParam
|
...diyPageTable.searchParam
|
||||||
@ -419,7 +418,7 @@ const loadDiyPageList = (page: number = 1) => {
|
|||||||
// 排除当前编辑的微页面以及存在 置顶组件的数据
|
// 排除当前编辑的微页面以及存在 置顶组件的数据
|
||||||
if (diyStore.id) {
|
if (diyStore.id) {
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
if (data[i].id == diyStore.id || data[i].value.indexOf('top_fixed') != -1) {
|
if (data[i].id == diyStore.id) {
|
||||||
isExistCount++;
|
isExistCount++;
|
||||||
} else {
|
} else {
|
||||||
newData.push(data[i]);
|
newData.push(data[i]);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap mt-[20px] min-w-[1200px]" v-if="page.use_template">
|
<div class="flex flex-wrap pt-[20px] min-w-[1200px] bg-[#fff] rounded-[4px]" v-if="page.use_template">
|
||||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap mt-[20px] min-w-[1200px]" v-if="page.use_template">
|
<div class="flex flex-wrap pt-[20px] min-w-[1200px] bg-[#fff] rounded-[4px]" v-if="page.use_template">
|
||||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||||
|
|
||||||
|
|||||||
@ -165,7 +165,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref, watch } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { getAccountList, getAccountStat, getAccountType } from '@/app/api/site'
|
import { getAccountList, getAccountStat, getAccountType } from '@/app/api/site'
|
||||||
import type { FormInstance } from 'element-plus'
|
import type { FormInstance } from 'element-plus'
|
||||||
@ -191,6 +191,11 @@ const siteAccountLogTable = reactive({
|
|||||||
|
|
||||||
const searchFormRef = ref<FormInstance>()
|
const searchFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
// 去空操作
|
||||||
|
watch(() => siteAccountLogTable.searchParam.trade_no, (nval) => {
|
||||||
|
siteAccountLogTable.searchParam.trade_no = nval.trim();
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取站点账单记录列表
|
* 获取站点账单记录列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between items-center py-[24px] pl-[62px] pr-[64px] home-head">
|
<div class="flex justify-between items-center py-[24px] pl-[62px] pr-[64px] home-head">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center" v-if="webConfig">
|
||||||
<img class="w-[32x] h-[32px] rounded-full" v-if="webConfig.icon" :src="img(webConfig.icon)" alt="">
|
<img class="w-[32x] h-[32px] rounded-full" v-if="webConfig.icon" :src="img(webConfig.icon)" alt="">
|
||||||
<img class="w-[32x] h-[32px] rounded-full" v-else src="@/app/assets/images/icon-addon.png" alt="">
|
<img class="w-[32x] h-[32px] rounded-full" v-else src="@/app/assets/images/icon-addon.png" alt="">
|
||||||
<span class="ml-[10px] text-[16px] font-bold">{{webConfig.site_name}}</span>
|
<span class="ml-[10px] text-[16px] font-bold">{{webConfig.site_name}}</span>
|
||||||
@ -71,12 +71,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref, toRefs } from 'vue'
|
import { reactive, ref, toRefs, computed } from 'vue'
|
||||||
import { Search } from '@element-plus/icons-vue'
|
import { Search } from '@element-plus/icons-vue'
|
||||||
import { getHomeSite } from '@/app/api/home'
|
import { getHomeSite } from '@/app/api/home'
|
||||||
import { getWebConfig } from '@/app/api/sys'
|
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import { getInstalledAddonList } from '@/app/api/addon'
|
import { getInstalledAddonList } from '@/app/api/addon'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
@ -138,24 +138,12 @@ const cutAppFn = (app:any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 网络设置
|
// 网络设置
|
||||||
const webConfig = ref({
|
const webConfig = computed(() => useSystemStore().website)
|
||||||
icon: '',
|
|
||||||
site_name: ''
|
|
||||||
})
|
|
||||||
const getWebConfigFn = () => {
|
|
||||||
getWebConfig().then(res => {
|
|
||||||
webConfig.value = res.data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getWebConfigFn()
|
|
||||||
|
|
||||||
const selectSite = (site: any) => {
|
const selectSite = (site: any) => {
|
||||||
storage.set({ key: 'siteId', data: site.site_id })
|
storage.set({ key: 'siteId', data: site.site_id })
|
||||||
storage.set({ key: 'siteInfo', data: site })
|
storage.set({ key: 'siteInfo', data: site })
|
||||||
storage.set({ key: 'comparisonSiteIdStorage', data: site.site_id })
|
storage.set({ key: 'comparisonSiteIdStorage', data: site.site_id })
|
||||||
useUserStore().$patch((site) => {
|
|
||||||
site.siteInfo = site
|
|
||||||
})
|
|
||||||
location.href = `${location.origin}/site/`
|
location.href = `${location.origin}/site/`
|
||||||
}
|
}
|
||||||
const logoutFn = () => {
|
const logoutFn = () => {
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
|
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
|
||||||
<span class="text-page-title">{{ t('editPersonal') }}</span>
|
|
||||||
</div>
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
|
||||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
|
|
||||||
<el-form-item :label="t('headImg')">
|
|
||||||
<upload-image v-model="saveInfo.head_img" :limit="1" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('userName')">
|
|
||||||
<span>{{saveInfo.username}}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('realName')">
|
|
||||||
<el-input v-model="saveInfo.real_name" :placeholder="t('realNamePlaceholder')" clearable class="input-width" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div class="flex justify-center mt-[50px]">
|
|
||||||
<el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button>
|
|
||||||
<el-button type="primary" @click="returnFn()">{{ t('cancel') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { t } from '@/lang'
|
|
||||||
import type { FormInstance } from 'element-plus'
|
|
||||||
|
|
||||||
import { getUserInfo, setUserInfo } from '@/app/api/personal'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
// 提交信息
|
|
||||||
const saveInfo = reactive({
|
|
||||||
head_img: '',
|
|
||||||
real_name: '',
|
|
||||||
username: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
const loading = ref(true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
const getUserInfoFn = () => {
|
|
||||||
loading.value = true
|
|
||||||
getUserInfo().then(res => {
|
|
||||||
loading.value = false
|
|
||||||
const data = res.data
|
|
||||||
saveInfo.head_img = data.head_img
|
|
||||||
saveInfo.real_name = data.real_name
|
|
||||||
saveInfo.username = data.username
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getUserInfoFn()
|
|
||||||
|
|
||||||
const submitForm = (formEl: FormInstance | undefined) => {
|
|
||||||
if (loading.value || !formEl) return
|
|
||||||
formEl.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
setUserInfo(saveInfo).then((res: any) => {
|
|
||||||
loading.value = false
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const returnFn = () => {
|
|
||||||
router.push('/user/center')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
:deep(.personal-body){
|
|
||||||
background-color: #fff;
|
|
||||||
.el-form-item__content{
|
|
||||||
.el-input{
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
.el-form-item__content{
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.el-button{
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
.personal-option{
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<!-- eslint-disable no-undef -->
|
<!-- eslint-disable no-undef -->
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-[#FAFAFA] box-border pb-[77px]">
|
<div v-loading="loading">
|
||||||
<div class="main-container" v-loading="loading">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="pt-[60px]">
|
<div class="">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="text-[24px] font-600 text-[#242424] leading-[33px]">欢迎使用niucloud-admin</span>
|
<span class="text-[24px] font-600 text-[#242424] leading-[33px]">欢迎使用niucloud-admin</span>
|
||||||
<div class="ml-[12px] bg-[#333] flex items-center py-[3px] px-[6px] rounded">
|
<div class="ml-[12px] bg-[#333] flex items-center py-[3px] px-[6px] rounded">
|
||||||
@ -36,7 +36,6 @@
|
|||||||
<span class="text-[12px] text-[#666] leading-[16px]">{{ time }}</span>
|
<span class="text-[12px] text-[#666] leading-[16px]">{{ time }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<div @click="toHref('site/list','1')" class="cursor-pointer">
|
<div @click="toHref('site/list','1')" class="cursor-pointer">
|
||||||
@ -138,7 +137,6 @@
|
|||||||
<div ref="siteStat" :style="{ width: '100%', height: '300px' }"></div>
|
<div ref="siteStat" :style="{ width: '100%', height: '300px' }"></div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-card class="box-card !border-none mt-[15px] site" shadow="never" :body-style="{ marginTop: '13px' }">
|
<el-card class="box-card !border-none mt-[15px] site" shadow="never" :body-style="{ marginTop: '13px' }">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@ -160,7 +158,7 @@
|
|||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -334,9 +332,6 @@ const toUpgrade = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-container {
|
|
||||||
margin: 0 84px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.profile-data .el-card__header) {
|
:deep(.profile-data .el-card__header) {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|||||||
@ -1,102 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
|
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
|
||||||
<span class="text-page-title">{{ t('personal') }}</span>
|
|
||||||
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span>
|
|
||||||
</div>
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
|
||||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
|
|
||||||
<el-form-item :label="t('headImg')">
|
|
||||||
<el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain">
|
|
||||||
<template #error>
|
|
||||||
<div
|
|
||||||
class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full">
|
|
||||||
<el-icon class="!text-[#fff] !text-[45px]">
|
|
||||||
<UserFilled />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-image>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('userName')">
|
|
||||||
<div>{{ saveInfo.username }}</div>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('realName')">
|
|
||||||
<div>{{ saveInfo.real_name }}</div>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { t } from '@/lang'
|
|
||||||
import type { FormInstance } from 'element-plus'
|
|
||||||
import { img } from '@/utils/common'
|
|
||||||
import { getUserInfo } from '@/app/api/personal'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
// 提交信息
|
|
||||||
const saveInfo = reactive({
|
|
||||||
head_img: '',
|
|
||||||
real_name: '',
|
|
||||||
original_password: '',
|
|
||||||
password: '',
|
|
||||||
password_copy: '',
|
|
||||||
username: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
const loading = ref(true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
const getUserInfoFn = () => {
|
|
||||||
loading.value = true
|
|
||||||
getUserInfo().then(res => {
|
|
||||||
loading.value = false
|
|
||||||
|
|
||||||
const data = res.data
|
|
||||||
saveInfo.head_img = data.head_img
|
|
||||||
saveInfo.real_name = data.real_name
|
|
||||||
saveInfo.original_password = data.original_password
|
|
||||||
saveInfo.password = data.password
|
|
||||||
saveInfo.password_copy = data.password
|
|
||||||
saveInfo.username = data.username
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getUserInfoFn()
|
|
||||||
|
|
||||||
// 编辑个人中心
|
|
||||||
const toEditPersonal = () => {
|
|
||||||
router.push('/user/edit_center')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
:deep(.personal-body) {
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
.el-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.personal-option {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
@ -245,7 +245,11 @@ watch(copied, () => {
|
|||||||
body {
|
body {
|
||||||
background: #edf0f3;
|
background: #edf0f3;
|
||||||
}
|
}
|
||||||
|
.main-container{
|
||||||
|
overflow: inherit !important;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
.copy {
|
.copy {
|
||||||
background: var(--el-color-primary) !important;
|
background: var(--el-color-primary) !important;
|
||||||
color: var(--el-color-white) !important;
|
color: var(--el-color-white) !important;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pt-[59px] px-[20px] app-store" v-loading="authLoading">
|
<div class="box-border main-container">
|
||||||
<div>
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
<div class="flex justify-between items-center h-[32px] mb-4">
|
||||||
<span class="text-page-title text-[#222]">{{ t('localAppText') }}</span>
|
<span class="text-page-title text-[#222]">{{ t('localAppText') }}</span>
|
||||||
<el-input class="!w-[250px]" :placeholder="t('search')" v-model="search_name" @keyup.enter="query">
|
<el-input class="!w-[250px]" :placeholder="t('search')" v-model="search_name" @keyup.enter="query">
|
||||||
@ -11,28 +11,28 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mt-[24px] justify-between">
|
<div class="flex my-[10px] justify-between">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[15px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'installed' }]"
|
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[20px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'installed' }]"
|
||||||
@click="activeNameTabFn('installed')">
|
@click="activeNameTabFn('installed')">
|
||||||
{{ t('installLabel') }}
|
{{ t('installLabel') }}
|
||||||
</div>
|
</div>
|
||||||
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[15px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'uninstalled' }]"
|
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[20px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'uninstalled' }]"
|
||||||
@click="activeNameTabFn('uninstalled')">
|
@click="activeNameTabFn('uninstalled')">
|
||||||
{{ t('uninstalledLabel') }}
|
{{ t('uninstalledLabel') }}
|
||||||
</div>
|
</div>
|
||||||
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[15px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'all' }]"
|
<div :class="['flex items-center text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[20px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]', { 'text-[#fff] !bg-[#000] border-[#000]': activeName === 'all' }]"
|
||||||
@click="activeNameTabFn('all')">
|
@click="activeNameTabFn('all')">
|
||||||
{{ t('buyLabel') }}
|
{{ t('buyLabel') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="['flex items-center text-white text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-primary rounded-full px-[15px] cursor-pointer bg-primary hover:bg-primary']"
|
<div :class="['flex items-center text-white text-[14px] h-[32px] border-[1px] border-solid my-[3px] border-primary rounded-full px-[20px] cursor-pointer bg-primary hover:bg-primary']"
|
||||||
@click="handleCloudBuild">
|
@click="handleCloudBuild">
|
||||||
{{ t('cloudBuild') }}
|
{{ t('cloudBuild') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[25px]">
|
<div class="min-h-[300px]" v-loading="authLoading">
|
||||||
<el-table v-if="localList[activeName].length" :data="info[activeName]" size="large" class="pt-[5px]">
|
<el-table v-if="localList[activeName].length&&!authLoading" :data="info[activeName]" size="large" class="pt-[5px]">
|
||||||
<el-table-column :label="t('appName')" align="left" width="320">
|
<el-table-column :label="t('appName')" align="left" width="320">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center cursor-pointer" @click = "handleTips">
|
<div class="flex items-center cursor-pointer" @click = "handleTips">
|
||||||
@ -110,7 +110,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-empty class="mx-auto overview-empty"
|
<el-empty class="mx-auto overview-empty"
|
||||||
v-if="!localList.installed.length && !loading && activeName == 'installed'">
|
v-if="!localList.installed.length && !loading && activeName == 'installed'&&!authLoading">
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
@ -121,7 +121,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</el-empty>
|
||||||
<el-empty class="mx-auto overview-empty"
|
<el-empty class="mx-auto overview-empty"
|
||||||
v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
|
v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'&&!authLoading">
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
@ -135,7 +135,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</el-empty>
|
||||||
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'"
|
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'&&!authLoading"
|
||||||
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
||||||
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
||||||
<div class="flex flex-1 flex-wrap justify-center relative">
|
<div class="flex flex-1 flex-wrap justify-center relative">
|
||||||
@ -161,7 +161,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-empty class="mx-auto overview-empty"
|
<el-empty class="mx-auto overview-empty"
|
||||||
v-if="!localList.all.length && !loading && authinfo && activeName == 'all'">
|
v-if="!localList.all.length && !loading && authinfo && activeName == 'all'&&!authLoading">
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
@ -384,7 +384,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<upgrade ref="upgradeRef" @complete="localListFn"/>
|
<upgrade ref="upgradeRef" @complete="localListFn"/>
|
||||||
@ -855,10 +855,11 @@ const checkAppMange = () => {
|
|||||||
authLoading.value = true
|
authLoading.value = true
|
||||||
getAuthinfo()
|
getAuthinfo()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
authLoading.value = false
|
||||||
if (res.data.data && res.data.data.length != 0) {
|
if (res.data.data && res.data.data.length != 0) {
|
||||||
authinfo.value = res.data.data
|
authinfo.value = res.data.data
|
||||||
}
|
}
|
||||||
authLoading.value = false
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
authLoading.value = false
|
authLoading.value = false
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="box-border pt-[64px]">
|
<div class="box-border main-container pt-[20px]">
|
||||||
<div class="text-page-title text-[#222] mb-[32px] pl-[14px]">工具管理</div>
|
<div class="text-page-title text-[#222] mb-[16px] pl-[20px]">工具管理</div>
|
||||||
<div class="flex flex-wrap mt-[28px]">
|
<div class="flex flex-wrap">
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/addon')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/addon')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">插件开发</span>
|
<span class="text-[16px] text-[#222] font-bold">插件开发</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/addon_develop.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/addon_develop.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/code')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/code')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">代码生成</span>
|
<span class="text-[16px] text-[#222] font-bold">代码生成</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/code.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/code.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/list')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/list')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">数据字典</span>
|
<span class="text-[16px] text-[#222] font-bold">数据字典</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -29,16 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/sys_dict_list.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/sys_dict_list.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/update')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/detection')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
|
||||||
<span class="text-[16px] text-[#222] font-bold">更新缓存</span>
|
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
|
||||||
更新缓存
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<img src="@/app/assets/images/tools/tools_Update_cache.png" class="w-[256px] h-[128px]" />
|
|
||||||
</div>
|
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/detection')">
|
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">环境监测</span>
|
<span class="text-[16px] text-[#222] font-bold">环境监测</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -47,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/tools_check_environment.png" class="w-[256px] h-[128px] cursor-pointer" />
|
<img src="@/app/assets/images/tools/tools_check_environment.png" class="w-[256px] h-[128px] cursor-pointer" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/schedule')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/schedule')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">计划任务</span>
|
<span class="text-[16px] text-[#222] font-bold">计划任务</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -56,7 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/tools_schedule.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/tools_schedule.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/authorize')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/authorize')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">授权信息</span>
|
<span class="text-[16px] text-[#222] font-bold">授权信息</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -65,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/app_auth.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/app_auth.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/admin_menu')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/admin_menu')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">平台菜单</span>
|
<span class="text-[16px] text-[#222] font-bold">平台菜单</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -74,7 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/site_menu')">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/site_menu')">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">站点菜单</span>
|
<span class="text-[16px] text-[#222] font-bold">站点菜单</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -83,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="developerDialogVisible = true">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="developerDialogVisible = true">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">开发模式</span>
|
<span class="text-[16px] text-[#222] font-bold">开发模式</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
@ -92,7 +83,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<img src="@/app/assets/images/tools/developer.png" class="w-[256px] h-[128px]" />
|
<img src="@/app/assets/images/tools/developer.png" class="w-[256px] h-[128px]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="goRouter">
|
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="goRouter">
|
||||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||||
<span class="text-[16px] text-[#222] font-bold">官方市场</span>
|
<span class="text-[16px] text-[#222] font-bold">官方市场</span>
|
||||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||||
|
|||||||
@ -127,7 +127,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { computed, reactive, ref, watch } from 'vue'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
@ -135,7 +135,9 @@ import storage from '@/utils/storage'
|
|||||||
import { getLoginConfig } from '@/app/api/auth'
|
import { getLoginConfig } from '@/app/api/auth'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import { setWindowTitle, img, getAppType } from '@/utils/common'
|
import { setWindowTitle, img, getAppType } from '@/utils/common'
|
||||||
import { getWebConfig, getWebCopyright } from '@/app/api/sys'
|
import { getWebCopyright } from '@/app/api/sys'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import Test from '@/utils/test'
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const imgLoading = ref(false)
|
const imgLoading = ref(false)
|
||||||
@ -150,20 +152,17 @@ getWebCopyright().then(({ data }) => {
|
|||||||
|
|
||||||
route.redirectedFrom && (route.query.redirect = route.redirectedFrom.path)
|
route.redirectedFrom && (route.query.redirect = route.redirectedFrom.path)
|
||||||
|
|
||||||
const webSite = ref({})
|
const webSite = computed(() => useSystemStore().website)
|
||||||
const setFormData = async (id: number = 0) => {
|
|
||||||
webSite.value = await (await getWebConfig()).data
|
|
||||||
}
|
|
||||||
setFormData()
|
|
||||||
|
|
||||||
// 判断登录页面[平台或者站点]
|
// 判断登录页面[平台或者站点]
|
||||||
const loginType = ref(getAppType())
|
const loginType = ref(getAppType())
|
||||||
|
|
||||||
|
watch(() => webSite.value, () => {
|
||||||
if (loginType.value == 'site') {
|
if (loginType.value == 'site') {
|
||||||
setWindowTitle(t('siteLogin'))
|
setWindowTitle(webSite.value.site_name+'-'+t('siteLogin'))
|
||||||
} else {
|
} else {
|
||||||
setWindowTitle(t('adminLogin'))
|
setWindowTitle(webSite.value.site_name+'-'+t('adminLogin'))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 验证码 - start
|
// 验证码 - start
|
||||||
const verifyRef = ref(null)
|
const verifyRef = ref(null)
|
||||||
@ -215,7 +214,11 @@ const loginFn = (data = {}) => {
|
|||||||
storage.set({ key: 'app_type', data: loginType.value })
|
storage.set({ key: 'app_type', data: loginType.value })
|
||||||
const { query: { redirect } } = route
|
const { query: { redirect } } = route
|
||||||
const path = typeof redirect === 'string' ? redirect : '/'
|
const path = typeof redirect === 'string' ? redirect : '/'
|
||||||
|
if (loginType.value == 'admin' && Test.empty(res.data.userrole)) {
|
||||||
|
router.push('/home/index')
|
||||||
|
} else {
|
||||||
router.push(path)
|
router.push(path)
|
||||||
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
<el-input v-model.trim="formData.label_name" clearable :placeholder="t('labelNamePlaceholder')" class="input-width" />
|
<el-input v-model.trim="formData.label_name" clearable :placeholder="t('labelNamePlaceholder')" class="input-width" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('memo')">
|
<el-form-item :label="t('memo')">
|
||||||
<el-input v-model.trim="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width" maxlength="200" />
|
<el-input v-model.trim="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width" maxlength="200" show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('sort')" prop="sort">
|
<el-form-item :label="t('sort')" prop="sort">
|
||||||
<el-input v-model.trim="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
|
<el-input v-model.trim="formData.sort" clearable maxlength="6" show-word-limit :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|||||||
@ -99,12 +99,12 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="180">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
|
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
|
||||||
<el-button type="primary" link @click="setMemberLable(row)">{{ t('setLable') }}</el-button>
|
<el-button type="primary" link @click="setMemberLable(row)">{{ t('setLable') }}</el-button>
|
||||||
<el-button type="primary" link @click="deleteEvent(row)">{{ t('memberDelete') }}</el-button>
|
<!-- <el-button type="primary" link @click="deleteEvent(row)">{{ t('memberDelete') }}</el-button>-->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
|
<div class="flex ml-[18px] justify-between items-center pt-[20px]">
|
||||||
<span class="text-page-title">{{pageName}}</span>
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="ruleFormRef" :rules="rules" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="150px" ref="ruleFormRef" :rules="rules" class="page-form" v-loading="loading">
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<h3 class="panel-title !text-sm">{{ t('copyrightEdit') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('copyrightEdit') }}</h3>
|
||||||
@ -42,7 +46,7 @@
|
|||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
<div class="fixed-footer-wrap">
|
<div class="fixed-footer-wrap">
|
||||||
<div class="fixed-footer">
|
<div class="fixed-footer">
|
||||||
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
|
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
|
||||||
@ -56,10 +60,10 @@ import { reactive, ref } from 'vue'
|
|||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { setCopyright, getCopyright } from '@/app/api/sys'
|
import { setCopyright, getCopyright } from '@/app/api/sys'
|
||||||
import { FormInstance, FormRules } from 'element-plus'
|
import { FormInstance, FormRules } from 'element-plus'
|
||||||
// import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
// const route = useRoute()
|
const route = useRoute()
|
||||||
// const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container bg-[#fff] rounded-[4px]">
|
||||||
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
|
<div class="flex ml-[18px] justify-between items-center pt-[20px]">
|
||||||
<span class="text-page-title">{{pageName}}</span>
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="ruleFormRef" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="150px" ref="ruleFormRef" class="page-form" v-loading="loading">
|
||||||
|
|||||||
@ -1,31 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container" v-loading="noticeTableData.loading">
|
<div class="main-container bg-[#fff] rounded-[4px]" v-loading="noticeTableData.loading">
|
||||||
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
|
<div class="flex ml-[18px] justify-between items-center pt-[20px]">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<h3 class="panel-title !text-base">{{ t('buyerNotice') }}</h3>
|
<h3 class="panel-title !text-base">{{ t('buyerNotice') }}</h3>
|
||||||
<div class="flex flex-row flex-wrap m-[-4px]">
|
<div class="flex flex-row flex-wrap m-[-4px]">
|
||||||
<el-table :data="noticeTableData.seller" size="large">
|
<el-table :data="noticeTableData.buyer" size="large" :span-method="buyerSpan">
|
||||||
|
<el-table-column prop="addon_name" :label="t('addon')" min-width="120" />
|
||||||
<el-table-column prop="name" :label="t('noticeType')" min-width="120" />
|
<el-table-column prop="name" :label="t('noticeType')" min-width="120" />
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="300">
|
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="300">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="text-sm mr-1 flex items-center cursor-pointer" v-if="row.sms_type == 1"
|
<div class="text-sm mr-1 flex items-center cursor-pointer"
|
||||||
|
v-if="row.support_type.indexOf('sms') != -1"
|
||||||
@click="setNotice(row, 'sms')">
|
@click="setNotice(row, 'sms')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_sms ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_sms ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span class="ml-0.5">{{ t('sms') }}</span>
|
<span class="ml-0.5">{{ t('sms') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm flex items-center cursor-pointer ml-[20px]" v-if="row.wechat_type"
|
<div class="text-sm flex items-center cursor-pointer ml-[20px]"
|
||||||
|
v-if="row.support_type.indexOf('wechat') != -1"
|
||||||
@click="setNotice(row, 'wechat')">
|
@click="setNotice(row, 'wechat')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_wechat ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_wechat ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span class="ml-0.5">{{ t('wechat') }}</span>
|
<span class="ml-0.5">{{ t('wechat') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm flex items-center cursor-pointer ml-[20px]" v-if="row.weapp_type"
|
<div class="text-sm flex items-center cursor-pointer ml-[20px]"
|
||||||
|
v-if="row.support_type.indexOf('weapp') != -1"
|
||||||
@click="setNotice(row, 'weapp')">
|
@click="setNotice(row, 'weapp')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_weapp ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_weapp ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
@ -42,26 +46,30 @@
|
|||||||
<el-card class="box-card !border-none mt-[16px]" shadow="never">
|
<el-card class="box-card !border-none mt-[16px]" shadow="never">
|
||||||
<h3 class="panel-title !text-base">{{ t('sellerNotice') }}</h3>
|
<h3 class="panel-title !text-base">{{ t('sellerNotice') }}</h3>
|
||||||
<div class="flex flex-row flex-wrap m-[-4px]">
|
<div class="flex flex-row flex-wrap m-[-4px]">
|
||||||
<el-table :data="noticeTableData.buyer" size="large">
|
<el-table :data="noticeTableData.seller" size="large" :span-method="buyerSpan">
|
||||||
|
<el-table-column prop="addon_name" :label="t('addon')" min-width="120" />
|
||||||
<el-table-column prop="name" :label="t('noticeType')" min-width="120" />
|
<el-table-column prop="name" :label="t('noticeType')" min-width="120" />
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="300">
|
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="300">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="text-sm mr-1 flex items-center cursor-pointer" v-if="row.sms_type == 1"
|
<div class="text-sm mr-1 flex items-center cursor-pointer"
|
||||||
|
v-if="row.support_type.indexOf('sms') != -1"
|
||||||
@click="setNotice(row, 'sms')">
|
@click="setNotice(row, 'sms')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_sms ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_sms ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span class="ml-0.5">{{ t('sms') }}</span>
|
<span class="ml-0.5">{{ t('sms') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm flex items-center cursor-pointer ml-[20px]" v-if="row.wechat_type"
|
<div class="text-sm flex items-center cursor-pointer ml-[20px]"
|
||||||
|
v-if="row.support_type.indexOf('wechat') != -1"
|
||||||
@click="setNotice(row, 'wechat')">
|
@click="setNotice(row, 'wechat')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_wechat ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_wechat ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span class="ml-0.5">{{ t('wechat') }}</span>
|
<span class="ml-0.5">{{ t('wechat') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm flex items-center cursor-pointer ml-[20px]" v-if="row.weapp_type"
|
<div class="text-sm flex items-center cursor-pointer ml-[20px]"
|
||||||
|
v-if="row.support_type.indexOf('weapp') != -1"
|
||||||
@click="setNotice(row, 'weapp')">
|
@click="setNotice(row, 'weapp')">
|
||||||
<el-icon class="text-[15px] mr-[3px]" :class="row.is_weapp ? 'open' : ''">
|
<el-icon class="text-[15px] mr-[3px]" :class="row.is_weapp ? 'open' : ''">
|
||||||
<SuccessFilled />
|
<SuccessFilled />
|
||||||
@ -109,26 +117,49 @@ const noticeTableData = reactive({
|
|||||||
*/
|
*/
|
||||||
const loadNoticeList = () => {
|
const loadNoticeList = () => {
|
||||||
noticeTableData.loading = true
|
noticeTableData.loading = true
|
||||||
|
|
||||||
|
getNoticeList().then(res => {
|
||||||
noticeTableData.buyer = []
|
noticeTableData.buyer = []
|
||||||
noticeTableData.seller = []
|
noticeTableData.seller = []
|
||||||
getNoticeList().then(res => {
|
res.data.forEach(item => {
|
||||||
Object.keys(res.data).forEach(key => {
|
if (item.notice.length) {
|
||||||
const item = res.data[key]
|
const buyer = [], seller = []
|
||||||
item.sms_type = item.support_type.indexOf('sms') !== -1 ? 1 : 0
|
Object.keys(item.notice).forEach((key, index) => {
|
||||||
item.wechat_type = item.support_type.indexOf('wechat') !== -1 ? 1 : 0
|
const notice = item.notice[key]
|
||||||
item.weapp_type = item.support_type.indexOf('weapp') !== -1 ? 1 : 0
|
notice.addon_name = item.title
|
||||||
if (item.receiver_type == 0) {
|
notice.receiver_type == 1 ? buyer.push(notice) : seller.push(notice)
|
||||||
noticeTableData.buyer.push(item)
|
})
|
||||||
|
if (buyer.length) {
|
||||||
|
buyer[0].rowspan = buyer.length
|
||||||
|
noticeTableData.buyer = noticeTableData.buyer.concat(buyer)
|
||||||
|
}
|
||||||
|
if (seller.length) {
|
||||||
|
seller[0].rowspan = seller.length
|
||||||
|
noticeTableData.seller = noticeTableData.seller.concat(seller)
|
||||||
}
|
}
|
||||||
if (item.receiver_type == 1) {
|
|
||||||
noticeTableData.seller.push(item)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
noticeTableData.loading = false
|
||||||
|
}).catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
noticeTableData.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
noticeTableData.loading = false
|
const buyerSpan = (row : any) => {
|
||||||
}).catch(() => {
|
if (row.columnIndex === 0) {
|
||||||
noticeTableData.loading = false
|
if (row.row.rowspan) {
|
||||||
})
|
return {
|
||||||
|
rowspan: row.row.rowspan,
|
||||||
|
colspan: 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
rowspan: 0,
|
||||||
|
colspan: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadNoticeList()
|
loadNoticeList()
|
||||||
@ -139,10 +170,10 @@ const setNotice = (data: any, type: string) => {
|
|||||||
eval(type + 'Dialog.value.setFormData(data)')
|
eval(type + 'Dialog.value.setFormData(data)')
|
||||||
eval(type + 'Dialog.value.showDialog = true;')
|
eval(type + 'Dialog.value.showDialog = true;')
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>.open {
|
<style lang="scss" scoped>
|
||||||
|
.open {
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,4 +181,5 @@ const setNotice = (data: any, type: string) => {
|
|||||||
>div:nth-last-child(1):first-child {
|
>div:nth-last-child(1):first-child {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}</style>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card class="box-card !border-none" shadow="never" v-loading="payLoading">
|
<div class="main-container" v-loading="payLoading">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<!-- 设置支付配置 -->
|
<!-- 设置支付配置 -->
|
||||||
<div class="flex justify-between items-center" v-if="!payLoading">
|
<div class="flex justify-between items-center" v-if="!payLoading">
|
||||||
<span class="text-page-title">{{ pageName }}</span>
|
<span class="text-page-title">{{ pageName }}</span>
|
||||||
@ -60,6 +61,7 @@
|
|||||||
<alipay ref="alipayDialog" @complete="setConfigInfo" />
|
<alipay ref="alipayDialog" @complete="setConfigInfo" />
|
||||||
<offlinepay ref="offlinepayDialog" @complete="setConfigInfo" />
|
<offlinepay ref="offlinepayDialog" @complete="setConfigInfo" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<h3 class="panel-title !text-sm">{{ t('websiteInfo') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('websiteInfo') }}</h3>
|
||||||
@ -40,7 +44,7 @@
|
|||||||
<upload-image v-model="formData.front_end_logo" />
|
<upload-image v-model="formData.front_end_logo" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="box-card !border-none" shadow="never" v-if="app_type == 'admin'">
|
<el-card class="box-card !border-none" shadow="never" v-if="appType == 'admin'">
|
||||||
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
|
||||||
<el-form-item :label="t('contactsTel')">
|
<el-form-item :label="t('contactsTel')">
|
||||||
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||||
@ -53,7 +57,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
<div class="fixed-footer-wrap">
|
<div class="fixed-footer-wrap">
|
||||||
<div class="fixed-footer">
|
<div class="fixed-footer">
|
||||||
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
|
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
|
||||||
@ -67,14 +71,15 @@ import { reactive, ref } from 'vue'
|
|||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { setWebsite, getWebsite, getService } from '@/app/api/sys'
|
import { setWebsite, getWebsite, getService } from '@/app/api/sys'
|
||||||
import { FormInstance, FormRules } from 'element-plus'
|
import { FormInstance, FormRules } from 'element-plus'
|
||||||
import storage from '@/utils/storage'
|
|
||||||
import { getAppType } from '@/utils/common'
|
import { getAppType } from '@/utils/common'
|
||||||
// import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import useSystemStore from '@/stores/modules/system';
|
||||||
|
|
||||||
// const route = useRoute()
|
const route = useRoute()
|
||||||
// const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const app_type = ref()
|
const appType = ref(getAppType())
|
||||||
const formData = reactive<Record<string, string>>({
|
const formData = reactive<Record<string, string>>({
|
||||||
site_name: '',
|
site_name: '',
|
||||||
logo: '',
|
logo: '',
|
||||||
@ -107,8 +112,6 @@ const setFormData = async (id: number = 0) => {
|
|||||||
formData['wechat_code'] = service_data.wechat_code
|
formData['wechat_code'] = service_data.wechat_code
|
||||||
formData['enterprise_wechat'] = service_data.enterprise_wechat
|
formData['enterprise_wechat'] = service_data.enterprise_wechat
|
||||||
formData['tel'] = service_data.tel
|
formData['tel'] = service_data.tel
|
||||||
|
|
||||||
app_type.value = getAppType()
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
setFormData()
|
setFormData()
|
||||||
@ -137,19 +140,13 @@ const save = async (formEl: FormInstance | undefined) => {
|
|||||||
|
|
||||||
setWebsite(formData).then(() => {
|
setWebsite(formData).then(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
setStore()
|
appType.value == 'admin' ? useSystemStore().getWebsiteInfo() : useUserStore().getSiteInfo()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const setStore = async () => {
|
|
||||||
const data = await (await getWebsite()).data
|
|
||||||
storage.set({ key: 'siteInfo', data })
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container bg-[#fff] rounded-[4px]">
|
||||||
<el-alert class="warm-prompt" type="info">
|
<el-alert class="warm-prompt" type="info">
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
|
|||||||
@ -1,105 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="main-container w-full bg-white" v-loading="loading">
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
|
||||||
<el-form :model="saveInfo" label-width="80px" ref="formRef" :rules="formRules" class="page-form">
|
|
||||||
<el-form-item :label="t('headImg')">
|
|
||||||
<upload-image v-model="saveInfo.head_img" :limit="1" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('userName')">
|
|
||||||
<span>{{ saveInfo.username }}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('realName')">
|
|
||||||
<el-input v-model="saveInfo.real_name" :placeholder="t('realNamePlaceholder')" clearable
|
|
||||||
class="input-width" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div class="fixed-footer-wrap">
|
|
||||||
<div class="fixed-footer">
|
|
||||||
<el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button>
|
|
||||||
<el-button type="primary" @click="returnFn(formRef)">{{ t('cancel') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { t } from '@/lang'
|
|
||||||
import type { FormInstance } from 'element-plus'
|
|
||||||
// import { img } from '@/utils/common'
|
|
||||||
import { getUserInfo, setUserInfo } from '@/app/api/personal'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
// 提交信息
|
|
||||||
const saveInfo = reactive({
|
|
||||||
head_img: '',
|
|
||||||
real_name: '',
|
|
||||||
username: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
const loading = ref(true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
const getUserInfoFn = () => {
|
|
||||||
loading.value = true
|
|
||||||
getUserInfo().then(res => {
|
|
||||||
loading.value = false
|
|
||||||
|
|
||||||
const data = res.data
|
|
||||||
saveInfo.head_img = data.head_img
|
|
||||||
saveInfo.real_name = data.real_name
|
|
||||||
saveInfo.username = data.username
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getUserInfoFn()
|
|
||||||
|
|
||||||
const submitForm = (formEl: FormInstance | undefined) => {
|
|
||||||
if (loading.value || !formEl) return
|
|
||||||
formEl.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
setUserInfo(saveInfo).then((res: any) => {
|
|
||||||
loading.value = false
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const returnFn = () => {
|
|
||||||
router.push('/user/center')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
:deep(.personal-body) {
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
.el-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.personal-option {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
@ -122,7 +122,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column :label="t('operation')" min-width="250" align="right" fixed="right">
|
<el-table-column :label="t('operation')" min-width="210" align="right" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="openClose(row.status, row.site_id)"
|
<el-button type="primary" link @click="openClose(row.status, row.site_id)"
|
||||||
v-if="row.status == 1 || row.status == 3">{{ row.status == 1 ? t('closeTxt') : t('openTxt')
|
v-if="row.status == 1 || row.status == 3">{{ row.status == 1 ? t('closeTxt') : t('openTxt')
|
||||||
|
|||||||
@ -1,100 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="main-container w-full bg-white" v-loading="loading">
|
|
||||||
<el-card class="box-card !border-none relative" shadow="never">
|
|
||||||
<el-form :model="saveInfo" label-width="80px" ref="formRef" class="page-form">
|
|
||||||
<el-form-item :label="t('headImg')">
|
|
||||||
<el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain">
|
|
||||||
<template #error>
|
|
||||||
<div
|
|
||||||
class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full">
|
|
||||||
<el-icon class="!text-[#fff] !text-[45px]">
|
|
||||||
<UserFilled />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-image>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('userName')">
|
|
||||||
<div>{{ saveInfo.username }}</div>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="t('realName')">
|
|
||||||
<div>{{ saveInfo.real_name }}</div>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<span class="text-[14px] text-[#999] absolute top-[25px] right-[20px] cursor-pointer" @click="toEditPersonal">{{
|
|
||||||
t('editPersonal') }}</span>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { t } from '@/lang'
|
|
||||||
import type { FormInstance } from 'element-plus'
|
|
||||||
import { img } from '@/utils/common'
|
|
||||||
import { getUserInfo } from '@/app/api/personal'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
// 提交信息
|
|
||||||
const saveInfo = reactive({
|
|
||||||
head_img: '',
|
|
||||||
real_name: '',
|
|
||||||
original_password: '',
|
|
||||||
password: '',
|
|
||||||
password_copy: '',
|
|
||||||
username: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
const loading = ref(true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
const getUserInfoFn = () => {
|
|
||||||
loading.value = true
|
|
||||||
getUserInfo().then(res => {
|
|
||||||
loading.value = false
|
|
||||||
|
|
||||||
const data = res.data
|
|
||||||
saveInfo.head_img = data.head_img
|
|
||||||
saveInfo.real_name = data.real_name
|
|
||||||
saveInfo.original_password = data.original_password
|
|
||||||
saveInfo.password = data.password
|
|
||||||
saveInfo.password_copy = data.password
|
|
||||||
saveInfo.username = data.username
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getUserInfoFn()
|
|
||||||
|
|
||||||
// 编辑个人中心
|
|
||||||
const toEditPersonal = () => {
|
|
||||||
router.push('/user/edit_center')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
:deep(.personal-body) {
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
.el-input {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item__content {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.personal-option {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
@ -56,7 +56,7 @@
|
|||||||
{{ row.last_ip || '' }}
|
{{ row.last_ip || '' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="160">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
|
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container attachment-container">
|
<div class="main-container attachment-container">
|
||||||
|
|
||||||
<el-card class="box-card !border-none full-container" shadow="never">
|
<el-card class="box-card !border-none full-container" shadow="never">
|
||||||
|
<div class="flex justify-between items-center mb-[16px]">
|
||||||
|
<span class="text-page-title">{{pageName}}</span>
|
||||||
|
</div>
|
||||||
<el-tabs v-model="type">
|
<el-tabs v-model="type">
|
||||||
<el-tab-pane :label="t(tab)" v-for="(tab, index) in attachmentType" :name="tab" :key="index">
|
<el-tab-pane :label="t(tab)" v-for="(tab, index) in attachmentType" :name="tab" :key="index">
|
||||||
<attachment scene="attachment" :type="tab" />
|
<attachment scene="attachment" :type="tab" />
|
||||||
@ -14,7 +18,10 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import attachment from '@/components/upload-attachment/attachment.vue'
|
import attachment from '@/components/upload-attachment/attachment.vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const pageName = route.meta.title
|
||||||
const attachmentType: string[] = ['image', 'video', 'icon']
|
const attachmentType: string[] = ['image', 'video', 'icon']
|
||||||
const type = ref(attachmentType[0])
|
const type = ref(attachmentType[0])
|
||||||
|
|
||||||
@ -30,7 +37,7 @@ const type = ref(attachmentType[0])
|
|||||||
.el-tabs {
|
.el-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: calc(100% - 40px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tabs__content {
|
.el-tabs__content {
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
|
||||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
|
||||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
|
||||||
<div class="flex flex-col ml-2">
|
|
||||||
<span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>
|
|
||||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>
|
|
||||||
</div>
|
|
||||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
|
||||||
<div class="flex flex-col ml-2">
|
|
||||||
<span class="text-sm truncate w-[190px]">{{t('dataCache')}}</span>
|
|
||||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('dataCacheDesc')">{{t('dataCacheDesc')}}</span>
|
|
||||||
</div>
|
|
||||||
<span class="plug-item-operate" @click="schemaCache()">{{t('refresh')}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { t } from '@/lang'
|
|
||||||
import { clearSchemaCache, menuRefresh } from '@/app/api/sys'
|
|
||||||
|
|
||||||
const loading = ref<Boolean>(false)
|
|
||||||
|
|
||||||
// 数据缓存
|
|
||||||
const schemaCache = () => {
|
|
||||||
loading.value = true
|
|
||||||
clearSchemaCache({}).then(res => {
|
|
||||||
loading.value = false
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 更新菜单
|
|
||||||
const refreshMenu = () => {
|
|
||||||
loading.value = true
|
|
||||||
menuRefresh({}).then(res => {
|
|
||||||
loading.value = false
|
|
||||||
}).catch(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.demo-tabs > .el-tabs__content {
|
|
||||||
padding: 32px;
|
|
||||||
color: #6b778c;
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
.plug-item{
|
|
||||||
.plug-item-operate{
|
|
||||||
@apply text-xs absolute right-3 cursor-pointer;
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -13,7 +13,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<upload-attachment :limit="limit" type="video" @confirm="confirmSelect" v-else>
|
<upload-attachment :limit="limit" type="video" @confirm="confirmSelect" v-else>
|
||||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||||
|
<slot name="icon">
|
||||||
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)"/>
|
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)"/>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</upload-attachment>
|
</upload-attachment>
|
||||||
</div>
|
</div>
|
||||||
@ -31,7 +33,9 @@
|
|||||||
<div class="rounded cursor-pointer relative bg-page video-wrap mr-[10px]" :style="style" v-if="videos.data.length < limit">
|
<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">
|
<upload-attachment :limit="limit" type="video" @confirm="confirmSelect">
|
||||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||||
|
<slot name="icon">
|
||||||
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)"/>
|
<icon name="iconfont-icon24gf-playCircle" size="25px" color="var(--el-text-color-secondary)"/>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</upload-attachment>
|
</upload-attachment>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -24,6 +24,9 @@
|
|||||||
"userName": "用户名",
|
"userName": "用户名",
|
||||||
"headImg": "头像",
|
"headImg": "头像",
|
||||||
"accountNumber": "账号",
|
"accountNumber": "账号",
|
||||||
|
"accountSettings": "账号设置",
|
||||||
|
"realName":"名称",
|
||||||
|
"realNamePlaceholder": "请输入用户名称",
|
||||||
"password": "密码",
|
"password": "密码",
|
||||||
"confirmPassword": "确认密码",
|
"confirmPassword": "确认密码",
|
||||||
"image": "图片",
|
"image": "图片",
|
||||||
@ -49,6 +52,7 @@
|
|||||||
"selectimage": "选择图片",
|
"selectimage": "选择图片",
|
||||||
"selectvideo": "选择视频",
|
"selectvideo": "选择视频",
|
||||||
"selecticon": "选择图标",
|
"selecticon": "选择图标",
|
||||||
|
"selectnews": "选择图文",
|
||||||
"uploadimage": "上传图片",
|
"uploadimage": "上传图片",
|
||||||
"uploadvideo": "上传视频",
|
"uploadvideo": "上传视频",
|
||||||
"addAttachmentCategory": "添加分组",
|
"addAttachmentCategory": "添加分组",
|
||||||
@ -64,7 +68,8 @@
|
|||||||
"placeholdervideoName": "请输入视频名称",
|
"placeholdervideoName": "请输入视频名称",
|
||||||
"placeholdericonName": "请输入图标名称",
|
"placeholdericonName": "请输入图标名称",
|
||||||
"success": "上传成功",
|
"success": "上传成功",
|
||||||
"triggerUpperLimit": "可选数量已达上限"
|
"triggerUpperLimit": "可选数量已达上限",
|
||||||
|
"mediaEmpty": "暂无素材,请点击上传按钮上传"
|
||||||
},
|
},
|
||||||
"tabs": {
|
"tabs": {
|
||||||
"closeLeft": "关闭左侧",
|
"closeLeft": "关闭左侧",
|
||||||
|
|||||||
@ -1,101 +1,183 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-aside :class="['layout-aside w-full ease-in duration-200', { 'bright': !dark }]">
|
<div :class="['layout-aside ease-in duration-200 flex h-full', { 'bright': !dark }]">
|
||||||
|
<div class="flex flex-col h-full border-0 border-r-[1px] border-solid border-[#eee] box-border bg-[#f5f6f8]">
|
||||||
|
<div class="w-full h-[64px] flex justify-center items-center w-[65px]flex-shrink-0">
|
||||||
|
<el-image style="width: 40px; height: 40px" :src="img(logoUrl)" fit="contain">
|
||||||
|
<template #error>
|
||||||
|
<div class="flex justify-center items-center w-full h-[40px]"><img class="max-w-[40px]" src="@/app/assets/images/site_login_logo.png" alt="" object-fit="contain"></div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<el-scrollbar class="flex-1 w-[65px] one-menu">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<template v-for="(item, index) in oneMenuData">
|
||||||
|
<div v-if="item.meta.show" class="menu-item py-[10px] w-full box-border cursor-pointer" :class="{'is-active':oneMenuActive===item.original_name}" @click="router.push({ name: item.name })">
|
||||||
|
<div class="w-[50px] h-full flex items-center justify-center mx-auto">
|
||||||
|
<template v-if="item.meta.icon">
|
||||||
|
<el-image class="w-[25px] h-[25px] overflow-hidden" :src="item.meta.icon" fit="fill" v-if="isUrl(item.meta.icon)"/>
|
||||||
|
<icon :name="item.meta.icon" size="25px" v-else />
|
||||||
|
</template>
|
||||||
|
<icon v-else :name="'iconfont iconshezhi1'" />
|
||||||
|
</div>
|
||||||
|
<div class="text-center text-[13px] mt-[5px]">{{ item.meta.short_title || item.meta.title }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center pt-[20px] pb-[10px] pl-[80px] pr-[70px]"
|
|
||||||
v-if="twoMenuData.length">
|
|
||||||
<template v-for="(item,index) in twoMenuData" :key="index">
|
|
||||||
<div
|
|
||||||
v-if="item.meta.show"
|
|
||||||
@click="redirect(item)"
|
|
||||||
:class="['flex items-center h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[10px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]',{'text-[#fff] !bg-[#000] border-[#000]': menuActive == item.name || menuTwoActive && menuTwoActive == item.name}]">
|
|
||||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px] !leading-[14px]" size="14px"
|
|
||||||
:title="item.meta.title" />
|
|
||||||
<span class="text-[14px]">{{ item.meta.short_title || item.meta.title }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<div class="flex flex-col two-menu w-[140px] h-[100vh]" v-if="twoMenuData.length">
|
||||||
|
<div class="w-[140px] h-[64px] bg-[#fff] flex items-center justify-center text-[16px]">{{ route.matched[1].meta.title }}</div>
|
||||||
|
<el-scrollbar class="flex-1">
|
||||||
|
<el-menu :default-active="route.name" :router="true" class="aside-menu " :collapse="systemStore.menuIsCollapse">
|
||||||
|
<menu-item v-for="(route, index) in twoMenuData" :routes="route" :key="index" />
|
||||||
|
</el-menu>
|
||||||
|
<div class="h-[48px]"></div>
|
||||||
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<!-- 三级菜单 -->
|
|
||||||
<div class="pt-[20px] pl-[80px] pr-[70px]" v-if="threeMenuData.length">
|
|
||||||
<el-tabs v-model="menuTwoActive" @tab-click="toolsHandleClick">
|
|
||||||
<template v-for="(item,index) in threeMenuData" :key="index">
|
|
||||||
<el-tab-pane :label="item.meta.title" :name="item.name" :path="item.path" v-if="item.meta.show"
|
|
||||||
@click="settingMenuFn(item)"></el-tab-pane>
|
|
||||||
</template>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
</div>
|
||||||
</el-aside>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref, computed } from 'vue'
|
import { watch, ref, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import { ADMIN_ROUTE,findFirstValidRoute } from "@/router/routers"
|
||||||
|
import { img, isUrl } from '@/utils/common'
|
||||||
|
import { getWebsite } from '@/app/api/sys'
|
||||||
|
import menuItem from './menu-item.vue'
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const routers = userStore.routers
|
||||||
const systemStore = useSystemStore()
|
const systemStore = useSystemStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const dark = computed(() => {
|
const dark = computed(() => {
|
||||||
return systemStore.dark
|
return systemStore.dark
|
||||||
})
|
})
|
||||||
|
const logoUrl = computed(() => {
|
||||||
|
return userStore.siteInfo.icon ? userStore.siteInfo.icon : systemStore.website.icon
|
||||||
|
})
|
||||||
const twoMenuData = ref<Record<string, any>[]>([])
|
const twoMenuData = ref<Record<string, any>[]>([])
|
||||||
const threeMenuData = ref<Record<string, any>[]>([])
|
|
||||||
const menuActive = ref('')
|
|
||||||
const menuTwoActive = ref('')
|
|
||||||
|
|
||||||
|
const oneMenuData = ref<Record<string, any>[]>([])
|
||||||
|
routers.forEach(item => {
|
||||||
|
item.original_name = item.name
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
item.name = findFirstValidRoute(item.children)
|
||||||
|
}
|
||||||
|
oneMenuData.value.push(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
const oneMenuActive = ref(oneMenuData.value[0].name)
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
twoMenuData.value = route.matched[1].children ?? []
|
twoMenuData.value = route.matched[1].children ?? []
|
||||||
threeMenuData.value = route.matched[2].children ?? []
|
oneMenuActive.value = route.matched[1].name == ADMIN_ROUTE.children[0].name ? route.matched[2].name : route.matched[1].name
|
||||||
menuActive.value = route.matched[2] ? route.matched[2].name : ''
|
|
||||||
menuTwoActive.value = route.matched[3] ? route.matched[3].name : ''
|
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
/**
|
// const logoShow = ref<boolean>(false)
|
||||||
* 跳转
|
// const getWebsiteFn = ()=>{
|
||||||
* @param data
|
// getWebsite().then((res:any)=>{
|
||||||
*/
|
// logoUrl.value = res.data.icon
|
||||||
const redirect = (data: any) => {
|
// console.log(res)
|
||||||
if (data.children) {
|
// logoShow.value = true
|
||||||
router.push(data.children[0].path)
|
// }).catch(()=>{
|
||||||
} else {
|
// logoShow.value = true
|
||||||
router.push(data.path)
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// getWebsiteFn()
|
||||||
|
|
||||||
const toolsHandleClick = (tab, event: Event) => {
|
|
||||||
router.push({name: tab.props.name})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.layout-aside {
|
.one-menu{
|
||||||
&.bright {
|
.menu-item{
|
||||||
li {
|
&:hover{
|
||||||
background-color: #F5F7F9;
|
color:var(--el-color-primary);
|
||||||
|
}
|
||||||
&.is-active:not(.is-opened) {
|
&.is-active{
|
||||||
position: relative;
|
background-color: var(--el-color-primary) !important;
|
||||||
color: #333;
|
color: #fff !important;
|
||||||
background-color: #fff;
|
}
|
||||||
|
span{
|
||||||
&::after {
|
font-size: 14px;
|
||||||
content: "";
|
margin-left: 8px;
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 2px;
|
|
||||||
background-color: var(--el-menu-active-color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.el-menu{
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.el-scrollbar{
|
||||||
|
height: calc(100vh - 65px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.two-menu{
|
||||||
.menu-item:hover{
|
.aside-menu:not(.el-menu--collapse) {
|
||||||
|
width: 140px;
|
||||||
|
border: 0;
|
||||||
|
padding-top: 10px;
|
||||||
|
.el-menu-item{
|
||||||
|
height: 36px;
|
||||||
|
margin: 0 8px 4px;
|
||||||
|
padding: 0 8px !important;
|
||||||
|
border-radius: 2px;
|
||||||
|
span{
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
&.is-active{
|
||||||
|
background-color: var(--el-color-primary-light-9) !important;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: #f7f7f7;
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.text-color{
|
.el-sub-menu{
|
||||||
|
margin-bottom: 8px;
|
||||||
|
.el-sub-menu__title{
|
||||||
|
margin: 0 8px 4px;
|
||||||
|
height: 36px;
|
||||||
|
padding-left: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
span{
|
||||||
|
height: 36px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: #f7f7f7;
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
.el-icon.el-sub-menu__icon-arrow{
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-menu-item{
|
||||||
|
padding-left: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-wrap {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
white-space: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-title {
|
||||||
|
flex: 1;
|
||||||
|
width: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -7,9 +7,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<span :class="['ml-[10px]', {'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}]">{{ meta.title }}</span>
|
<span :class="['ml-[10px]', {'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}]">{{ meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
<menu-item v-for="(route, index) in routes.children" :routes="route" :route-path="resolvePath(route.path)" :key="index" />
|
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" />
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-menu-item v-else-if="routes.meta.class == 1" :index="String(routes.name)" :route="'/'+routePath">
|
<el-menu-item v-else-if="routes.meta.class == 1" :index="String(routes.name)" :route="routes.path">
|
||||||
<div v-if="meta.icon" class="w-[16px] h-[16px] relative flex justify-center">
|
<div v-if="meta.icon" class="w-[16px] h-[16px] relative flex justify-center">
|
||||||
<icon :name="meta.icon" class="absolute top-[50%] -translate-y-[50%]" />
|
<icon :name="meta.icon" class="absolute top-[50%] -translate-y-[50%]" />
|
||||||
</div>
|
</div>
|
||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item v-else :index="String(routes.name)" :route="'/'+routePath">
|
<el-menu-item v-else :index="String(routes.name)" :route="routes.path">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
|
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -62,16 +62,16 @@ const props = defineProps({
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
routePath: {
|
// routePath: {
|
||||||
type: String
|
// type: String
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
const meta = computed(() => props.routes.meta)
|
const meta = computed(() => props.routes.meta)
|
||||||
|
|
||||||
const resolvePath = (path: string) => {
|
// const resolvePath = (path: string) => {
|
||||||
return `${props.routePath}/${path}`
|
// return `/${path}`
|
||||||
}
|
// }
|
||||||
|
|
||||||
const indexList = ref();
|
const indexList = ref();
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
|
|||||||
@ -1,23 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="h-[60px] bg-[#2B303B] layout-admin flex items-center justify-between px-[15px] text-white" >
|
<el-container class="h-[64px] layout-admin flex items-center justify-between px-[15px]" >
|
||||||
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||||
<div class="flex items-center text-[14px] leading-[1]">
|
<div class="left-panel flex items-center text-[14px] leading-[1]">
|
||||||
<span class="iconfont icontuodong !text-[25px] mr-[6px]"></span>
|
|
||||||
|
|
||||||
<template v-for="(item, index) in oneMenuData">
|
|
||||||
<template v-if="item.meta.show">
|
|
||||||
<span class="mx-2 text-[#4F5563] mx-[15px]" v-if="index">|</span>
|
|
||||||
<span class="cursor-pointer" @click="router.push({ name: item.name })" >
|
|
||||||
{{ item.meta.short_title || item.meta.title }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="right-panel h-full flex items-center justify-end">
|
|
||||||
<!-- 刷新当前页 -->
|
<!-- 刷新当前页 -->
|
||||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||||
<icon name="element-Refresh" />
|
<icon name="element-Refresh" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 面包屑导航 -->
|
||||||
|
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
|
||||||
|
<el-breadcrumb separator="/">
|
||||||
|
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel h-full flex items-center justify-end">
|
||||||
|
|
||||||
<!-- 用户信息 -->
|
<!-- 用户信息 -->
|
||||||
<div class="navbar-item flex items-center h-full cursor-pointer">
|
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||||
<user-info />
|
<user-info />
|
||||||
@ -58,29 +55,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref,computed } from 'vue'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import useAppStore from '@/stores/modules/app'
|
import useAppStore from '@/stores/modules/app'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute,useRouter } from 'vue-router'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import userInfo from './user-info.vue'
|
import userInfo from './user-info.vue'
|
||||||
import { findFirstValidRoute } from "@/router/routers"
|
import { findFirstValidRoute } from "@/router/routers"
|
||||||
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const routers = userStore.routers
|
const routers = userStore.routers
|
||||||
|
|
||||||
const oneMenuData = ref<Record<string, any>[]>([])
|
|
||||||
routers.forEach(item => {
|
|
||||||
item.original_name = item.name
|
|
||||||
if (item.children && item.children.length) {
|
|
||||||
item.name = findFirstValidRoute(item.children)
|
|
||||||
}
|
|
||||||
oneMenuData.value.push(item)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 检测登录 start
|
// 检测登录 start
|
||||||
const detectionLoginDialog = ref(false)
|
const detectionLoginDialog = ref(false)
|
||||||
const comparisonToken = ref('')
|
const comparisonToken = ref('')
|
||||||
@ -110,6 +97,12 @@ const refreshRouter = () => {
|
|||||||
appStore.refreshRouterView()
|
appStore.refreshRouterView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 面包屑导航
|
||||||
|
const breadcrumb = computed(() => {
|
||||||
|
const matched = route.matched.filter(item => { return item.meta.title })
|
||||||
|
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
|
||||||
|
return matched
|
||||||
|
})
|
||||||
storage.set({ key: 'currHeadMenuName', data: "" })
|
storage.set({ key: 'currHeadMenuName', data: "" })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -121,7 +114,6 @@ storage.set({ key: 'currHeadMenuName', data: "" })
|
|||||||
}
|
}
|
||||||
.navbar-item {
|
.navbar-item {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
.index-item {
|
.index-item {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
@ -133,7 +125,7 @@ storage.set({ key: 'currHeadMenuName', data: "" })
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
.layout-admin .el-dropdown{
|
/* .layout-admin .el-dropdown{
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
} */
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -8,13 +8,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item>
|
<el-dropdown-item @click="getUserInfoFn">
|
||||||
<router-link to="/user/center">
|
<!-- <router-link to="/user/center"> -->
|
||||||
<div class="flex items-center leading-[1] py-[5px]">
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
<span class="text-[14px]">账号设置</span>
|
<span class="text-[14px]">账号设置</span>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
<!-- </router-link> -->
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
<router-link to="/tools/authorize">
|
<router-link to="/tools/authorize">
|
||||||
@ -61,6 +61,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<user-info-edit ref="userInfoEditRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
|||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import { setUserInfo } from '@/app/api/personal'
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import userInfoEdit from '@/app/components/user-info-edit/index.vue'
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const clickEvent = (command: string) => {
|
const clickEvent = (command: string) => {
|
||||||
@ -86,7 +87,10 @@ const clickEvent = (command: string) => {
|
|||||||
const logout = () => {
|
const logout = () => {
|
||||||
userStore.logout();
|
userStore.logout();
|
||||||
}
|
}
|
||||||
|
const userInfoEditRef = ref(null)
|
||||||
|
const getUserInfoFn = ()=>{
|
||||||
|
userInfoEditRef.value?.open()
|
||||||
|
}
|
||||||
// 修改密码 --- start
|
// 修改密码 --- start
|
||||||
let changePasswordDialog = ref(false)
|
let changePasswordDialog = ref(false)
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|||||||
@ -1,21 +1,23 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="common-layout min-w-[1200px]" >
|
<div class="common-layout min-w-[1200px]" >
|
||||||
<el-container class="w-100 h-screen">
|
<el-container class="w-100 h-screen">
|
||||||
<el-header class="h-[60px]">
|
<layout-aside></layout-aside>
|
||||||
|
|
||||||
|
<el-container>
|
||||||
|
<el-header class="!h-[64px]">
|
||||||
<layout-header></layout-header>
|
<layout-header></layout-header>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-container class="flex flex-col">
|
|
||||||
<div ref="layoutAsideRef">
|
|
||||||
<layout-aside @complete="heightChange"></layout-aside>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-main :class="['main-wrap h-full p-0',{'bg-page': dark}]">
|
<el-main :class="['main-wrap h-full p-0 bg-page']">
|
||||||
<el-scrollbar class="layout-content-height" :class="{'px-[64px]': flag }" :style="{height: contentHeight}">
|
<el-scrollbar>
|
||||||
|
<div class="p-[10px]">
|
||||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||||
<keep-alive :include="tabbarStore.tabNames">
|
<keep-alive :include="tabbarStore.tabNames">
|
||||||
<component :is="Component" :key="route.fullPath" />
|
<component :is="Component" :key="route.fullPath" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-main>
|
</el-main>
|
||||||
|
|
||||||
@ -23,40 +25,15 @@
|
|||||||
</el-container>
|
</el-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, onMounted} from 'vue'
|
import { computed, ref, onMounted} from 'vue'
|
||||||
import layoutHeader from './components/header/index.vue'
|
import layoutHeader from './components/header/index.vue'
|
||||||
import layoutAside from './components/aside/index.vue'
|
import layoutAside from './components/aside/index.vue'
|
||||||
import useAppStore from '@/stores/modules/app'
|
import useAppStore from '@/stores/modules/app'
|
||||||
import useTabbarStore from '@/stores/modules/tabbar'
|
import useTabbarStore from '@/stores/modules/tabbar'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
|
||||||
import useStyleStore from '@/stores/modules/style'
|
|
||||||
import { CollectionTag } from '@element-plus/icons-vue'
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const tabbarStore = useTabbarStore()
|
const tabbarStore = useTabbarStore()
|
||||||
const systemStore = useSystemStore()
|
|
||||||
const layoutAsideRef = ref()
|
|
||||||
const styleStore = useStyleStore()
|
|
||||||
|
|
||||||
// 控制页面内容高度start
|
|
||||||
let contentHeight= ref("")
|
|
||||||
const heightChange = ()=>{
|
|
||||||
setTimeout(() => {
|
|
||||||
contentHeight.value = `calc(100vh - ${layoutAsideRef.value.clientHeight + 60}px)`
|
|
||||||
}, 600);
|
|
||||||
}
|
|
||||||
heightChange();
|
|
||||||
// 控制页面内容高度end
|
|
||||||
|
|
||||||
const dark = computed(()=>{
|
|
||||||
return systemStore.dark
|
|
||||||
})
|
|
||||||
|
|
||||||
const flag = computed(()=>{
|
|
||||||
return styleStore.flag
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -4,8 +4,11 @@
|
|||||||
<div class="w-[124px] px-[8px] bg-[#282c34] h-screen one-menu">
|
<div class="w-[124px] px-[8px] bg-[#282c34] h-screen one-menu">
|
||||||
<el-header class="logo-wrap">
|
<el-header class="logo-wrap">
|
||||||
<div class="logo flex items-center m-auto h-[64px]" v-if="!systemStore.menuIsCollapse">
|
<div class="logo flex items-center m-auto h-[64px]" v-if="!systemStore.menuIsCollapse">
|
||||||
<img class="max-h-[40px] max-w-[40px] rounded-full" v-if="siteInfo.logo" :src="img(siteInfo.logo)" alt="">
|
<el-image style="width: 40px; height: 40px" :src="img(logoUrl)" fit="contain">
|
||||||
<img class="max-h-[40px] max-w-[40px] rounded-full" v-else src="@/app/assets/images/icon-addon.png" alt="">
|
<template #error>
|
||||||
|
<div class="flex justify-center items-center w-full h-[40px]"><img class="max-w-[40px]" src="@/app/assets/images/icon-addon.png" alt="" object-fit="contain"></div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="logo flex items-center justify-center h-[64px]" v-else>
|
<div class="logo flex items-center justify-center h-[64px]" v-else>
|
||||||
<i class="text-3xl iconfont iconyunkongjian"></i>
|
<i class="text-3xl iconfont iconyunkongjian"></i>
|
||||||
@ -43,7 +46,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch,computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
import useSystemStore from '@/stores/modules/system'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
@ -62,6 +65,9 @@ const addonIndexRoute = userStore.addonIndexRoute
|
|||||||
const oneMenuData = ref<Record<string, any>[]>([])
|
const oneMenuData = ref<Record<string, any>[]>([])
|
||||||
const twoMenuData = ref<Record<string, any>[]>([])
|
const twoMenuData = ref<Record<string, any>[]>([])
|
||||||
const addonRouters: Record<string, any> = {}
|
const addonRouters: Record<string, any> = {}
|
||||||
|
const logoUrl = computed(() => {
|
||||||
|
return userStore.siteInfo.icon ? userStore.siteInfo.icon : systemStore.website.icon
|
||||||
|
})
|
||||||
|
|
||||||
routers.forEach(item => {
|
routers.forEach(item => {
|
||||||
item.original_name = item.name
|
item.original_name = item.name
|
||||||
@ -142,12 +148,12 @@ watch(route, () => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
&:hover{
|
&:hover{
|
||||||
background-color: var(--el-color-primary);
|
background-color: transparent;
|
||||||
color: #fff;
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
&.is-active{
|
&.is-active{
|
||||||
background-color: var(--el-color-primary) !important;
|
background-color: var(--el-color-primary) !important;
|
||||||
color: #fff;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
span{
|
span{
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@ -14,11 +14,13 @@
|
|||||||
<span class="text-[14px]">切换站点</span>
|
<span class="text-[14px]">切换站点</span>
|
||||||
</div>
|
</div>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item @click="toLink('/user/center')">
|
<el-dropdown-item @click="getUserInfoFn">
|
||||||
|
<!-- <router-link to="/user/center"> -->
|
||||||
<div class="flex items-center leading-[1] py-[5px]">
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
<span class="text-[14px]">账号设置</span>
|
<span class="text-[14px]">账号设置</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- </router-link> -->
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item @click="changePasswordDialog=true">
|
<el-dropdown-item @click="changePasswordDialog=true">
|
||||||
<div class="flex items-center leading-[1] py-[5px]">
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
@ -26,16 +28,15 @@
|
|||||||
<span class="text-[14px]">修改密码</span>
|
<span class="text-[14px]">修改密码</span>
|
||||||
</div>
|
</div>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item command="logout">
|
<el-dropdown-item @click="logout">
|
||||||
<div class="flex items-center leading-[1] py-[2px]">
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
<span class="iconfont icontuichudenglu !text-[21px] mr-[8px]"></span>
|
<span class="iconfont icontuichudenglu ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
<span class="text-[14px]">退出登录</span>
|
<span class="text-[14px]">退出登录</span>
|
||||||
</div>
|
</div>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
||||||
<el-dialog v-model="changePasswordDialog" width="450px" title="修改密码" :before-close="handleClose">
|
<el-dialog v-model="changePasswordDialog" width="450px" title="修改密码" :before-close="handleClose">
|
||||||
<div>
|
<div>
|
||||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||||
@ -58,21 +59,21 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<user-info-edit ref="userInfoEditRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { UserFilled } from '@element-plus/icons-vue'
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
import { reactive, ref } from 'vue'
|
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import { setUserInfo } from '@/app/api/personal'
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import userInfoEdit from '@/app/components/user-info-edit/index.vue'
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const clickEvent = (command: string) => {
|
const clickEvent = (command: string) => {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'logout':
|
case 'logout':
|
||||||
@ -81,54 +82,60 @@ const clickEvent = (command: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
userStore.logout();
|
||||||
|
}
|
||||||
const toLink = (link) => {
|
const toLink = (link) => {
|
||||||
router.push(link)
|
router.push(link)
|
||||||
}
|
}
|
||||||
|
const userInfoEditRef = ref(null)
|
||||||
|
const getUserInfoFn = ()=>{
|
||||||
|
userInfoEditRef.value?.open()
|
||||||
|
}
|
||||||
// 修改密码 --- start
|
// 修改密码 --- start
|
||||||
const changePasswordDialog = ref(false)
|
let changePasswordDialog = ref(false)
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>();
|
||||||
// 提交信息
|
// 提交信息
|
||||||
const saveInfo = reactive({
|
let saveInfo = reactive({
|
||||||
original_password: '',
|
original_password: '',
|
||||||
password: '',
|
password: '',
|
||||||
password_copy: ''
|
password_copy: ''
|
||||||
})
|
});
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const formRules = reactive<FormRules>({
|
const formRules = reactive<FormRules>({
|
||||||
original_password: [
|
original_password: [
|
||||||
{ required: true, message: t('originalPasswordPlaceholder'), trigger: 'blur' }
|
{ required: true, message: t("originalPasswordPlaceholder"), trigger: "blur" },
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }
|
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||||
],
|
],
|
||||||
password_copy: [
|
password_copy: [
|
||||||
{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }
|
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||||
]
|
]
|
||||||
})
|
});
|
||||||
const submitForm = (formEl: FormInstance | undefined) => {
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return
|
if (!formEl) return
|
||||||
formEl.validate((valid) => {
|
formEl.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
let msg = ''
|
let msg = "";
|
||||||
if (saveInfo.password && !saveInfo.original_password) msg = t('originalPasswordHint')
|
if (saveInfo.password && !saveInfo.original_password) msg = t('originalPasswordHint');
|
||||||
if (saveInfo.password && saveInfo.original_password && !saveInfo.password_copy) msg = t('newPasswordHint')
|
if (saveInfo.password && saveInfo.original_password && !saveInfo.password_copy) msg = t('newPasswordHint');
|
||||||
if (saveInfo.password && saveInfo.original_password && saveInfo.password_copy && saveInfo.password != saveInfo.password_copy) msg = t('doubleCipherHint')
|
if (saveInfo.password && saveInfo.original_password && saveInfo.password_copy && saveInfo.password != saveInfo.password_copy) msg = t('doubleCipherHint');
|
||||||
if (msg) {
|
if (msg) {
|
||||||
ElNotification({
|
ElNotification({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: msg
|
message: msg,
|
||||||
})
|
})
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserInfo(saveInfo).then((res: any) => {
|
setUserInfo(saveInfo).then((res: any) => {
|
||||||
changePasswordDialog.value = false
|
changePasswordDialog.value = false;
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
// 修改密码 --- end
|
// 修改密码 --- end
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<layout-header></layout-header>
|
<layout-header></layout-header>
|
||||||
</el-header>
|
</el-header>
|
||||||
|
|
||||||
<el-main :class="['main-wrap h-full p-0',{'bg-page': dark}]">
|
<el-main :class="['main-wrap h-full p-0 bg-page']">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<div class="p-[10px]">
|
<div class="p-[10px]">
|
||||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<layout-header></layout-header>
|
<layout-header></layout-header>
|
||||||
</el-header>
|
</el-header>
|
||||||
|
|
||||||
<el-main class="main-wrap h-full p-0">
|
<el-main class="main-wrap h-full p-0 bg-page">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<div class="p-[10px]">
|
<div class="p-[10px]">
|
||||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||||
|
|||||||
@ -47,27 +47,19 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
to.redirectedFrom && (to.query = to.redirectedFrom.query)
|
to.redirectedFrom && (to.query = to.redirectedFrom.query)
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const siteInfo = userStore.siteInfo
|
const systemStore = useSystemStore()
|
||||||
const appType = getAppType()
|
const appType = getAppType()
|
||||||
|
|
||||||
let title: string = to.meta.title ?? ''
|
let title: string = to.meta.title ?? ''
|
||||||
|
|
||||||
if (!siteInfo && appType != 'home') {
|
if (!userStore.siteInfo && appType != 'home') {
|
||||||
await userStore.getSiteInfo()
|
await userStore.getSiteInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (siteInfo) {
|
|
||||||
title += '-' + siteInfo.site_name
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置网站标题
|
|
||||||
setWindowTitle(title)
|
|
||||||
|
|
||||||
// 加载语言包
|
// 加载语言包
|
||||||
await language.loadLocaleMessages(to.meta.addon || '', (to.meta.view || to.path), useSystemStore().lang);
|
await language.loadLocaleMessages(to.meta.addon || '', (to.meta.view || to.path), systemStore.lang);
|
||||||
|
|
||||||
let matched: any = to.matched;
|
let matched: any = to.matched;
|
||||||
|
|
||||||
if (matched && matched.length && matched[0].path != '/:pathMatch(.*)*') {
|
if (matched && matched.length && matched[0].path != '/:pathMatch(.*)*') {
|
||||||
matched = matched[0].path;
|
matched = matched[0].path;
|
||||||
} else {
|
} else {
|
||||||
@ -76,6 +68,15 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
|
|
||||||
const loginPath = to.path == '/' ? '/admin/login' : `/${matched == '/admin' ? 'admin' : 'site'}/login`
|
const loginPath = to.path == '/' ? '/admin/login' : `/${matched == '/admin' ? 'admin' : 'site'}/login`
|
||||||
|
|
||||||
|
if (appType != 'site' || to.path === loginPath) {
|
||||||
|
title += systemStore.website.site_name ? ('-' + systemStore.website.site_name) : ''
|
||||||
|
} else {
|
||||||
|
title += userStore.siteInfo && userStore.siteInfo.site_name ? ('-' + userStore.siteInfo.site_name) : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置网站标题
|
||||||
|
setWindowTitle(title)
|
||||||
|
|
||||||
// 判断是否需登录
|
// 判断是否需登录
|
||||||
if (NO_LOGIN_ROUTES.includes(to.path)) {
|
if (NO_LOGIN_ROUTES.includes(to.path)) {
|
||||||
next()
|
next()
|
||||||
|
|||||||
@ -36,34 +36,6 @@ export const ADMIN_ROUTE: RouteRecordRaw = {
|
|||||||
{
|
{
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: () => import('@/app/views/login/index.vue')
|
component: () => import('@/app/views/login/index.vue')
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'user',
|
|
||||||
component: Default,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'center',
|
|
||||||
meta: {
|
|
||||||
type: 1,
|
|
||||||
title: '个人中心'
|
|
||||||
},
|
|
||||||
component: () => import('@/app/views/index/personal.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'user',
|
|
||||||
component: Default,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'edit_center',
|
|
||||||
meta: {
|
|
||||||
type: 1,
|
|
||||||
title: '编辑个人中心'
|
|
||||||
},
|
|
||||||
component: () => import('@/app/views/index/edit_personal.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -103,34 +75,6 @@ export const SITE_ROUTE: RouteRecordRaw = {
|
|||||||
{
|
{
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: () => import('@/app/views/login/index.vue')
|
component: () => import('@/app/views/login/index.vue')
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'user',
|
|
||||||
component: Default,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'center',
|
|
||||||
meta: {
|
|
||||||
type: 1,
|
|
||||||
title: '个人中心'
|
|
||||||
},
|
|
||||||
component: () => import('@/app/views/site/personal.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'user',
|
|
||||||
component: Default,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'edit_center',
|
|
||||||
meta: {
|
|
||||||
type: 1,
|
|
||||||
title: '编辑个人中心'
|
|
||||||
},
|
|
||||||
component: () => import('@/app/views/site/edit_personal.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ const useDiyStore = defineStore('diy', {
|
|||||||
'#c7158577'
|
'#c7158577'
|
||||||
],
|
],
|
||||||
components: [], // 组件集合
|
components: [], // 组件集合
|
||||||
position: ['fixed', 'top_fixed','right_fixed','bottom_fixed','left_fixed'],
|
position: ['top_fixed','right_fixed','bottom_fixed','left_fixed','fixed'],
|
||||||
global: {
|
global: {
|
||||||
title: "页面", // 页面标题
|
title: "页面", // 页面标题
|
||||||
|
|
||||||
@ -211,7 +211,14 @@ const useDiyStore = defineStore('diy', {
|
|||||||
delete component.template;
|
delete component.template;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.checkComponentIsAdd(component)) return;
|
if (!this.checkComponentIsAdd(component)) {
|
||||||
|
// 组件最多只能添加n个
|
||||||
|
ElMessage({
|
||||||
|
type: 'warning',
|
||||||
|
message: `${component.componentTitle}${t('componentCanOnlyAdd')}${component.uses}${t('piece')}`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 置顶组件,只能在第一个位置中添加
|
// 置顶组件,只能在第一个位置中添加
|
||||||
if(component.position && this.position.indexOf(component.position) != -1){
|
if(component.position && this.position.indexOf(component.position) != -1){
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import { useCssVar } from '@vueuse/core'
|
import { useCssVar } from '@vueuse/core'
|
||||||
|
import { getWebConfig } from '@/app/api/sys'
|
||||||
|
|
||||||
interface System {
|
interface System {
|
||||||
menuIsCollapse: boolean,
|
menuIsCollapse: boolean,
|
||||||
@ -9,7 +10,9 @@ interface System {
|
|||||||
theme: string,
|
theme: string,
|
||||||
lang: string,
|
lang: string,
|
||||||
sidebar: string,
|
sidebar: string,
|
||||||
sidebarStyle: string
|
sidebarStyle: string,
|
||||||
|
currHeadMenuName: any,
|
||||||
|
website: Object
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = storage.get('theme') ?? {}
|
const theme = storage.get('theme') ?? {}
|
||||||
@ -25,7 +28,8 @@ const useSystemStore = defineStore('system', {
|
|||||||
sidebar: theme.sidebar ?? 'oneType',
|
sidebar: theme.sidebar ?? 'oneType',
|
||||||
lang: storage.get('lang') ?? 'zh-cn',
|
lang: storage.get('lang') ?? 'zh-cn',
|
||||||
sidebarStyle: theme.sidebarStyle ?? 'threeType',
|
sidebarStyle: theme.sidebarStyle ?? 'threeType',
|
||||||
currHeadMenuName: ''
|
currHeadMenuName: '',
|
||||||
|
website: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -41,6 +45,11 @@ const useSystemStore = defineStore('system', {
|
|||||||
this.menuIsCollapse = value
|
this.menuIsCollapse = value
|
||||||
storage.set({ key: 'menuiscollapse', data: value })
|
storage.set({ key: 'menuiscollapse', data: value })
|
||||||
useCssVar('--aside-width').value = value ? 'calc(var(--el-menu-icon-width) + var(--el-menu-base-level-padding) * 2)' : '210px'
|
useCssVar('--aside-width').value = value ? 'calc(var(--el-menu-icon-width) + var(--el-menu-base-level-padding) * 2)' : '210px'
|
||||||
|
},
|
||||||
|
async getWebsiteInfo() {
|
||||||
|
await getWebConfig().then(({ data }) => {
|
||||||
|
this.website = data
|
||||||
|
}).catch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import storage from '@/utils/storage'
|
|||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
||||||
import useTabbarStore from './tabbar'
|
import useTabbarStore from './tabbar'
|
||||||
|
import Test from '@/utils/test'
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
token: string,
|
token: string,
|
||||||
@ -41,6 +42,9 @@ const userStore = defineStore('user', {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
login(form, app_type)
|
login(form, app_type)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
if (app_type == 'admin' && Test.empty(res.data.userrole)) {
|
||||||
|
storage.setPrefix('site')
|
||||||
|
}
|
||||||
this.token = res.data.token
|
this.token = res.data.token
|
||||||
this.userInfo = res.data.userinfo
|
this.userInfo = res.data.userinfo
|
||||||
this.siteInfo = res.data.site_info || {}
|
this.siteInfo = res.data.site_info || {}
|
||||||
|
|||||||
@ -38,6 +38,10 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-container{
|
.main-container{
|
||||||
|
// background-color: #fff;
|
||||||
|
background-color: var(--el-bg-color-overlay);
|
||||||
|
min-height: calc(100vh - 84px);
|
||||||
|
overflow: hidden;
|
||||||
.full-container {
|
.full-container {
|
||||||
height: calc(100vh - 122px);
|
height: calc(100vh - 122px);
|
||||||
}
|
}
|
||||||
@ -54,11 +58,11 @@ html {
|
|||||||
height: 48px;
|
height: 48px;
|
||||||
|
|
||||||
.fixed-footer {
|
.fixed-footer {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
height: inherit;
|
height: inherit;
|
||||||
background:var(--el-bg-color-overlay);
|
background:var(--el-bg-color-overlay);
|
||||||
width: 100%;
|
right: 10px;
|
||||||
left: 0;
|
left: 10px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -257,7 +261,12 @@ html.dark {
|
|||||||
// background-color: #636363 !important;
|
// background-color: #636363 !important;
|
||||||
// opacity: 1 !important;
|
// opacity: 1 !important;
|
||||||
//}
|
//}
|
||||||
|
.el-card{
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
:root input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
|
:root input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
|
||||||
box-shadow: 0 0 50px 50px white inset;
|
box-shadow: 0 0 50px 50px white inset;
|
||||||
}
|
}
|
||||||
|
.text-page-title{
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 3883393 */
|
font-family: "iconfont"; /* Project id 3883393 */
|
||||||
src: url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.woff2?t=1711684151959') format('woff2'),
|
src: url('//at.alicdn.com/t/c/font_3883393_eqk4fw84z0e.woff2?t=1712631982793') format('woff2'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.woff?t=1711684151959') format('woff'),
|
url('//at.alicdn.com/t/c/font_3883393_eqk4fw84z0e.woff?t=1712631982793') format('woff'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.ttf?t=1711684151959') format('truetype');
|
url('//at.alicdn.com/t/c/font_3883393_eqk4fw84z0e.ttf?t=1712631982793') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,22 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconxingzhuang-wenzi:before {
|
||||||
|
content: "\eb99";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconxiaochengxu1:before {
|
||||||
|
content: "\e631";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconshipin1:before {
|
||||||
|
content: "\e63a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icontupian:before {
|
||||||
|
content: "\e667";
|
||||||
|
}
|
||||||
|
|
||||||
.iconfenxiang:before {
|
.iconfenxiang:before {
|
||||||
content: "\e655";
|
content: "\e655";
|
||||||
}
|
}
|
||||||
@ -21,10 +37,6 @@
|
|||||||
content: "\e63f";
|
content: "\e63f";
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconhuojian1:before {
|
|
||||||
content: "\e633";
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconkaifazujian:before {
|
.iconkaifazujian:before {
|
||||||
content: "\e640";
|
content: "\e640";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,38 @@
|
|||||||
{
|
{
|
||||||
"id": "3883393",
|
"id": "3883393",
|
||||||
"name": "系统",
|
"name": "niushop-vite-admin",
|
||||||
"font_family": "iconfont",
|
"font_family": "iconfont",
|
||||||
"css_prefix_text": "icon",
|
"css_prefix_text": "icon",
|
||||||
"description": "系统图标",
|
"description": "niushop-vite admin端",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "4354254",
|
||||||
|
"name": "形状-文字",
|
||||||
|
"font_class": "xingzhuang-wenzi",
|
||||||
|
"unicode": "eb99",
|
||||||
|
"unicode_decimal": 60313
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "4424124",
|
||||||
|
"name": "小程序",
|
||||||
|
"font_class": "xiaochengxu1",
|
||||||
|
"unicode": "e631",
|
||||||
|
"unicode_decimal": 58929
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "27876594",
|
||||||
|
"name": "视频1",
|
||||||
|
"font_class": "shipin1",
|
||||||
|
"unicode": "e63a",
|
||||||
|
"unicode_decimal": 58938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "29941073",
|
||||||
|
"name": "图片",
|
||||||
|
"font_class": "tupian",
|
||||||
|
"unicode": "e667",
|
||||||
|
"unicode_decimal": 58983
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "2672195",
|
"icon_id": "2672195",
|
||||||
"name": "分享",
|
"name": "分享",
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import axios, { HttpStatusCode } from 'axios'
|
|||||||
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig } from 'axios'
|
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig } from 'axios'
|
||||||
import { getToken, isUrl } from './common';
|
import { getToken, isUrl } from './common';
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MessageParams } from 'element-plus'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
@ -55,7 +56,7 @@ class Request {
|
|||||||
const res = response.data
|
const res = response.data
|
||||||
if (res.code != 1) {
|
if (res.code != 1) {
|
||||||
this.handleAuthError(res.code)
|
this.handleAuthError(res.code)
|
||||||
if (res.code != 401 && response.config.showErrorMessage !== false) ElMessage({ message: res.msg, type: 'error', dangerouslyUseHTMLString: true, duration: 5000 })
|
if (res.code != 401 && response.config.showErrorMessage !== false) this.showElMessage({ message: res.msg, type: 'error', dangerouslyUseHTMLString: true, duration: 5000 })
|
||||||
return Promise.reject(new Error(res.msg || 'Error'))
|
return Promise.reject(new Error(res.msg || 'Error'))
|
||||||
} else {
|
} else {
|
||||||
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
||||||
@ -168,7 +169,7 @@ class Request {
|
|||||||
const baseURL = isUrl(err.config.baseURL) ? err.config.baseURL : `${location.origin}${err.config.baseURL}`
|
const baseURL = isUrl(err.config.baseURL) ? err.config.baseURL : `${location.origin}${err.config.baseURL}`
|
||||||
errMessage = baseURL + t('axios.baseUrlError')
|
errMessage = baseURL + t('axios.baseUrlError')
|
||||||
}
|
}
|
||||||
errMessage && ElMessage({ dangerouslyUseHTMLString: true, duration: 5000, message: errMessage, type: 'error' })
|
errMessage && this.showElMessage({ dangerouslyUseHTMLString: true, duration: 5000, message: errMessage, type: 'error' })
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleAuthError(code: number) {
|
private handleAuthError(code: number) {
|
||||||
@ -178,6 +179,18 @@ class Request {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private messageCache = new Map();
|
||||||
|
|
||||||
|
private showElMessage(options: MessageParams) {
|
||||||
|
const cacheKey = options.message
|
||||||
|
const cachedMessage = this.messageCache.get(cacheKey);
|
||||||
|
|
||||||
|
if (!cachedMessage || Date.now() - cachedMessage.timestamp > 5000) { // 5秒内重复内容不再弹出,可自定义过期时间
|
||||||
|
this.messageCache.set(cacheKey, { timestamp: Date.now() });
|
||||||
|
ElMessage(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Request()
|
export default new Request()
|
||||||
|
|||||||
@ -14,6 +14,10 @@ class Storage {
|
|||||||
this.prefix = getAppType() == 'admin' ? 'admin' : 'site'
|
this.prefix = getAppType() == 'admin' ? 'admin' : 'site'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setPrefix(prefix: string) {
|
||||||
|
this.prefix = prefix
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置缓存
|
* 设置缓存
|
||||||
* @param param
|
* @param param
|
||||||
|
|||||||
@ -88,8 +88,11 @@ class ExceptionHandle extends Handle
|
|||||||
'trace' => $e->getTrace(),
|
'trace' => $e->getTrace(),
|
||||||
'previous' => $e->getPrevious(),
|
'previous' => $e->getPrevious(),
|
||||||
] : [];
|
] : [];
|
||||||
// 添加自定义异常处理机制
|
|
||||||
|
|
||||||
|
// 添加自定义异常处理机制
|
||||||
|
if (strpos($e->getMessage(), 'open_basedir') !== false) {
|
||||||
|
return fail('OPEN_BASEDIR_ERROR');
|
||||||
|
}
|
||||||
if ($e instanceof DbException) {
|
if ($e instanceof DbException) {
|
||||||
return fail(get_lang('DATA_GET_FAIL').':'.$e->getMessage(), [
|
return fail(get_lang('DATA_GET_FAIL').':'.$e->getMessage(), [
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
|
|||||||
@ -43,6 +43,17 @@ class Diy extends BaseAdminController
|
|||||||
return success(( new DiyService() )->getPage($data));
|
return success(( new DiyService() )->getPage($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notes 获取自定义页面分页列表,轮播搜索组件用
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getPageByCarouselSearch()
|
||||||
|
{
|
||||||
|
$data = $this->request->params([
|
||||||
|
]);
|
||||||
|
return success(( new DiyService() )->getPageByCarouselSearch($data));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notes 获取自定义页面列表
|
* @notes 获取自定义页面列表
|
||||||
* @return Response
|
* @return Response
|
||||||
|
|||||||
@ -25,6 +25,7 @@ use think\Response;
|
|||||||
|
|
||||||
class Login extends BaseAdminController
|
class Login extends BaseAdminController
|
||||||
{
|
{
|
||||||
|
use WapTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
@ -69,6 +70,12 @@ class Login extends BaseAdminController
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function test(){
|
public function test(){
|
||||||
|
$this->addon = 'shop';
|
||||||
|
$this->uninstallPageCode(project_path(). 'uni-app/src/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function geAddonPackagePath(string $addon)
|
||||||
|
{
|
||||||
|
return root_path() . 'addon' .DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,7 +85,7 @@ class Site extends BaseAdminController
|
|||||||
*/
|
*/
|
||||||
public function menu()
|
public function menu()
|
||||||
{
|
{
|
||||||
return success((new AuthSiteService())->getMenuList(1, 'all', 'all', 0));
|
return success((new AuthSiteService())->getMenuList(1, 1, 'all', 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user