update admin

This commit is contained in:
全栈小学生 2024-06-15 15:34:55 +08:00
parent af96bb867b
commit 7e5030ae3b
273 changed files with 11612 additions and 10696 deletions

View File

@ -2,7 +2,6 @@ import request from '@/utils/request'
/**
*
* @param addon
*/
export function cloudBuild() {
return request.post('niucloud/build', {})
@ -10,7 +9,6 @@ export function cloudBuild() {
/**
*
* @param addon
*/
export function getCloudBuildTask() {
return request.get('niucloud/build')

View File

@ -8,15 +8,16 @@ import request from '@/utils/request'
* @returns
*/
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})
return request.get(`diy/carousel_search`, {params})
}
/**
@ -25,7 +26,7 @@ export function getDiyPageListByCarouselSearch(params: Record<string, any>) {
* @returns
*/
export function getDiyList(params: Record<string, any>) {
return request.get(`diy/list`, {params})
return request.get(`diy/list`, {params})
}
/**
@ -34,7 +35,7 @@ export function getDiyList(params: Record<string, any>) {
* @returns
*/
export function getDiyPageInfo(id: number) {
return request.get(`diy/diy/${id}`);
return request.get(`diy/diy/${id}`);
}
/**
@ -43,7 +44,7 @@ export function getDiyPageInfo(id: number) {
* @returns
*/
export function addDiyPage(params: Record<string, any>) {
return request.post('diy/diy', params, {showSuccessMessage: true})
return request.post('diy/diy', params, {showSuccessMessage: true})
}
/**
@ -51,7 +52,7 @@ export function addDiyPage(params: Record<string, any>) {
* @param params
*/
export function editDiyPage(params: Record<string, any>) {
return request.put(`diy/diy/${params.id}`, params, {showSuccessMessage: true})
return request.put(`diy/diy/${params.id}`, params, {showSuccessMessage: true})
}
/**
@ -59,7 +60,7 @@ export function editDiyPage(params: Record<string, any>) {
* @param params
*/
export function setUseDiyPage(params: Record<string, any>) {
return request.put(`diy/use`, params, {showSuccessMessage: true})
return request.put(`diy/use`, params, {showSuccessMessage: true})
}
/**
@ -67,7 +68,7 @@ export function setUseDiyPage(params: Record<string, any>) {
* @param params
*/
export function editDiyPageShare(params: Record<string, any>) {
return request.put(`diy/diy/share`, params, {showSuccessMessage: true})
return request.put(`diy/diy/share`, params, {showSuccessMessage: true})
}
/**
@ -76,35 +77,35 @@ export function editDiyPageShare(params: Record<string, any>) {
* @returns
*/
export function deleteDiyPage(id: number) {
return request.delete(`diy/diy/${id}`, {showSuccessMessage: true})
return request.delete(`diy/diy/${id}`, {showSuccessMessage: true})
}
/**
*
*/
export function initPage(params: Record<string, any>) {
return request.get(`diy/init`, {params})
return request.get(`diy/init`, {params})
}
/**
*
*/
export function getLink(params: Record<string, any>) {
return request.get(`diy/link`, {params})
return request.get(`diy/link`, {params})
}
/**
*
*/
export function getDiyBottomList(params: Record<string, any>) {
return request.get(`diy/bottom`, {params})
return request.get(`diy/bottom`, {params})
}
/**
*
*/
export function getDiyBottomConfig(params: Record<string, any>) {
return request.get(`diy/bottom/config`, {params})
return request.get(`diy/bottom/config`, {params})
}
/**
@ -113,21 +114,21 @@ export function getDiyBottomConfig(params: Record<string, any>) {
* @returns
*/
export function setDiyBottomConfig(params: Record<string, any>) {
return request.post('diy/bottom', params, {showSuccessMessage: true})
return request.post('diy/bottom', params, {showSuccessMessage: true})
}
/**
*
*/
export function getDiyTemplate(params: Record<string, any>) {
return request.get(`diy/template`, {params})
return request.get(`diy/template`, {params})
}
/**
*
*/
export function getDiyTemplatePages(params: Record<string, any>) {
return request.get(`diy/template/pages`, {params})
return request.get(`diy/template/pages`, {params})
}
/**
@ -136,7 +137,7 @@ export function getDiyTemplatePages(params: Record<string, any>) {
* @returns
*/
export function getDiyRouteList(params: Record<string, any>) {
return request.get(`diy/route`, {params})
return request.get(`diy/route`, {params})
}
/**
@ -144,7 +145,7 @@ export function getDiyRouteList(params: Record<string, any>) {
* @returns
*/
export function getDiyRouteAppList() {
return request.get(`diy/route/apps`)
return request.get(`diy/route/apps`)
}
/**
@ -152,7 +153,7 @@ export function getDiyRouteAppList() {
* @param params
*/
export function getDiyRouteInfo(params: Record<string, any>) {
return request.get(`diy/route/info`, {params});
return request.get(`diy/route/info`, {params});
}
/**
@ -160,7 +161,7 @@ export function getDiyRouteInfo(params: Record<string, any>) {
* @param params
*/
export function editDiyRouteShare(params: Record<string, any>) {
return request.put(`diy/route/share`, params, {showSuccessMessage: true})
return request.put(`diy/route/share`, params, {showSuccessMessage: true})
}
/**
@ -169,7 +170,7 @@ export function editDiyRouteShare(params: Record<string, any>) {
* @returns
*/
export function getDecoratePage(params: Record<string, any>) {
return request.get(`diy/decorate`, {params})
return request.get(`diy/decorate`, {params})
}
/**
@ -178,7 +179,7 @@ export function getDecoratePage(params: Record<string, any>) {
* @returns
*/
export function changeTemplate(params: Record<string, any>) {
return request.put(`diy/change`, params, {showSuccessMessage: true})
return request.put(`diy/change`, params, {showSuccessMessage: true})
}
/**
@ -187,5 +188,5 @@ export function changeTemplate(params: Record<string, any>) {
* @returns
*/
export function getApps(params: Record<string, any>) {
return request.get(`diy/apps`)
return request.get(`diy/apps`)
}

View File

@ -3,3 +3,17 @@ import request from '@/utils/request'
export function getHomeSite(params: Record<string, any>) {
return request.get(`home/site`, { params })
}
/**
*
*/
export function getSiteGroup() {
return request.get(`home/site/group`)
}
/**
*
*/
export function createSite(params: Record<string, any>) {
return request.post(`home/site/create`, params)
}

View File

@ -33,7 +33,6 @@ export function getModule() {
/**
*
* @param params
* @returns
*/
export function getModuleVersion() {
@ -51,7 +50,6 @@ export function downloadVersion(params: Record<string, any>) {
/**
*
* @param params
* @returns
*/
export function getFrameworkNewVersion() {

View File

@ -48,7 +48,7 @@ export function getPayRefundPages(params: Record<string, any>) {
/**
* 退
* @param id
* @param refund_no
*/
export function getPayRefundInfo(refund_no: string) {
return request.get(`pay/refund/${refund_no}`)
@ -56,7 +56,6 @@ export function getPayRefundInfo(refund_no: string) {
/**
* 退
* @param id
*/
export function getRefundType() {
return request.get(`pay/refund/type`)
@ -64,8 +63,15 @@ export function getRefundType() {
/**
* 退
* @param id
* @param params
*/
export function getRefundTransfer(params: Record<string, any>) {
return request.post(`pay/refund/transfer`, params, {showSuccessMessage: true})
}
}
/**
*
*/
export function getAllPayType() {
return request.get(`pay/type/all`)
}

View File

@ -83,7 +83,7 @@ export function getSiteGroupList(params: Record<string, any>) {
/**
*
* @param site_id
* @param groupId
*/
export function getSiteGroupInfo(groupId: number) {
return request.get(`site/group/${groupId}`);
@ -123,6 +123,14 @@ export function getSiteGroupAll(params: Record<string, any> = {}) {
return request.get(`site/group/all`)
}
/**
* ()
* @param params
*/
export function getUserSiteGroupAll(params: Record<string, any> = {}) {
return request.get(`site/group/user`, { params })
}
/***************************************************** 当前站点用户 *************************************************/
/**
@ -159,15 +167,6 @@ export function editUser(params: Record<string, any>) {
return request.put(`site/user/${params.uid}`, params, { showSuccessMessage: true })
}
/**
*
* @param uid
* @returns
*/
export function deleteUser(uid: number) {
return request.delete(`site/user/${uid}`, { showSuccessMessage: true })
}
/**
*

View File

@ -81,6 +81,7 @@ export function getMenus(type: string) {
/**
*
* @param app_type
* @param menu_key
*/
export function getMenuInfo(app_type: string, menu_key: string) {
@ -106,6 +107,7 @@ export function editMenu(params: Record<string, any>) {
/**
*
* @param app_type
* @param menu_key
*/
export function deleteMenu(app_type: string, menu_key: string) {
@ -311,7 +313,6 @@ export function getIconList(params: Record<string, any>) {
/**
* evn
* @param params
* @returns
*/
export function getEnv() {
@ -414,7 +415,7 @@ export function getPayList() {
*
* @param channel
*/
export function getTransferInfo(channel) {
export function getTransferInfo(channel: string) {
return request.get(`pay/channel/lists/${channel}`)
}
@ -624,14 +625,6 @@ export function setIndexList(params: Record<string, any>) {
return request.put(`sys/config/site_index`, params, { showSuccessMessage: true })
}
/**
*
* @returns
*/
export function getLayouts() {
return request.get('sys/layout')
}
/**
*
*/
@ -719,6 +712,24 @@ export function setLayout(params: Record<string, any>) {
return request.put(`sys/config/layout`, params, { showSuccessMessage: true })
}
/**
*
* @returns
*/
export function getThemecolor() {
return request.get('sys/config/themecolor')
}
/**
*
* @param params
* @returns
*/
export function setThemecolor(params: Record<string, any>) {
return request.put(`sys/config/themecolor`, params)
}
/***************************************************** 报表导出 ****************************************************/
/**
@ -767,4 +778,12 @@ export function exportDataCheck(type: string, params: Record<string, any>) {
*/
export function deleteExport(id: number) {
return request.delete(`sys/export/${id}`, { showSuccessMessage: true })
}
}
/**
*
* @returns
*/
export function getWxoplatform() {
return request.get('sys/wxoplatform/config')
}

View File

@ -37,7 +37,7 @@ export function getAddonDevelopCheck(key: any) {
* key黑名单
* @returns
*/
export function getAddonKeyBlackList(key: any) {
export function getAddonKeyBlackList() {
return request.get('addon_develop/key/blacklist')
}

View File

@ -11,7 +11,6 @@ export function getUpgradeContent(addon: string = '') {
/**
*
* @param addon
*/
export function getUpgradeTask() {
return request.get('upgrade/task')

View File

@ -6,8 +6,8 @@ import request from '@/utils/request'
/**
*
* @param params
* @returns
* @param params
* @returns
*/
export function getUserList(params: Record<string, any>) {
return request.get(`user/user`, { params })
@ -16,7 +16,7 @@ export function getUserList(params: Record<string, any>) {
/**
*
* @param uid uid
* @returns
* @returns
*/
export function getUserInfo(uid: number) {
return request.get(`user/user/${uid}`);
@ -24,25 +24,17 @@ export function getUserInfo(uid: number) {
/**
*
* @param params
* @returns
* @param params
* @returns
*/
export function addUser(params: Record<string, any>) {
return request.post('user/user', params, { showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editUser(params: Record<string, any>) {
return request.put(`user/user/${params.uid}`, params, { showSuccessMessage: true })
}
/**
*
* @param params
* @returns
* @param params
* @returns
*/
export function getAllUserList(params: Record<string, any>) {
return request.get(`user/user_all`, { params })
@ -50,9 +42,49 @@ export function getAllUserList(params: Record<string, any>) {
/**
*
* @param username
* @returns
* @param username
* @returns
*/
export function checkUsernameIsExist(username: string) {
return request.get(`user/isexist`, { params: { username } })
}
}
/**
*
* @param params
*/
export function getUserCreateSiteLimit(uid: number) {
return request.get(`user/user/create_site_limit/${uid}`)
}
/**
*
* @param id
*/
export function getUserCreateSiteLimitInfo(id: number) {
return request.get(`user/user/create_site_limit/info/${id}`)
}
/**
*
* @param params
*/
export function addUserCreateSiteLimit(params: Record<string, any>) {
return request.post(`user/user/create_site_limit`, params, { showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editUserCreateSiteLimit(params: Record<string, any>) {
return request.put(`user/user/create_site_limit/${params.id}`, params, { showSuccessMessage: true })
}
/**
*
* @param params
*/
export function delUserCreateSiteLimit(id: number) {
return request.delete(`user/user/create_site_limit/${id}`, { showSuccessMessage: true })
}

View File

@ -33,10 +33,19 @@ export function getVerifierList(params: Record<string, any>) {
}
/**
*
*
* @param params
* @returns
*/
export function getVerifierSelect() {
return request.get(`verify/verifier/select`)
}
/**
*
* @returns
*/
export function getVerifyTypeList() {
return request.get(`verify/verifier/type`)
}

View File

@ -124,7 +124,6 @@ export function setSubscribeReply(params: Record<string, any>) {
return request.put('wechat/reply/subscribe', params, { showSuccessMessage: true })
}
/**
*
*/

View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
/**
*
* @returns
*/
export function getConfig() {
return request.get('wxoplatform/config')
}
/**
*
*/
export function getStatic() {
return request.get('wxoplatform/static');
}
/**
*
* @param params
* @returns
*/
export function editConfig(params: Record<string, any>) {
return request.put('wxoplatform/config', params, { showSuccessMessage: true })
}
/**
* url
*/
export function getAuthorizationUrl() {
return request.get('wxoplatform/authorizationUrl');
}
/**
*
*/
export function getAuthorizationResult(params: Record<string, any>) {
return request.get('wxoplatform/authorization', { params, showErrorMessage: false });
}
/**
*
* @returns
*/
export function weappCommit() {
return request.post('wxoplatform/weapp/version/commit', {}, { showSuccessMessage: true })
}
/**
*
*/
export function getWeappCommitRecord(params: Record<string, any>) {
return request.get('wxoplatform/weapp/commit', { params })
}
/**
*
*/
export function getWeappLastCommitRecord() {
return request.get('wxoplatform/weapp/commit/last')
}
/**
*
* @returns
*/
export function siteWeappCommit() {
return request.post('wxoplatform/site/weapp/commit', {}, { showSuccessMessage: true })
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,8 +1,7 @@
<template>
<el-dialog v-model="showDialog" :title="t('cloudbuild.title')" width="850px" :close-on-click-modal="false"
:close-on-press-escape="false" :before-close="dialogClose">
<el-dialog v-model="showDialog" :title="t('cloudbuild.title')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false" :before-close="dialogClose">
<div v-show="active == 'build'" class="h-[60vh]" v-loading="loading">
<div v-if="active == 'build'" class="h-[60vh]" v-loading="loading">
<div class="h-[60vh] flex flex-col" v-if="cloudBuildCheck && !cloudBuildTask">
<el-scrollbar>
<div class="bg-[#fff] my-3" v-if="cloudBuildCheck.dir">
@ -19,8 +18,7 @@
<span>{{ t('status') }}</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]"
v-for="item in cloudBuildCheck.dir.is_readable">
<el-row class="pb-[10px] items pl-[15px]" v-for="item in cloudBuildCheck.dir.is_readable">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
@ -36,8 +34,7 @@
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]"
v-for="item in cloudBuildCheck.dir.is_write">
<el-row class="pb-[10px] items pl-[15px]" v-for="item in cloudBuildCheck.dir.is_write">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
@ -47,10 +44,10 @@
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
</div>
@ -58,12 +55,11 @@
</el-scrollbar>
</div>
<div class="h-[60vh]" v-show="cloudBuildTask">
<terminal ref="terminalRef" context="" :init-log="null" :show-header="false"
:show-log-time="true" @exec-cmd="onExecCmd"/>
<terminal ref="terminalRef" context="" :init-log="null" :show-header="false" :show-log-time="true" @exec-cmd="onExecCmd"/>
</div>
</div>
<div v-show="active == 'complete'">
<div v-if="active == 'complete'">
<div class="h-[60vh] flex flex-col">
<div class="flex-1 h-0">
<el-result icon="success" :title="t('cloudbuild.cloudbuildSuccess')"></el-result>
@ -81,7 +77,6 @@ import { Terminal, TerminalFlash } from 'vue-web-terminal'
import 'vue-web-terminal/lib/theme/dark.css'
import { AnyObject } from "@/types/global"
import { ElNotification, ElMessageBox } from "element-plus"
import {preUpgradeCheck} from "@/app/api/upgrade";
const showDialog = ref<boolean>(false)
const cloudBuildTask = ref<null | AnyObject>(null)
@ -120,7 +115,7 @@ const getCloudBuildLogFn = () => {
return
}
const data = res.data.data ?? []
const data = res.data.data ?? [];
let error = ''
if (data[0] && data[0].length && showDialog.value) {
@ -174,11 +169,11 @@ const elNotificationClick = () => {
}
const open = async () => {
showDialog.value = true
loading.value = true
active.value = 'build'
if (cloudBuildTask.value) {
showDialog.value = true
loading.value = false
getCloudBuildLogFn()
return
@ -189,9 +184,11 @@ const open = async () => {
cloudBuild().then(({ data }) => {
loading.value = false
cloudBuildTask.value = data
showDialog.value = true
getCloudBuildLogFn()
}).catch(() => {
showDialog.value = false
loading.value = false
})
} else {
loading.value = false
@ -205,7 +202,7 @@ const open = async () => {
/**
* 升级进度动画
*/
let flashInterval = null
let flashInterval: null | number = null
const terminalFlash = new TerminalFlash()
const onExecCmd = (key, command, success, failed, name) => {
if (command == '开始编译') {
@ -230,7 +227,7 @@ const makeIterator = (array: string[]) => {
}
const dialogClose = (done: () => {}) => {
if (active.value == 'cloudbuild' && cloudBuildTask.value) {
if (active.value == 'build' && cloudBuildTask.value) {
ElMessageBox.confirm(
t('cloudbuild.showDialogCloseTips'),
t('warning'),
@ -240,6 +237,7 @@ const dialogClose = (done: () => {}) => {
type: 'warning'
}
).then(() => {
terminalRef.value.execute('clear')
done()
}).catch(() => { })
} else {
@ -249,6 +247,7 @@ const dialogClose = (done: () => {}) => {
watch(() => showDialog.value, () => {
if (!showDialog.value) {
cloudBuildTask.value = null
active.value = 'build'
cloudBuildLog = []
flashInterval && clearInterval(flashInterval)
@ -258,7 +257,8 @@ watch(() => showDialog.value, () => {
defineExpose({
open,
cloudBuildTask
cloudBuildTask,
loading
})
</script>

View File

@ -45,8 +45,7 @@
<span>{{ t('status') }}</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]"
v-for="item in upgradeCheck.dir.is_readable">
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_readable">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
@ -56,14 +55,13 @@
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]"
v-for="item in upgradeCheck.dir.is_write">
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_write">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
@ -73,10 +71,10 @@
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
</div>
@ -84,8 +82,7 @@
</el-scrollbar>
</div>
<div class="h-[60vh]" v-show="upgradeTask">
<terminal ref="terminalRef" :context="upgradeTask ? upgradeTask.upgrade.app_key : ''" :init-log="null" :show-header="false"
:show-log-time="true" @exec-cmd="onExecCmd"/>
<terminal ref="terminalRef" :context="upgradeTask ? upgradeTask.upgrade.app_key : ''" :init-log="null" :show-header="false" :show-log-time="true" @exec-cmd="onExecCmd"/>
</div>
</div>

View File

@ -1,12 +1,8 @@
<template>
<el-dialog
v-model="dialogVisible"
:title="t('accountSettings')"
width="500"
>
<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" />
<upload-image v-model="saveInfo.head_img" :limit="1" :type="'avatar'" />
</el-form-item>
<el-form-item :label="t('userName')">
<span>{{saveInfo.username}}</span>
@ -27,10 +23,12 @@
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { deepClone } from '@/utils/common'
import { getUserInfo, setUserInfo } from '@/app/api/personal'
import { useRouter } from 'vue-router'
import useUserStore from '@/stores/modules/user'
const userStore = useUserStore()
const router = useRouter()
//
const saveInfo = reactive({})
@ -42,7 +40,6 @@ const dialogVisible = ref(false)
* 获取用户信息
*/
const getUserInfoFn = () => {
getUserInfo().then(res => {
loading.value = false
const data = res.data
@ -64,6 +61,9 @@ const submitForm = (formEl: FormInstance | undefined) => {
setUserInfo(saveInfo).then((res: any) => {
loading.value = false
dialogVisible.value = false
let data = deepClone(userStore.userInfo)
data.head_img = saveInfo.head_img
userStore.setUserInfo(data)
}).catch(() => {
loading.value = false
})

View File

@ -19,5 +19,9 @@
"wechatSet": "小程序配置",
"subscribeMessage": "订阅消息",
"weappRelease": "版本管理",
"alert":"您正在体验通用版小程序,不发布你将不可用"
"alert":"您正在体验通用版小程序,不发布你将不可用",
"authWeapp": "授权绑定微信小程序",
"clickSetting": "点击配置微信小程序",
"seeConfig": "查看配置",
"refreshAuth": "重新授权"
}

View File

@ -41,5 +41,6 @@
"localInsertTips": "请先将uni-app编译成微信小程序然后使用微信开发者工具进行上传",
"uploadSuccessTips": "小程序上传成功后还需到<a href='https://mp.weixin.qq.com/' target='_blank' class='text-primary'>微信公众平台</a>提交审核,审核通过后发布才算正式上线。",
"knownToKnow": "我已知晓,不需要再次提示",
"siteAuthTips": "上传代码需先绑定授权码,请联系平台管理员进行绑定"
"siteAuthTips": "上传代码需先绑定授权码,请联系平台管理员进行绑定",
"againUpload": "重新上传"
}

View File

@ -7,7 +7,7 @@
"clickAccess": "点击接入",
"wechatSetting": "微信公众号配置",
"wechatSetting1": "微信公众号认证之后配置微信公众号连接,具体查看配置与发布教程",
"settingInfo": "点击配置",
"settingInfo": "点击配置微信公众号",
"wechatAccess": "微信公众号发布",
"releaseCourse": "发布教程",
"completeAccess": "完成接入",
@ -16,5 +16,9 @@
"wechatAccessBtn": "查看审核进度",
"clickAccess2":"扫描二维码进入微信公众号",
"wechatTemplate": "模板消息",
"reply": "自动回复"
"reply": "自动回复",
"authWechat": "授权绑定微信公众号",
"clickSetting": "点击配置微信公众号",
"seeConfig": "查看配置",
"refreshAuth": "重新授权"
}

View File

@ -155,10 +155,6 @@
"customGoods": "手动选择",
"goodsNum": "商品数量",
"selectCategory": "选择分类",
"isBecomeFenxiao": "成为分销商",
"isBecomeFenxiaoDesc": "是否展示会员成为分销商的按钮",
"are": "是",
"no": "否",
"categoryName": "分类名称",
"categoryImage": "分类图片",
"selectSource": "选择数据源",

View File

@ -38,7 +38,9 @@
"newSite": "新增站点",
"appMarketplace": "应用市场",
"siteDistribution": "站点分布",
"addUser": "新增用户",
"normalSiteSum": "正常站点(个)",
"weekExpireSiteCount":"即将到期站点(个)",
"expireSiteSum": "过期站点(个)",
"noInstallAppSun": "未安装应用(个)",
"installAppSun": "已安装应用(个)",

View File

@ -67,7 +67,7 @@
"addonUninstall": "插件卸载",
"appIdentification":"应用标识",
"tipText":"标识指开发应用或插件的文件夹名称",
"uninstallTips": "卸载插件将会移除admin web uni-app目录下该插件的内容是否要继续进行卸载?",
"uninstallTips": "是否要卸载该插件",
"upgrade": "升级",
"newVersion": "最新版本",
"cloudBuild": "云编译",

View File

@ -21,6 +21,7 @@
"verifyType": "核销类型",
"verifyTypePlaceholder": "请选择核销类型",
"verifier": "核销员",
"verifierPlaceholder": "请选择核销员",
"createTime":"添加时间",
"addVerifier":"添加核销员",
"verifierDeleteTips":"确定要删除该核销员吗?",

View File

@ -16,5 +16,10 @@
"growthFormatError": "成长值只能为整数",
"growthNeedLt": "成长值需小于",
"growthNeedGt": "成长值需大于",
"growthTips": "升级到该等级需达到的最低成长值"
"growthTips": "升级到该等级需达到的最低成长值",
"levelStyle": "等级样式",
"levelImg": "等级图标",
"bgColor": "背景颜色",
"bgImg": "背景图片",
"borderColor": "边框颜色"
}

View File

@ -50,5 +50,6 @@
"memberInfoPlaceholder":"请输入会员编号/昵称/手机号",
"lock": "锁定",
"normal": "正常",
"memberLevel": "会员等级"
"memberLevel": "会员等级",
"memberLevelPlaceholder": "请选择会员等级"
}

View File

@ -3,5 +3,7 @@
"setting": "设置",
"selectLayout": "选择布局",
"emptyData": "还没有安装应用",
"manyApp": "多应用"
"manyApp": "多应用",
"layout": "布局",
"themeColor": "色调"
}

View File

@ -10,6 +10,7 @@
"isBindMobileTip": "开启之后,会员通过账号或者第三方注册账户会强制绑定手机号,方便商家进行管理,同时方便会员在不同端口统一账号",
"agreement": "政策协议",
"agreementTips": "注册时服务协议和隐私协议是否进行展示",
"mobileOrUsernameNoEmpty":"普通注册方式至少需启用一种",
"commonSetting": "通用设置",
"tripartiteSetting": "第三方设置"
}

View File

@ -43,7 +43,7 @@
"defaultTamplate": "请选择模板",
"isEnable": "是否启用",
"onState": "开启状态",
"configurePaymentMethod": "请先配置该支付方式",
"configurePaymentMethod": "请先配置该支付方式",
"enablePaymentMode": "请先开启该支付方式",
"clickConfigure": "点击配置",
"setConfig": "设置支付配置",
@ -58,4 +58,4 @@
"collectionBankPlaceholder": "请输入收款银行",
"collectionAccountPlaceholder": "请输入收款账号",
"collectionDescPlaceholder": "请输入转账说明"
}
}

View File

@ -1,19 +0,0 @@
{
"oplatformSetting": "开放平台设置",
"appidPlaceholder": "微信第三方平台AppId",
"appsecretPlaceholder": "微信第三方平台AppSecret",
"oplatformComm": "开放平台通信",
"empowerStartDomain": "授权发起页域名",
"empowerReceiveUrl": "授权事件接收URL",
"messageValidationToken": "消息校验Token",
"messageDecryptKey": "消息加解密Key",
"messageReceiveUrl": "消息与事件接收URL",
"wechatDomain": "公众号开发域名",
"weappDomain": "小程序服务器域名",
"weappBusinessDomain": "小程序业务域名",
"oplatformBuilder": "开发者设置",
"builderEmail": "开发者邮箱",
"builderMobile": "开发者手机号",
"builderQQ": "开发者QQ",
"builderWx": "开发者微信"
}

View File

@ -15,6 +15,7 @@
"statusExpire":"已到期",
"phone":"客服电话",
"groupIdPlaceholder":"请选择套餐",
"uIdPlaceholder":"请选择站点管理员",
"appIdPlaceholder":"请选择应用",
"keywordsPlaceholder":"请输入关键字",
"keywords":"关键字",

View File

@ -8,5 +8,21 @@
"siteNum": "站点数量",
"endDate": "结束时间",
"startDate": "开始时间",
"loginTime": "最后登录时间"
"loginTime": "最后登录时间",
"addUser": "添加用户",
"username": "账号",
"passwordPlaceholder": "请输入用户密码",
"usernamePlaceholder": "请输入用户账号",
"realNamePlaceholder": "请输入真实姓名",
"confirmPasswordPlaceholder": "请再次确认密码",
"userRealNamePlaceholder": "请输入名称",
"userCreateSiteLimit": "套餐权限",
"siteGroup": "站点套餐",
"siteMonth": "站点效期限",
"siteNum": "建站数量",
"month": "月",
"siteMonthPlaceholder": "请输入站点效期限",
"siteNumPlaceholder": "请输入建站数量",
"siteMonthCannotLtOne": "站点效期限不能小于1",
"siteNumCannotLtOne": "建站数量不能小于1"
}

View File

@ -13,5 +13,18 @@
"lastLoginTime": "最后登录时间",
"lastLoginIP": "最后登录IP",
"yes": "是",
"no": "否"
}
"no": "否",
"siteGroup": "站点套餐",
"siteGroupPlaceholder": "请选择站点套餐",
"userCreateSiteLimit": "套餐权限",
"addSserCreateSiteLimit": "添加套餐权限",
"createSiteNum": "可创建站点数量",
"createSiteTimeLimit": "站点有效期限",
"month": "月",
"createdSiteNum": "已创建站点数",
"numPlaceholder": "请输入可创建站点数量",
"monthPlaceholder": "请输入站点创建有效期限",
"numCannotLtZero": "站点创建数量不能小于0",
"monthCannotLtZero": "站点创建有效期不能小于0",
"createSiteTimeLimitDeleteTips": "确认要删除吗?"
}

View File

@ -9,7 +9,7 @@
"key":"插件标识",
"type":"插件类型",
"version":"版本号",
"stutas":"状态",
"status":"状态",
"codeDeleteTips":"删除插件后对应文件会一并删除,是否确认",
"step1":"新建一个插件",
"describe1":"点击新建插件,生成插件后系统会生成对应插件的基础代码",

View File

@ -0,0 +1,33 @@
{
"oplatformSetting": "开放平台设置",
"appidPlaceholder": "请输入微信第三方平台AppId",
"appSecretPlaceholder": "请输入微信第三方平台AppSecret",
"tokenPlaceholder": "请输入消息校验Token",
"aesKeyPlaceholder": "请输入消息加解密Key",
"oplatformComm": "开放平台通信",
"empowerStartDomain": "授权发起页域名",
"empowerReceiveUrl": "授权事件接收URL",
"messageValidationToken": "消息校验Token",
"messageDecryptKey": "消息加解密Key",
"messageReceiveUrl": "消息与事件接收URL",
"wechatDomain": "公众号开发域名",
"weappDomain": "小程序服务器域名",
"weappBusinessDomain": "小程序业务域名",
"oplatformBuilder": "开发者设置",
"builderEmail": "开发者邮箱",
"builderMobile": "开发者手机号",
"builderQQ": "开发者QQ",
"builderWx": "开发者微信",
"messageDecryptKeyTips": "在代替公众号或小程序收发消息过程中使用。必须是长度为43位的字符串只能是字母和数字。",
"regenerate": "重新生成",
"messagesReceiving": "消息与事件接收",
"domainSetting": "域名配置",
"developerWeappUpload": "开发小程序配置",
"developerAppid": "开发小程序appid",
"uploadKey": "代码上传密钥",
"uploadKeyTips": "",
"uploadIpTips": "",
"developAppid": "开发小程序APPID",
"developAppidPlaceholder": "请输入开发小程序APPID",
"uploadIpTips": "如果小程序代码上传开启了ip白名单设置在ip白名单中添加ip"
}

View File

@ -0,0 +1,11 @@
{
"groupName": "站点套餐",
"lastTime": "上次同步时间",
"weappVersionUpdate": "小程序同步",
"weappVersionUpdateRecord": "小程序同步记录",
"createTime": "提交时间",
"userVersion": "版本号",
"failReason": "失败原因",
"updateTips": "版本提交成功之后会自动给已授权的小程序进行同步更新,使用该功能必须要启动消息队列",
"seeUpdateRecord": "查看同步记录"
}

View File

@ -1,90 +1,92 @@
<template>
<div class="main main-container min-w-[1000px] min-h-[650px]" v-loading="loading">
<el-card class="box-card !border-none" shadow="never" v-if="!loading">
<div class="flex">
<div class="bg-[#F3F6FF] mr-[14px] w-[402px] pt-[30px] pl-[32px] pr-[20px] pb-[60px] timeline-log-wrap">
<div class="flex items-center justify-between">
<span class="text-page-title">版本信息</span>
<!--授权信息-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never" v-if="!loading">
<div class="flex">
<div class="w-[450px] mr-[20px] p-[50px] bg-[var(--el-color-info-light-9)]">
<div class="flex items-center justify-between">
<span class="text-page-title">版本信息</span>
<div class="flex-1 w-0 flex justify-end">
<el-button class="text-[#4C4C4C] w-[78px] h-[32px] !bg-transparent" @click="getFrameworkVersionListFn" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">检测更新</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleUpgrade" v-else>一键升级</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleCloudBuild">云编译</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleCloudBuild" :loading="cloudBuildRef?.loading">云编译</el-button>
</div>
</div>
<div class="mt-[30px] flex items-center text-[14px] text-[#797979]">
<span>当前版本</span>
<span class="text-[26px] ml-[15px] mr-[10px] text-[#656668]">{{versions}}</span>
<em class="text-[12px]" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">(当前已是最新版本)</em>
</div>
<div class="mt-[30px] flex items-center text-[14px] text-[#797979]">
<span>当前版本</span>
<span class="text-[26px] ml-[15px] mr-[10px] text-[#656668]">{{versions}}</span>
<em class="text-[12px]" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">(当前已是最新版本)</em>
<em class="text-[12px] text-[red]" v-else>(最新版本{{ newVersion.version_no }})</em>
</div>
</div>
<div class="flex-1 flex justify-between items-center bg-[#F3F6FF] pt-[34px] pl-[30px] pr-[60px] pb-[62px] timeline-log-wrap">
<div class="flex flex-col">
<div class="flex flex-wrap items-center">
<p class="text-page-title mr-[20px]">授权信息</p>
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
</div>
<div class="mt-[46px] ml-[40px] flex flex-wrap">
<span class="text-[14px] mr-[84px]">授权域名<em class="ml-[12px] text-[12px]">{{ authinfo.site_address || '--' }}</em></span>
<span class="text-[14px] flex items-center">
<span>授权码</span>
<em class="ml-[12px] mr-[10px] text-[12px]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<View />
</el-icon>
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<Hide />
</el-icon>
</span>
</div>
</div>
<div class="flex flex-1 flex-wrap justify-end relative">
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click"
class="mt-[8px]">
<div class="px-[18px] py-[8px]">
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务
</p>
<div class="flex justify-end mt-[36px]">
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
</div>
</div>
<template #reference>
<el-button
class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent"
plain type="primary">如何获取授权码?</el-button>
</template>
</el-popover>
</div>
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
<el-card class="box-card !border-none" shadow="never">
<el-form-item prop="auth_code">
<el-input v-model.trim="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
</el-form-item>
</div>
</div>
<div class="mt-[20px]">
<el-form-item prop="auth_secret">
<el-input v-model.trim="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
</el-form-item>
</div>
<div class="flex flex-1 justify-between items-center p-[50px] bg-[var(--el-color-info-light-9)]">
<div class="flex flex-col">
<div class="flex flex-wrap items-center">
<p class="text-page-title mr-[20px]">授权信息</p>
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
</div>
<div class="mt-[46px] ml-[40px] flex flex-wrap">
<span class="text-[14px] mr-[84px]">授权域名<em class="ml-[12px] text-[12px]">{{ authinfo.site_address || '--' }}</em></span>
<span class="text-[14px] flex items-center">
<span>授权码</span>
<em class="ml-[12px] mr-[10px] text-[12px]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<View />
</el-icon>
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<Hide />
</el-icon>
</span>
</div>
</div>
<div class="flex flex-1 flex-wrap justify-end relative">
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click" class="mt-[8px]">
<div class="px-[18px] py-[8px]">
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务
</p>
<div class="flex justify-end mt-[36px]">
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
</div>
</div>
<template #reference>
<el-button
class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent"
plain type="primary">如何获取授权码?</el-button>
</template>
</el-popover>
</div>
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
<el-card class="box-card !border-none" shadow="never">
<el-form-item prop="auth_code">
<el-input v-model.trim="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
</el-form-item>
<div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
@click="save(formRef)">{{ t('confirm') }}</el-button>
</div>
<div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
</div>
</el-card>
</el-form>
</el-dialog>
</div>
</div>
</el-card>
<div class="mt-[20px]">
<el-form-item prop="auth_secret">
<el-input v-model.trim="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
</el-form-item>
</div>
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
<div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t('confirm') }}</el-button>
</div>
<div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
</div>
</el-card>
</el-form>
</el-dialog>
</div>
</div>
</el-card>
<el-card class="box-card !border-none " shadow="never" v-if="!loading">
<div class="text-page-title mb-[20px]">历史版本</div>
@ -99,7 +101,7 @@
<upgrade ref="upgradeRef" />
<cloud-build ref="cloudBuildRef" />
</div>
</div>
</template>
<script lang="ts" setup>
@ -141,9 +143,9 @@ const authCodeApproveFn = () => {
}
interface AuthInfo {
company_name: string,
site_address: string,
auth_code: string
company_name: string,
site_address: string,
auth_code: string
}
const authinfo = ref<AuthInfo>({
@ -154,19 +156,18 @@ const authinfo = ref<AuthInfo>({
const loading = ref(true)
const saveLoading = ref(false)
const checkAppMange = () => {
getAuthinfo()
.then((res) => {
loading.value = false
if (res.data.data && res.data.data.length != 0) {
authinfo.value = res.data.data
authCodeApproveDialog.value = false
}
})
.catch(() => {
loading.value = false
getAuthinfo().then((res) => {
loading.value = false
if (res.data.data && res.data.data.length != 0) {
authinfo.value = res.data.data
authCodeApproveDialog.value = false
})
}
}).catch(() => {
loading.value = false
authCodeApproveDialog.value = false
})
}
checkAppMange()
const formData = reactive<Record<string, string>>({
@ -247,41 +248,4 @@ const handleCloudBuild = () => {
}
</script>
<style lang="scss" scoped>
.app-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
}
.main {
background-color: var(--el-bg-color-overlay);
}
em {
font-style: normal
}
.timeline-log-wrap {
background: #F5F7F9;
}
html.dark {
.timeline-log-wrap {
background: var(--el-bg-color);
color: var(--el-text-color-regular);
}
}
</style>
<style>
.auth-code-dialog .el-overlay {
background-color: transparent;
}
.auth-code-dialog .el-dialog__header {
padding: 0;
}
.auth-code-dialog .el-dialog__body {
padding: 20px 30px;
}
</style>
<style lang="scss" scoped></style>

View File

@ -1,12 +1,15 @@
<template>
<div class="main-container w-full " v-loading="loading">
<!--应用管理-->
<div class="main-container" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">应用管理</span>
</div>
<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 class="relative bg-page cursor-pointer px-4 mr-4 mt-[20px] border-br-light border-[1px] hover:border-primary">
<div class="relative cursor-pointer mt-[20px] mr-4 px-4 border-br-light border-[1px] bg-[var(--el-color-info-light-9)] hover:border-primary">
<div @click="toLink(item.key)" class="flex py-5 items-center">
<div class="flex justify-center items-center">
<el-image class="w-[40px] h-[40px]" :src="img(item.icon)" fit="contain">
@ -24,7 +27,8 @@
</div>
</div>
</div>
<div class="empty flex items-center justify-center" v-if="!loading && !appList.length">
<div class="empty flex items-center justify-center" v-if="!loading && !appList.length">
<el-empty :description="t('emptyAppData')" />
</div>
</el-card>
@ -57,25 +61,12 @@ const toLink = (addon: string) => {
</script>
<style lang="scss" scoped>
.main-container,
.empty {
min-height: calc(100vh - 84px);
}
.app-text {
overflow: hidden;
/* 超出部分隐藏 */
white-space: nowrap;
/* 禁止文本换行 */
text-overflow: ellipsis;
/* 显示省略号 */
}
.app-item:hover .with-ite {
display: block;
}
.el-form-item {
margin-bottom: 0px !important;
}
.app-text {
overflow: hidden;
/* 超出部分隐藏 */
white-space: nowrap;
/* 禁止文本换行 */
text-overflow: ellipsis;
/* 显示省略号 */
}
</style>

View File

@ -1,814 +0,0 @@
<template>
<div class="app-store" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<div v-if="info[activeName] && !loading">
<div class="flex justify-between items-center h-[32px]">
<span class="text-[16px] text-[#222] font-600">{{ t('localAppText') }}</span>
<div class="w-[247px]">
<el-input :placeholder="t('search')" v-model.trim="searchName" @keyup.enter="query">
<template #suffix>
<el-icon class="el-input__icon cursor-pointer" size="14px" @click="query">
<search />
</el-icon>
</template>
</el-input>
</div>
</div>
<div class="flex mt-[16px]">
<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]"
@click="activeName = 'installed'">
{{ t('installLabel') }}
</div>
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'uninstalled' }"
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 = 'uninstalled'">
{{ t('uninstalledLabel') }}
</div>
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'all' }"
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 = 'all'">
{{ t('buyLabel') }}
</div>
</div>
<div class="mt-[32px]">
<el-table v-if="localList[activeName].length" :data="info[activeName]" size="large" class="pt-[5px]">
<el-table-column :label="t('appName')" align="left" width="320">
<template #default="{ row }">
<div class="flex items-center"
:class="{ 'cursor-pointer': row.type == 'app' && Object.keys(row.install_info).length }"
@click="itemPath(row)">
<el-image class="w-[54px] h-[54px]" :src="row.icon" fit="contain">
<template #error>
<img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt="">
</template>
</el-image>
<div 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] mt-[6px]">{{ row.version }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column align="left" min-width="120">
<template #header>
<div class="flex items-center">
<span class="text-[#222] font-500 text-[13px] mr-[5px]">{{ t('appIdentification') }}</span>
<el-tooltip class="box-item" effect="light" :content="t('tipText')" placement="bottom">
<el-icon class="cursor-pointer text-[16px] text-[#a9a9a9]">
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<template #default="{ row }">
<span class="text-[#222] font-500 text-[13px]">{{ row.key }}</span>
</template>
</el-table-column>
<el-table-column prop="" :label="t('introduction')" align="left" min-width="200">
<template #default="{ row }">
<span class="text-[#222] font-500 text-[13px] multi-hidden">{{ row.desc }}</span>
</template>
</el-table-column>
<el-table-column :label="t('type')" align="left" min-width="100">
<template #default="{ row }">
<span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon') }}</span>
</template>
</el-table-column>
<el-table-column prop="" :label="t('author')" align="left" min-width="100">
<template #default="{ row }">
<span class="text-[#222] font-500 text-[13px]">{{ row.author }}</span>
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" align="right" width="150">
<template #default="{ row }">
<el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{ 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-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>
</el-table-column>
</el-table>
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading && activeName == 'installed'">
<template #image>
<div class="w-[230px] mx-auto">
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
</div>
</template>
<template #description>
<p class="flex items-center">{{ t('installed-empty') }}</p>
</template>
</el-empty>
<el-empty class="mx-auto overview-empty" v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
<template #image>
<div class="w-[230px] mx-auto">
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
</div>
</template>
<template #description>
<p class="flex items-center">
<span>{{ t('descriptionLeft') }}</span>
<el-link type="primary" @click="goRouter" class="mx-[5px]">{{ t('link') }}</el-link>
<span>{{ t('descriptionRight') }}</span>
</p>
</template>
</el-empty>
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'" 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="flex flex-1 flex-wrap justify-center relative">
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" class="mt-[8px]">
<div class="px-[18px] py-[8px]">
<p class="leading-[32px] text-[14px]">
您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务</p>
<div class="flex justify-end mt-[36px]">
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
</div>
</div>
<template #reference>
<el-button
class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent"
plain type="primary">如何获取授权码?</el-button>
</template>
</el-popover>
</div>
</div>
</div>
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
<el-card class="box-card !border-none" shadow="never">
<el-form-item prop="auth_code">
<el-input v-model.trim="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
</el-form-item>
<div class="mt-[20px]">
<el-form-item prop="auth_secret">
<el-input v-model.trim="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
</el-form-item>
</div>
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
<div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t('confirm') }}</el-button>
</div>
<div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
</div>
</el-card>
</el-form>
</el-dialog>
<!-- 详情 -->
<el-dialog v-model="appStoreShowDialog" :title="t('plugDetail')" width="500px" :destroy-on-close="true">
<el-form :model="appStoreInfo" label-width="120px" ref="formRef" class="page-form">
<el-form-item :label="t('title')">
<div class="input-width"> {{ appStoreInfo.title }} </div>
</el-form-item>
<el-form-item :label="t('desc')">
<div class="input-width"> {{ appStoreInfo.desc }} </div>
</el-form-item>
<el-form-item :label="t('author')">
<div class="input-width"> {{ appStoreInfo.author }} </div>
</el-form-item>
<el-form-item :label="t('version')">
<div class="input-width"> {{ appStoreInfo.version }} </div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="appStoreShowDialog = false">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
<!-- 安装弹窗 -->
<el-dialog v-model="installShowDialog" :title="t('addonInstall')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false" :before-close="installShowDialogClose">
<el-steps :space="200" :active="installStep" finish-status="success" align-center>
<el-step :title="t('envCheck')" class="flex-1" />
<el-step :title="t('installProgress')" class="flex-1" />
<el-step :title="t('installComplete')" class="flex-1" />
</el-steps>
<div v-show="installStep == 1" v-loading="!installCheckResult.dir">
<el-scrollbar max-height="50vh">
<div class="min-h-[150px]">
<div class="bg-[#fff] my-3" v-if="installCheckResult.dir">
<p class="pt-[20px] pl-[20px] ">{{ t('dirPermission') }}</p>
<div class="px-[20px] pt-[10px] text-[14px]">
<el-row class="py-[10px] items table-head-bg pl-[15px] mb-[10px]">
<el-col :span="12">
<span>{{ t('path') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('demand') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('status') }}</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('readable') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_write" :key="index">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('write') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
</div>
</div>
</div>
</el-scrollbar>
<div class="flex justify-end">
<el-tooltip effect="dark" :content="t('installTips')" placement="top">
<el-button type="default" :disabled="!installCheckResult.is_pass || cloudInstalling"
:loading="localInstalling" @click="handleInstall">{{ t('localInstall') }}</el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="t('cloudInstallTips')" placement="top">
<el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling"
:loading="cloudInstalling" @click="handleCloudInstall">{{ t('cloudInstall') }}</el-button>
</el-tooltip>
</div>
</div>
<div v-show="installStep == 2" class="h-[50vh] mt-[20px]">
<terminal name="my-terminal" :context="currAddon" :init-log="null" :show-header="false" :show-log-time="true" />
</div>
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
<!-- 提示信息 -->
<div v-for="(item, index) in installAfterTips" class="mb-[10px]" :key="index">
<el-alert :title="item" type="error" :closable="false" />
</div>
</div>
</el-dialog>
<el-dialog v-model="uninstallShowDialog" :title="t('addonUninstall')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false">
<el-scrollbar max-height="50vh">
<div class="min-h-[150px]">
<div class="bg-[#fff] my-3" v-if="uninstallCheckResult.dir">
<p class="pt-[20px] pl-[20px] ">{{ t('dirPermission') }}</p>
<div class="px-[20px] pt-[10px] text-[14px]">
<el-row class="py-[10px] items table-head-bg pl-[15px] mb-[10px]">
<el-col :span="12">
<span>{{ t('path') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('demand') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('status') }}</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in uninstallCheckResult.dir.is_readable" :key="index">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('readable') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in uninstallCheckResult.dir.is_write" :key="index">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('write') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
</div>
</div>
</div>
</el-scrollbar>
</el-dialog>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, h } from 'vue'
import { t } from '@/lang'
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon'
import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
import { ElMessageBox, ElNotification, FormInstance, FormRules, NotificationHandle } from 'element-plus'
// import { img } from '@/utils/common'
import { Terminal, api as terminalApi } from 'vue-web-terminal'
import { findFirstValidRoute } from '@/router/routers'
import storage from '@/utils/storage'
import { useRouter } from 'vue-router'
import useUserStore from '@/stores/modules/user'
import { AnyObject } from '@/types/global'
const router = useRouter()
const activeName = ref('installed')
const loading = ref<Boolean>(true)
const downloading = ref('')
const installAfterTips = ref<string[]>([])
const userStore: any = useUserStore()
const downEvent = (param: Record<string, any>) => {
if (downloading.value) return
downloading.value = param.key
downloadVersion({ addon: param.key, version: param.version }).then(() => {
installAddonFn(param.key)
localListFn()
downloading.value = ''
}).catch(() => {
downloading.value = ''
})
}
const authCode = ref('')
getAuthinfo().then(res => {
if (res.data.data && res.data.data.auth_code) {
authCode.value = res.data.data.auth_code
}
}).catch(() => {
})
/**
* 本地下载的插件列表
*/
// input
const searchName = ref('')
//
const info:AnyObject = ref<{
installed: never[];
uninstalled: never[];
all: never[];
}>({
installed: [],
uninstalled: [],
all: []
})
const query = () => {
if (searchName.value == '' || searchName.value == null) {
info.value.installed = localList.value.installed
info.value.uninstalled = localList.value.uninstalled
info.value.all = localList.value.all
return false
}
info.value.installed = localList.value.installed.filter((el: any) => el.title.indexOf(searchName.value) != -1)
info.value.uninstalled = localList.value.uninstalled.filter((el: any) => el.title.indexOf(searchName.value) != -1)
info.value.all = localList.value.all.filter((el: any) => el.title.indexOf(searchName.value) != -1)
}
const localList:AnyObject = ref({
installed: [],
uninstalled: [],
all: [],
error: ''
})
const localListFn = () => {
loading.value = true
getAddonLocal({}).then(res => {
const data:any = res.data.list
localList.value.error = res.data.error
localList.value.installed = []
localList.value.uninstalled = []
localList.value.all = []
for (const i in data) {
if (data[i].is_local == false) localList.value.all.push(data[i])
if (data[i].install_info && Object.keys(data[i].install_info)?.length) {
localList.value.installed.push(data[i])
} else {
if (data[i].is_download == true) localList.value.uninstalled.push(data[i])
}
}
query()
userStore.routers.forEach((item:AnyObject, index:number) => {
if (item.children && item.children.length) {
item.name = findFirstValidRoute(item.children)
appLink.value[item.meta.app] = findFirstValidRoute(item.children)
} else {
appLink.value[item.meta.app] = item.name
}
})
loading.value = false
}).catch(() => {
loading.value = false
})
}
localListFn()
//
const appLink: any = ref({})
const itemPath = (data: any) => {
if (data.type == 'app' && Object.keys(data.install_info).length) {
storage.set({ key: 'menuAppStorage', data: data.key })
storage.set({ key: 'plugMenuTypeStorage', data: '' })
const appMenuList = userStore.appMenuList
appMenuList.push(data.key)
userStore.setAppMenuList(appMenuList)
const name: any = appLink.value[data.key]
router.push({ name })
}
}
const currAddon = ref('')
//
const installShowDialog = ref(false)
//
const installStep = ref(1)
//
const installCheckResult = ref<AnyObject>({})
/**
* 安装
* @param key
*/
const installAddonFn = (key: string) => {
currAddon.value = key
preInstallCheck(key).then(res => {
installStep.value = 1
installShowDialog.value = true
installAfterTips.value = []
installCheckResult.value = res.data
userStore.clearRouters()
}).catch(() => { })
}
/**
* 获取正在进行的安装任务
*/
let notificationEl: NotificationHandle | null | any = null
const getInstallTask = (first: boolean = true) => {
getAddonInstalltask().then(res => {
if (res.data) {
if (first) {
installLog = []
currAddon.value = res.data.addon
if (!installShowDialog.value) {
notificationEl = ElNotification.success({
title: t('warning'),
dangerouslyUseHTMLString: true,
message: h('div', {}, [
t('installingTips'),
h('span', { class: 'text-primary cursor-pointer', onClick: checkInstallTask }, [t('installPercent')])
]),
duration: 0,
showClose: false
})
}
}
if (res.data.error) {
return
}
if (res.data.mode == 'cloud') {
getCloudInstallLog()
}
setTimeout(() => {
getInstallTask(false)
}, 2000)
} else {
if (!first) {
installStep.value = 3
localListFn()
userStore.clearRouters()
notificationEl.close()
}
}
})
}
getInstallTask()
const checkInstallTask = () => {
installShowDialog.value = true
installStep.value = 2
}
const localInstalling = ref(false)
/**
* 安装插件
*/
const handleInstall = () => {
if (!installCheckResult.value.is_pass || localInstalling.value) return
localInstalling.value = true
installAddon({ addon: currAddon.value }).then(res => {
installStep.value = 3
localListFn()
userStore.getAppList()
localInstalling.value = false
if (res.data.length) installAfterTips.value = res.data
}).catch((res) => {
localInstalling.value = false
})
}
const cloudInstalling = ref(false)
/**
* 云安装插件
*/
const handleCloudInstall = () => {
if (!authCode.value) {
authElMessageBox()
return
}
if (!installCheckResult.value.is_pass || cloudInstalling.value) return
cloudInstalling.value = true
cloudInstallAddon({ addon: currAddon.value }).then(res => {
installStep.value = 2
terminalApi.execute('my-terminal', 'clear')
terminalApi.pushMessage('my-terminal', { content: '开始安装插件', class: 'info' })
getInstallTask()
cloudInstalling.value = false
}).catch((res) => {
cloudInstalling.value = false
})
}
const authElMessageBox = () => {
ElMessageBox.confirm(
t('authTips'),
t('warning'),
{
distinguishCancelAndClose: true,
confirmButtonText: t('toBind'),
cancelButtonText: t('toNiucloud')
}
).then(() => {
router.push({ path: '/app/authorize' })
}).catch((action: string) => {
if (action === 'cancel') {
window.open('https://www.niucloud.com/app')
}
})
}
let installLog: string[] = []
const getCloudInstallLog = () => {
getAddonCloudInstallLog(currAddon.value)
.then(res => {
const data = res.data.data ?? []
if (data[0] && data[0].length && installShowDialog.value == true) {
data[0].forEach((item: { action: string; code: number; msg: any }) => {
if (!installLog.includes(item.action)) {
terminalApi.pushMessage('my-terminal', { content: `正在执行:${item.action}` })
installLog.push(item.action)
if (item.code == 0) {
terminalApi.pushMessage('my-terminal', { content: item.msg, class: 'error' })
}
}
})
}
})
.catch(() => {
notificationEl?.close()
})
}
watch(currAddon, (nval) => {
installCheckResult.value = {}
})
//
const uninstallShowDialog = ref(false)
//
const uninstallCheckResult = ref<AnyObject>({})
/**
* 卸载
* @param key
*/
const uninstallAddonFn = (key: string) => {
preUninstallCheck(key).then(({ data }) => {
if (data.is_pass) {
uninstallAddon({ addon: key }).then(res => {
localListFn()
userStore.clearRouters()
loading.value = false
}).catch(() => {
loading.value = false
})
} else {
uninstallCheckResult.value = data
uninstallShowDialog.value = true
}
})
}
const market = () => {
window.open('https://www.niucloud.com/app')
}
/**
* 安装弹窗关闭提示
* @param done
*/
const installShowDialogClose = (done: () => {}) => {
if (installStep.value == 2) {
ElMessageBox.confirm(
t('installShowDialogCloseTips'),
t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
cancelInstall(currAddon.value)
done()
}).catch(() => { })
} else done()
}
//
const appStoreShowDialog = ref(false)
const appStoreInfo = ref<AnyObject>({})
const getAddonDetialFn = (data: AnyObject) => {
appStoreShowDialog.value = true
appStoreInfo.value = data
}
//
const authCodeApproveDialog = ref(false)
const authinfo = ref('')
const getAuthCodeDialog: Record<string, any> | null = ref(null)
const saveLoading = ref(false)
const checkAppMange = () => {
getAuthinfo()
.then((res) => {
if (res.data.data && res.data.data.length != 0) {
authinfo.value = res.data.data
}
})
.catch(() => {
authCodeApproveDialog.value = false
})
}
checkAppMange()
const authCodeApproveFn = () => {
authCodeApproveDialog.value = true
}
const formData = reactive<Record<string, string>>({
auth_code: '',
auth_secret: ''
})
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
auth_code: [
{ required: true, message: t('authCodePlaceholder'), trigger: 'blur' }
],
auth_secret: [
{ required: true, message: t('authSecretPlaceholder'), trigger: 'blur' }
]
})
const save = async (formEl: FormInstance | undefined) => {
if (saveLoading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
saveLoading.value = true
setAuthinfo(formData)
.then(() => {
saveLoading.value = false
setTimeout(() => {
location.reload()
}, 1000)
})
.catch(() => {
saveLoading.value = false
})
}
})
}
const goRouter = () => {
window.open('https://www.niucloud.com/app')
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.demo-tabs>.el-tabs__content {
padding: 32px;
color: #6b778c;
font-size: 32px;
font-weight: 600;
}
.plug-item {
.plug-item-operate {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
font-size: var(--el-font-size-extra-small);
}
}
:deep(.t-container) {
box-shadow: none !important;
.t-window {
padding: 10px 20px !important;
}
}
.switch-btn.active {
border-color: var(--el-color-primary);
color: #fff;
background-color: var(--el-color-primary);
}
.plug-large {
.plug-item-operate {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
font-size: var(--el-font-size-extra-small);
}
}
.app-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
}
// --
.table-head-bg {
background: #f5f7f9;
}
html.dark .table-head-bg {
background: #141414;
}
.el-alert .el-alert__title {
font-size: 16px;
line-height: 18px;
}
.app-store {
height: calc(100vh - 120px);
box-sizing: border-box;
}
</style>

View File

@ -1,7 +1,6 @@
<template>
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
<el-form :model="formData" label-width="90px" class="page-form" ref="formRef" :rules="formRules"
v-loading="loading">
<el-form :model="formData" label-width="90px" class="page-form" ref="formRef" :rules="formRules" v-loading="loading">
<el-form-item :label="t('menuName')" prop="menu_name">
<el-input v-model="formData.menu_name" :placeholder="t('menuNamePlaceholder')" class="input-width" />
</el-form-item>

View File

@ -64,8 +64,8 @@
import { ref, reactive, computed, toRaw } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { getUserInfo, getAllUserList } from '@/app/api/user'
import { addUser, editUser } from '@/app/api/site'
import { getAllUserList } from '@/app/api/user'
import { getUserInfo, addUser, editUser } from '@/app/api/site'
import { allRole } from '@/app/api/sys'
import { img, deepClone } from '@/utils/common'
import { AnyObject } from '@/types/global'

View File

@ -23,7 +23,6 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { t } from '@/lang'
// import type { FormInstance } from 'element-plus'
import { getLogInfo } from '@/app/api/site'
const showDialog = ref(false)

View File

@ -1,10 +1,13 @@
<template>
<!--操作日志-->
<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>
<span class="text-page-title">{{ pageName }}</span>
</div>
<div class="flex justify-between items-center mt-[16px]">
<div class="flex justify-between items-center mt-[20px]">
<el-form :inline="true" :model="sysUserLogTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('ip')" prop="ip">
<el-input v-model="sysUserLogTableData.searchParam.ip" :placeholder="t('ipPlaceholder')" />
@ -43,11 +46,12 @@
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="sysUserLogTableData.page" v-model:page-size="sysUserLogTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="sysUserLogTableData.total" @size-change="loadSysUserLogList()" @current-change="loadSysUserLogList" />
</div>
<user-log-detail ref="userLogDetailDialog" @complete="loadSysUserLogList()" />
</div>
</el-card>

View File

@ -1,7 +1,9 @@
<template>
<!--平台菜单-->
<div class="main-container">
<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">
<span class="text-page-title">{{ pageName }}</span>
<div class="flex items-center">
<el-button type="primary" class="w-[100px]" @click="addEvent">
@ -11,13 +13,13 @@
{{ t('initializeMenu') }}
</el-button>
</div>
</div>
<el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading">
<el-table class="mt-[20px]" :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading">
<template #empty>
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')" min-width="150" />
<el-table-column :label="t('icon')" width="100" align="center">
<template #default="{ row }">

View File

@ -1,10 +1,13 @@
<template>
<!--角色管理-->
<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>
<span class="text-page-title">{{ pageName }}</span>
</div>
<div class="flex justify-between items-center mt-[16px]">
<div class="flex justify-between items-center mt-[20px]">
<el-form :inline="true" :model="roleTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('roleName')" prop="search">
<el-input v-model="roleTableData.searchParam.search" class="w-[240px]" :placeholder="t('roleNamePlaceholder')" />

View File

@ -1,8 +1,11 @@
<template>
<!--站点菜单-->
<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 class="flex items-center">
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addMenu') }}

View File

@ -1,10 +1,13 @@
<template>
<!--管理员-->
<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>
<span class="text-page-title">{{ pageName }}</span>
</div>
<div class="flex justify-between items-center mt-[16px]">
<div class="flex justify-between items-center mt-[20px]">
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('accountNumber')" prop="seach">
<el-input v-model="userTableData.searchParam.seach" class="input-width" :placeholder="t('accountNumberPlaceholder')" />
@ -16,11 +19,13 @@
</el-form>
<el-button type="primary" class="w-[100px] self-start" @click="addEvent">{{ t('addUser') }}</el-button>
</div>
<div>
<el-table :data="userTableData.data" size="large" v-loading="userTableData.loading">
<template #empty>
<span>{{ !userTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column :label="t('headImg')" width="100" align="left">
<template #default="{ row }">
<div class="w-[35px] h-[35px] flex items-center justify-center">
@ -30,7 +35,11 @@
</template>
</el-table-column>
<el-table-column prop="username" :label="t('accountNumber')" min-width="120" show-overflow-tooltip />
<el-table-column prop="real_name" :label="t('userRealName')" min-width="120" show-overflow-tooltip />
<el-table-column prop="real_name" :label="t('userRealName')" min-width="120" show-overflow-tooltip>
<template #default="{ row }">
<span>{{ row.real_name ? row.real_name :'--' }}</span>
</template>
</el-table-column>
<el-table-column :label="t('userRoleName')" min-width="120" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.is_admin">{{ t('administrator') }}</span>
@ -82,8 +91,7 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { lockUser, unlockUser } from '@/app/api/site'
import { getUserList } from '@/app/api/user'
import { getUserList, lockUser, unlockUser } from '@/app/api/site'
import EditUser from '@/app/views/auth/components/edit-user.vue'
import { img } from '@/utils/common'
import { ElMessageBox } from 'element-plus'

View File

@ -1,232 +1,106 @@
<template>
<!-- <div class="w-full p-5 ">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[16px]">{{ t('aliappAccessFlow') }}</span>
</div>
<div>
<ul class="progress-wrap flex items-center text-center min-h-[120px]">
<li class="progress-point ">
<div
class="progress-point-pic list-none inline-block w-[30px] h-[30px] leading-[30px] text-center mt-[10px] mb-[20px]">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/register.png" alt="">
</div>
<p class="text-[14px] text-[14px]">{{ t('aliappAttestation') }}</p>
<el-button link type="primary" @click="linkEvent('https://open.alipay.com/develop/manage')">{{ t('aliappAttest')
}}</el-button>
</li>
<!--支付宝小程序-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<li class="progress-point-arrow list-none">
<img src="@/app/assets/images/arrow.png" alt="">
</li>
<li class="progress-point">
<div
class="progress-point-pic list-none inline-block w-[30px] h-[30px] leading-[30px] text-center mt-[10px] mb-[20px]">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/config_info.png" alt="">
</div>
<p class="text-[14px]">{{ t('aliappwebsite') }}</p>
<el-button link type="primary" @click="router.push('/channel/aliapp/config')">{{ t('aliappSet')
}}</el-button>
</li>
<li class="progress-point-arrow list-none">
<img src="@/app/assets/images/arrow.png" alt="">
</li>
<li class="progress-point ">
<div
class="progress-point-pic list-none inline-block w-[30px] h-[30px] leading-[30px] text-center mt-[10px] mb-[20px]">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/complete.png" alt="">
</div>
<p class="text-[14px]">{{ t('aliappEmplace') }}</p>
<el-button link type="primary" @click="linkEvent('https://open.alipay.com/develop/manage')">{{ t('emplace')
}}</el-button>
</li>
<li class="progress-point-arrow list-none">
<img src="@/app/assets/images/arrow.png" alt="">
</li>
<li class="progress-point ">
<div
class="progress-point-pic list-none inline-block w-[30px] h-[30px] leading-[30px] text-center mt-[10px] mb-[20px]">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/public_number.png" alt="">
</div>
<p class="text-[14px]">{{ t('uploadVersion') }}</p>
<el-button link type="primary" @click="router.push('/channel/aliapp/course')">{{
t('releaseCourse') }}</el-button>
</li>
<li class="progress-point-arrow list-none">
<img src="@/app/assets/images/arrow.png" alt="">
</li>
<li class="progress-point ">
<div
class="progress-point-pic list-none inline-block w-[30px] h-[30px] leading-[30px] text-center mt-[10px] mb-[20px]">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/complete.png" alt="">
</div>
<p class="text-[14px]">{{ t('completeAccess') }}</p>
<el-button link type="primary"></el-button>
</li>
</ul>
</div>
<div class="flex justify-between items-center mt-[40px]">
<span class="text-[16px]">{{ t('aliappInlet') }}</span>
</div>
<div class="flex flex-wrap p-5">
<div class="w-[280px] h-[70px] flex bg-[#f7f8fa] items-center my-[20px] mr-[20px] cursor-pointer" @click="router.push('/channel/aliapp/config')">
<img class="w-[40px] h-[40px] mr-[10px] ml-[20px]" src="@/app/assets/images/wechat_icon.png" alt="">
<div class="flex flex-col h-[40px] justify-around">
<p class="text-[#666] text-[14px]">{{ t('aliappSet') }}</p>
<p class="text-[#999] text-[12px]">{{ t('aliappSet') }}</p>
</div>
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
</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('weappAccessFlow')" name="/channel/aliapp" />
<!-- <el-tab-pane :label="t('subscribeMessage')" name="/channel/aliapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/aliapp/code" /> -->
</el-tabs>
<div class="p-[20px]">
<p class="text-[16px] mb-[20px]">{{ t("weappInlet") }}</p>
<el-row>
<el-col :span="20">
<el-steps direction="vertical">
<el-step>
<template #icon v-if="active > 1">
<el-icon size="25px" class="text-color">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 1">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">1</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("weappAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("weappAttest") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://open.alipay.com/develop/manage')">{{ t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 2">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 2">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">2</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("weappSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("emplace") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/aliapp/config')">{{ t("weappSettingBtn") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 3">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 3">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">3</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("uploadVersion") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<!-- <el-button type="primary" plain @click="router.push('/channel/aliapp/code')">{{
t("weappRelease") }}</el-button> -->
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 4">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 4">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">4</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("completeAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<!-- <div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain>{{
t("wechatAccessBtn") }}</el-button>
</div> -->
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class=" text-[14px] text-[#303133] font-[700]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/aliapp" />
</el-tabs>
<div class="p-[20px]">
<h3 class="panel-title !text-sm">{{ t("weappInlet") }}</h3>
<el-row>
<el-col :span="20">
<el-steps :active="4" direction="vertical">
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("weappAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("weappAttest") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://open.alipay.com/develop/manage')">{{ t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("weappSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("emplace") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/aliapp/config')">{{ t("weappSettingBtn") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("uploadVersion") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]"></div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("completeAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class=" text-[12px]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { getAliappConfig } from '@/app/api/aliapp'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/aliapp')
const active = ref(2)
const qrCode = ref<string>('')
@ -242,57 +116,4 @@ const handleClick = (val: any) => {
}
</script>
<style lang="scss" scoped>
.progress-point {
flex-grow: 1;
list-style: none;
}
.border-color {
border-color: var(--el-color-primary);
}
.bg-color {
background-color: var(--el-color-primary);
}
.text-color {
color: var(--el-color-primary);
}
.bg-color1 {
background-color: var(--el-color-info-light-8);
}
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}
:deep(.el-step.is-vertical .el-step__icon.is-icon) {
padding: 8px 0;
height: 40px;
background-color: #fff;
}
:deep(.el-step__title) {
height: 40px;
line-height: 40px !important;
}
</style>
<style lang="scss" scoped></style>

View File

@ -1,14 +1,12 @@
<template>
<!--支付宝配置-->
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/aliapp' })">
<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" class="page-form" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('aliappSet') }}</h3>
@ -20,10 +18,9 @@
<upload-image v-model="formData.qrcode" />
<div class="form-tip">{{ t('aliappQrcodeTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('aliappDevelopInfo') }}</h3>
<el-form-item :label="t('aliappOriginal')">
@ -60,7 +57,7 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
<el-form-item label="AESKey">
@ -68,10 +65,8 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<div class="flex">
<h3 class="panel-title !text-sm">{{ t('functionSetting') }}</h3>
</div>
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('functionSetting') }}</h3>
<el-form-item :label="t('serveWhiteList')">
<el-input :model-value="formData.request_url" class="input-width" :readonly="true">
@ -80,7 +75,6 @@
</template>
</el-input>
</el-form-item>
</el-card>
</el-form>
@ -98,6 +92,7 @@ import { t } from '@/lang'
import { setAliappConfig, getAliappConfig, getAliappStatic } from '@/app/api/aliapp'
import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()

View File

@ -1,104 +1,100 @@
<template>
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/aliapp' })">
<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-card class="box-card !border-none" shadow="never">
<div class="mt-[20px]">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsOne1') }}--<el-button link type="primary" @click="linkEvent">{{ t('alipayCourseTipsOne2') }}</el-button>, {{ t('alipayCourseTipsOne3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay1.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay2.png" />
</div>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay3.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsTwo2') }}</p>
<div class="w-[100%] mt-[10px] flex flex-wrap">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4.png" />
</div>
<div>
<el-row :gutter="20">
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_1.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_2.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_3.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_4.jpg" />
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<!-- <span class="text-primary">{{ t('alipayCourseTipsThree2') }}</span> -->
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsThree1') }}
</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay5.png" />
</div>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay6.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsThree2') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay7.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsThree3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay8.png" />
</div>
</div>
</div>
</div>
</el-card>
</div>
<!--配置教程-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsOne1') }}--<el-button link type="primary" @click="linkEvent">{{ t('alipayCourseTipsOne2') }}</el-button>, {{ t('alipayCourseTipsOne3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay1.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay2.png" />
</div>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay3.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsTwo2') }}</p>
<div class="w-[100%] mt-[10px] flex flex-wrap">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4.png" />
</div>
<div>
<el-row :gutter="20">
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_1.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_2.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_3.jpg" />
</div>
</el-col>
<el-col :span="6">
<div class="w-[100%]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay4_4.jpg" />
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<!-- <span class="text-primary">{{ t('alipayCourseTipsThree2') }}</span> -->
<p class="flex items-center text-[14px]">{{ t('alipayCourseTipsThree1') }}
</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay5.png" />
</div>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay6.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsThree2') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay7.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('alipayCourseTipsThree3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/alipay8.png" />
</div>
</div>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getWechatConfig } from '@/app/api/wechat'
// import { img } from '@/utils/common'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()

View File

@ -1,10 +1,13 @@
<template>
<div class="main-container bg-[#fff] rounded-[4px]">
<div class="flex ml-[18px] justify-between items-center pt-[20px]">
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<!--H5端-->
<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 class="page-form mt-[20px]" :model="formData" label-width="150px" ref="formRef">
<el-form-item :label="t('isOpen')">
<el-switch v-model="formData.is_open"/>
</el-form-item>
@ -16,9 +19,8 @@
</el-input>
<span class="ml-2 cursor-pointer visit-btn" @click="visitFn">{{t('clickVisit')}}</span>
</el-form-item>
</el-card>
</el-form>
</el-form>
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
@ -116,7 +118,7 @@ const save = async (formEl: FormInstance | undefined) => {
</script>
<style lang="scss" scoped>
.visit-btn{
color:var(--el-color-primary);
}
.visit-btn{
color:var(--el-color-primary);
}
</style>

View File

@ -1,13 +1,16 @@
<template>
<div class="main-container bg-[#fff] rounded-[4px]" v-loading="loading">
<div class="flex pl-[18px] justify-between items-center pt-[20px]">
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form">
<el-card class="box-card !border-none" shadow="never">
<!-- <el-form-item :label="t('preview')" prop="weapp_name">-->
<!-- <img class="w-[500px]" src="@/app/assets/images/channel/preview.png" alt="">-->
<!-- </el-form-item>-->
<!--PC端-->
<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 class="page-form mt-[20px]" :model="formData" label-width="150px" ref="formRef">
<!-- <el-form-item :label="t('preview')" prop="weapp_name">
<img class="w-[500px]" src="@/app/assets/images/channel/preview.png" alt="">
</el-form-item> -->
<el-form-item :label="t('isOpen')">
<el-switch v-model="formData.is_open"/>
@ -19,11 +22,10 @@
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
</template>
</el-input>
<span class="ml-2 cursor-pointer visit-btn" @click="visitFn">{{t('clickVisit')}}</span>
<span class="ml-2 cursor-pointer visit-btn">{{t('clickVisit')}}</span>
</el-form-item>
</el-card>
</el-form>
</el-form>
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
@ -121,7 +123,7 @@ const save = async (formEl: FormInstance | undefined) => {
</script>
<style lang="scss" scoped>
.visit-btn{
color:var(--el-color-primary);
}
.visit-btn {
color: var(--el-color-primary);
}
</style>

View File

@ -1,225 +1,164 @@
<template>
<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('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<div class="p-[20px]">
<p class="text-[16px] mb-[20px]">{{ t("weappInlet") }}</p>
<el-row>
<el-col :span="20">
<el-steps direction="vertical">
<el-step>
<template #icon v-if="active > 1">
<el-icon size="25px" class="text-color">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 1">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">1</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("weappAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("weappAttest") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://mp.weixin.qq.com/')">{{ t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 2">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 2">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">2</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("weappSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("emplace") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/weapp/config')">{{ t("weappSettingBtn") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 3">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 3">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">3</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("uploadVersion") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/weapp/code')">{{ t("weappRelease") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 4">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 4">
<div 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>
</template>
<template #icon v-else>
<div class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">4</div>
</template>
<template #title>
<p class="text-[14px] text-[#303133] font-[700]">
{{ t("completeAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<!-- <el-button type="primary" plain>{{
t("wechatAccessBtn") }}</el-button> -->
</div>
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class=" text-[14px] text-[#303133] font-[700]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
<!--微信小程序-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="mt-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<div class="p-[20px]">
<h3 class="panel-title !text-sm">{{ t("weappInlet") }}</h3>
<el-row>
<el-col :span="20">
<el-steps class="!mt-[10px]" :active="4" direction="vertical">
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("weappAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("weappAttest") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://mp.weixin.qq.com/')">{{ t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("weappSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("emplace") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<template v-if="oplatformConfig.app_id && oplatformConfig.app_secret">
<el-button type="primary" @click="router.push('/channel/weapp/config')">{{ weappConfig.app_id ? t("seeConfig") : t("weappSettingBtn") }}</el-button>
<el-button type="primary" plain @click="authBindWeapp">{{ weappConfig.is_authorization ? t("refreshAuth") : t("authWeapp") }}</el-button>
</template>
<template v-else>
<el-button type="primary" @click="router.push('/channel/weapp/config')">{{ t("weappSettingBtn") }}</el-button>
<el-button type="primary" plain @click="router.push('/channel/weapp/course')">配置教程</el-button>
</template>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("uploadVersion") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/weapp/code')">{{ t("weappRelease") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("completeAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("releaseCourse") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]"></div>
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class=" text-[12px]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { onMounted, onUnmounted, ref } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { getWeappConfig } from '@/app/api/weapp'
import { getAuthorizationUrl } from '@/app/api/wxoplatform'
import { getWxoplatform } from '@/app/api/sys'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/weapp')
const active = ref(2)
const qrCode = ref('')
const weappConfig = ref({})
const oplatformConfig = ref({})
const onShowGetWeappConfig = async () => {
await getWeappConfig().then(({ data }) => {
weappConfig.value = data
qrCode.value = data.qr_code
})
}
onMounted(async () => {
const res = await getWeappConfig()
qrCode.value = res.data.qr_code
onShowGetWeappConfig()
await getWxoplatform().then(({ data }) => {
oplatformConfig.value = data
})
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
onShowGetWeappConfig()
}
})
})
onUnmounted(() => {
document.removeEventListener('visibilitychange', () => {
})
})
const linkEvent = (url: string) => {
window.open(url, '_blank')
}
const handleClick = (val: any) => {
router.push({ path: activeName.value })
}
const authBindWeapp = () => {
getAuthorizationUrl().then(({ data }) => {
window.open(data)
})
}
</script>
<style lang="scss" scoped>
.progress-point {
flex-grow: 1;
list-style: none;
}
.border-color {
border-color: var(--el-color-primary);
}
.bg-color {
background-color: var(--el-color-primary);
}
.text-color {
color: var(--el-color-primary);
}
.bg-color1 {
background-color: var(--el-color-info-light-8);
}
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__active-bar {
display: none;
}
.el-tabs__item.is-active {
border-bottom: 2px solid var(--el-color-primary);
}
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}
:deep(.el-step.is-vertical .el-step__icon.is-icon) {
padding: 8px 0;
height: 40px;
background-color: #fff;
}
:deep(.el-step__title) {
height: 40px;
line-height: 40px !important;
}</style>
<style lang="scss" scoped></style>

View File

@ -1,24 +1,29 @@
<template>
<div class="main-container min-h-[300px] p-5 bg-[#fff] rounded-[4px]">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<el-card class="box-card !border-none" shadow="never" v-loading="loading">
<div class="mt-[50px]">
<el-button type="primary" @click="insert" :loading="uploading" :disabled="weappTableData.loading">{{ t('cloudRelease') }}</el-button>
<el-button @click="localInsert" :disabled="weappTableData.loading">{{ t('localRelease') }}</el-button>
<!--小程序发布-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<div class="mt-[20px]" v-if="!weappConfig.is_authorization">
<el-button type="primary" @click="insert" :loading="uploading" :disabled="loading">{{ t('cloudRelease') }}</el-button>
<el-button @click="localInsert" :disabled="loading">{{ t('localRelease') }}</el-button>
</div>
<el-table class="mt-[15px]" :data="weappTableData.data" v-loading="weappTableData.loading" size="default">
<template #empty>
<span>{{ t('emptyData') }}</span>
</template>
<el-table-column prop="version" :label="t('code')" align="left" />
<!-- <el-table-column prop="desc" :label="t('content')" align="left" /> -->
<el-table-column prop="status_name" :label="t('status')" align="left">
<template #default="{ row }">
<div>{{ row.status_name }}</div>
@ -27,27 +32,30 @@
<el-table-column prop="create_time" :label="t('createTime')" align="center" />
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="120">
<template #default="{ row, $index }">
<template v-if="previewContent && $index == 0 && row.status == 1 && weappTableData.page == 1">
<template v-if="previewContent && $index == 0 && (row.status == 1 || row.status == 2) && weappTableData.page == 1">
<el-tooltip :content="previewContent" raw-content effect="light">
<el-button type="primary" link>{{ t('preview') }}</el-button>
</el-tooltip>
</template>
<el-button type="primary" link v-if="row.status == -1" @click="handleFailReason(row)">
<el-button type="primary" link v-if="row.status == -1 || row.status == -2" @click="handleFailReason(row)">
{{ t('failReason') }}</el-button>
<el-button type="primary" link v-if="row.status == -2" @click="againUpload(row)" :loading="uploading">
{{ t('againUpload') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="weappTableData.page" v-model:page-size="weappTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="weappTableData.total"
@size-change="getWeappVersionListFn" @current-change="getWeappVersionListFn" />
@size-change="getWeappVersionListFn()" @current-change="getWeappVersionListFn" />
</div>
</el-card>
<el-dialog v-model="dialogVisible" :title="t('codeDownTwoDesc')" width="30%" :before-close="handleClose">
<el-form ref="ruleFormRef" :model="form" label-width="120px">
<el-form-item prop="code" :label="t('code')">
<el-input v-model="form.code" :placeholder="t('codePlaceholder')"
onkeyup="this.value = this.value.replace(/[^\d\.]/g,'');" />
<el-input v-model="form.code" :placeholder="t('codePlaceholder')" onkeyup="this.value = this.value.replace(/[^\d\.]/g,'');" />
</el-form-item>
<el-form-item prop="path" :label="t('path')">
<upload-file v-model="form.path" :api="'weapp/upload'" :accept="'.zip'" />
@ -65,11 +73,13 @@
</span>
</template>
</el-dialog>
<el-dialog v-model="failReasonDialogVisible" :title="t('failReason')" width="60%">
<el-scrollbar class="h-[60vh] w-full whitespace-pre p-[20px]">
{{ failReason }}
</el-scrollbar>
</el-dialog>
<el-dialog v-model="uploadSuccessShowDialog" :title="t('warning')" width="500px" draggable>
<span v-html="t('uploadSuccessTips')"></span>
<template #footer>
@ -92,6 +102,7 @@ import { getAppType } from '@/utils/common'
import { ElMessageBox } from 'element-plus'
import { AnyObject } from '@/types/global'
import Storage from '@/utils/storage'
import {siteWeappCommit} from "@/app/api/wxoplatform";
const route = useRoute()
const router = useRouter()
@ -132,10 +143,12 @@ getAuthinfo().then(res => {
const weappConfig = ref<{
app_id:string,
app_secret:string
app_secret:string,
is_authorization: number
}>({
app_id: '',
app_secret: ''
app_secret: '',
is_authorization: 0
})
getWeappConfig().then(res => {
weappConfig.value = res.data
@ -207,11 +220,9 @@ const localInsert = () => {
const previewContent = ref('')
const getWeappPreviewImage = () => {
if (!authCode.value) return
getWeappPreview()
.then(res => {
if (res.data) previewContent.value = `<img src="${res.data}" class="w-[150px]">`
})
.catch()
getWeappPreview().then(res => {
if (res.data) previewContent.value = `<img src="${ res.data }" class="w-[150px]">`
}).catch()
}
const getWeappUploadLogFn = (key: string) => {
@ -283,43 +294,19 @@ const knownToKnow = () => {
Storage.set({ key: 'weappUploadTipsLock', data: true })
uploadSuccessShowDialog.value = false
}
const againUpload = () => {
if (uploading.value) return
uploading.value = true
siteWeappCommit().then(() => {
getWeappVersionListFn()
getWeappPreviewImage()
uploading.value = false
}).catch(() => {
uploading.value = false
})
}
</script>
<style lang="scss" scoped>
.el-collapse {
border: 0px !important
}
.el-collapse-item .el-collapse-item__wrap {
border: 0px !important
}
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__active-bar {
display: none;
}
.el-tabs__item.is-active {
border-bottom: 2px solid var(--el-color-primary);
}
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}
</style>
<style lang="scss" scoped></style>

View File

@ -1,48 +1,44 @@
<template>
<!--小程序配置-->
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/weapp' })">
<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="170px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="170px" ref="formRef" :rules="formRules" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('weappInfo') }}</h3>
<el-form-item :label="t('weappName')" prop="weapp_name">
<el-input v-model.trim="formData.weapp_name" :placeholder="t('weappNamePlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.weapp_name" :placeholder="t('weappNamePlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
</el-form-item>
<el-form-item :label="t('weappOriginal')" prop="weapp_original">
<el-input v-model.trim="formData.weapp_original" :placeholder="t('weappOriginalPlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.weapp_original" :placeholder="t('weappOriginalPlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
</el-form-item>
<el-form-item :label="t('weappQrcode')" prop="qr_code">
<upload-image v-model="formData.qr_code" />
<div class="form-tip">{{ t('weappQrcodeTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('weappDevelopInfo') }}</h3>
<el-form-item :label="t('weappAppid')" prop="app_id">
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
<div class="form-tip">{{ t('weappAppidTips') }}</div>
</el-form-item>
<el-form-item :label="t('weappAppsecret')" prop="app_secret">
<el-form-item :label="t('weappAppsecret')" prop="app_secret" v-if="!formData.is_authorization">
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
<div class="form-tip">{{ t('weappAppsecretTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never" v-if="!formData.is_authorization">
<h3 class="panel-title !text-sm">{{ t('weappUpload') }}</h3>
<el-form-item :label="t('uploadKey')" prop="upload_private_key">
@ -54,7 +50,7 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
<el-form-item label="URL">
@ -71,8 +67,7 @@
</el-form-item>
<el-form-item label="EncodingAESKey" prop="encoding_aes_key">
<el-input v-model.trim="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')"
class="input-width" maxlength="43" show-word-limit clearable />
<el-input v-model.trim="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')" class="input-width" maxlength="43" show-word-limit clearable />
<div class="form-tip">{{ t('encodingAESKeyTips') }}</div>
</el-form-item>
@ -88,7 +83,7 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<div class="flex">
<h3 class="panel-title !text-sm">{{ t('functionSetting') }}</h3>
</div>
@ -121,7 +116,6 @@
</template>
</el-input>
</el-form-item>
</el-card>
</el-form>
@ -134,11 +128,12 @@
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { reactive, ref, watch, computed } from 'vue'
import { t } from '@/lang'
import { getWeappConfig, setWeappConfig } from '@/app/api/weapp'
import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
@ -147,7 +142,7 @@ const pageName = route.meta.title
const loading = ref(true)
const formData = reactive<Record<string, string>>({
const formData = reactive<Record<string, any>>({
weapp_name: '',
weapp_original: '',
app_id: '',
@ -161,31 +156,34 @@ const formData = reactive<Record<string, string>>({
socket_url: '',
upload_url: '',
download_url: '',
upload_private_key: ''
upload_private_key: '',
is_authorization: 0
})
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
weapp_name: [
{ required: true, message: t('weappNamePlaceholder'), trigger: 'blur' }
],
weapp_original: [
{ required: true, message: t('weappOriginalPlaceholder'), trigger: 'blur' }
],
app_id: [
{ required: true, message: t('appidPlaceholder'), trigger: 'blur' }
],
app_secret: [
{ required: true, message: t('appSecretPlaceholder'), trigger: 'blur' }
],
token: [
{ required: true, message: t('tokenPlaceholder'), trigger: 'blur' }
],
encoding_aes_key: [
{ required: true, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
]
const formRules = computed(() => {
return {
weapp_name: [
{ required: true, message: t('weappNamePlaceholder'), trigger: 'blur' }
],
weapp_original: [
{ required: true, message: t('weappOriginalPlaceholder'), trigger: 'blur' }
],
app_id: [
{ required: true, message: t('appidPlaceholder'), trigger: 'blur' }
],
app_secret: [
{ required: !formData.is_authorization, message: t('appSecretPlaceholder'), trigger: 'blur' }
],
token: [
{ required: true, message: t('tokenPlaceholder'), trigger: 'blur' }
],
encoding_aes_key: [
{ required: true, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
]
}
})
/**

View File

@ -1,68 +1,63 @@
<template>
<!--配置教程-->
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/weapp' })">
<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-card class="box-card !border-none" shadow="never">
<div class="mt-[20px]">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}<el-button link type="primary" @click="linkEvent">{{ t("writingTipsOne2") }}</el-button>,{{ t('writingTipsOne3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_1.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_2.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span class="text-primary">{{ t('writingTipsThree2') }}</span></p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_3.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">4</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsFour1') }}<span class="text-primary">URL /
Token / EncondingAESKey</span>{{ t('writingTipsFour2') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_4.png" />
</div>
</div>
</div>
</div>
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}<el-button link type="primary" @click="linkEvent">{{ t("writingTipsOne2") }}</el-button>,{{ t('writingTipsOne3') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_1.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_2.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span class="text-primary">{{ t('writingTipsThree2') }}</span></p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_3.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">4</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsFour1') }}<span class="text-primary">URL / Token / EncondingAESKey</span>{{ t('writingTipsFour2') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/weapp_4.png" />
</div>
</div>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
// import { img } from '@/utils/common'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()

View File

@ -1,39 +1,33 @@
<template>
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<el-card class="box-card !border-none" shadow="never">
<el-alert class="warm-prompt !my-[20px]" type="info">
<template #default>
<div class="flex">
<el-icon class="mr-2 mt-[2px]" size="18">
<Warning />
</el-icon>
<div>
<p class="text-base">{{ t('operationTipTwo') }}</p>
</div>
</div>
</template>
</el-alert>
<div>
<el-table :data="cronTableData.data" :span-method="templateSpan" size="large" v-loading="cronTableData.loading">
<!--订阅消息-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
<el-tab-pane :label="t('subscribeMessage')" name="/channel/weapp/message" />
<el-tab-pane :label="t('weappRelease')" name="/channel/weapp/code" />
</el-tabs>
<el-alert :title="t('operationTipTwo')" type="info" show-icon />
<div class="mt-[20px]">
<el-table :data="cronTableData.data" :span-method="templateSpan" size="large" v-loading="cronTableData.loading">
<template #empty>
<span>{{ !cronTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="addon_name" :label="t('addon')" min-width="120" />
<el-table-column prop="name" :show-overflow-tooltip="true" :label="t('name')" min-width="150" >
<template #default="{ row }">
<div class="flex items-center">
<span class="mr-[5px]">{{row.name }}</span>
<el-tooltip :content="row.weapp.tips" v-if="row.weapp.tips" placement="top">
<icon name="element-WarningFilled" />
<icon name="element WarningFilled" />
</el-tooltip>
</div>
</template>
@ -174,32 +168,4 @@ const infoSwitch = (res:any) => {
</script>
<style lang="scss" scoped>
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__active-bar {
display: none;
}
.el-tabs__item.is-active {
border-bottom: 2px solid var(--el-color-primary);
}
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}</style>
<style lang="scss" scoped></style>

View File

@ -1,147 +1,138 @@
<template>
<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="p-[20px]">
<p class="text-[16px] mb-[20px]">{{ t("wechatInlet") }}</p>
<el-row>
<el-col :span="20">
<el-steps direction="vertical">
<el-step>
<template #icon v-if="active > 1">
<el-icon size="25px" class="text-color">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 1">
<div
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>
</template>
<template #icon v-else>
<div
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
1</div>
</template>
<template #title>
<p class=" text-[14px] text-[#303133] font-[700]">
{{ t("wechatAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatAttestation1") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://mp.weixin.qq.com/')">{{
t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 2">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 2">
<div
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>
</template>
<template #icon v-else>
<div
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
2</div>
</template>
<template #title>
<p class=" text-[14px] text-[#303133] font-[700]">
{{ t("wechatSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatSetting1") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/wechat/config')">{{
t("settingInfo")
}}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #icon v-if="active > 3">
<el-icon size="25px">
<CircleCheckFilled />
</el-icon>
</template>
<template #icon v-else-if="active == 3">
<div
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>
</template>
<template #icon v-else>
<div
class="w-[24px] h-[24px] text-[#fff] bg-[#778aa3] text-center leading-[24px] rounded-full">
3</div>
</template>
<template #title>
<p class=" text-[14px] text-[#303133] font-[700]">
{{ t("wechatAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatAccess") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/wechat/course')">{{
t("releaseCourse")
}}</el-button>
</div>
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrcode ? img(qrcode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrcode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class=" text-[14px] text-[#303133] font-[700]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
<!--微信公众号-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @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="p-[20px]">
<h3 class="panel-title !text-sm">{{ t("wechatInlet") }}</h3>
<el-row>
<el-col :span="20">
<el-steps class="!mt-[10px]" :active="3" direction="vertical">
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("wechatAttestation") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatAttestation1") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://mp.weixin.qq.com/')">{{ t("clickAccess") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("wechatSetting") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatSetting1") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<template v-if="oplatformConfig.app_id && oplatformConfig.app_secret">
<el-button type="primary" @click="router.push('/channel/wechat/config')">{{ wechatConfig.app_id ? t("seeConfig") : t("clickSetting") }}</el-button>
<el-button type="primary" plain @click="authBindWechat">{{ wechatConfig.is_authorization ? t("refreshAuth") : t("authWechat") }}</el-button>
</template>
<template v-else>
<el-button type="primary" @click="router.push('/channel/wechat/config')">{{ t("clickSetting") }}</el-button>
</template>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("wechatAccess") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("wechatAccess") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/wechat/course')">{{ t("releaseCourse") }}</el-button>
</div>
</template>
</el-step>
</el-steps>
</el-col>
<el-col :span="4">
<div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qrcode ? img(qrcode) : ''">
<template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qrcode ? t('fileErr') : t('emptyQrCode') }}</span>
</div>
</template>
</el-image>
</div>
<div class="mt-[22px] text-center">
<p class="text-[12px]">{{ t('clickAccess2') }}</p>
</div>
</el-col>
</el-row>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ref, onMounted, onUnmounted } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { getWechatConfig } from '@/app/api/wechat'
import { getAuthorizationUrl } from '@/app/api/wxoplatform'
import { getWxoplatform } from '@/app/api/sys'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/wechat')
const active = ref(2)
const qrcode = ref('')
const wechatConfig = ref({})
const oplatformConfig = ref({})
const onShowGetWechatConfig = async () => {
await getWechatConfig().then(({data}) => {
wechatConfig.value = data
qrcode.value = data.qr_code
})
}
onMounted(async () => {
const res = await getWechatConfig()
qrcode.value = res.data.qr_code
onShowGetWechatConfig()
await getWxoplatform().then(({ data }) => {
oplatformConfig.value = data
})
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
onShowGetWechatConfig()
}
})
})
onUnmounted(() => {
document.removeEventListener('visibilitychange', () => {
})
})
const linkEvent = (url: string) => {
@ -151,67 +142,12 @@ const linkEvent = (url: string) => {
const handleClick = (val: any) => {
router.push({ path: activeName.value })
}
const authBindWechat = () => {
getAuthorizationUrl().then(({ data }) => {
window.open(data)
})
}
</script>
<style lang="scss" scoped>
.progress-point {
flex-grow: 1;
list-style: none;
}
.border-color {
border-color: var(--el-color-primary);
}
.bg-color {
background-color: var(--el-color-primary);
}
.text-color {
color: var(--el-color-primary);
}
.bg-color1 {
background-color: var(--el-color-info-light-8);
}
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__active-bar {
display: none;
}
.el-tabs__item.is-active {
border-bottom: 2px solid var(--el-color-primary);
}
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}
:deep(.el-step.is-vertical .el-step__icon.is-icon) {
padding: 8px 0;
height: 40px;
background-color: #fff;
}
:deep(.el-step__title) {
height: 40px;
line-height: 40px !important;
}
</style>
<style lang="scss" scoped></style>

View File

@ -23,7 +23,7 @@
{{ 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" />
<icon name="element Delete" color="#fff" size="40px" />
</div>
</div>
</div>

View File

@ -1,29 +1,24 @@
<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 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 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 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 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 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>
@ -43,7 +38,7 @@
<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)" />
<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>
@ -51,7 +46,7 @@
<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)" />
<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>
@ -66,7 +61,7 @@
<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)" />
<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>
@ -74,7 +69,7 @@
<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)" />
<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>
@ -89,7 +84,7 @@
<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)" />
<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>
@ -113,7 +108,7 @@
<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)" />
<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>

View File

@ -2,8 +2,7 @@
<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">
<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">
@ -24,15 +23,13 @@
<!-- 素材管理 -->
<div v-if="attachment.data.length">
<div class="flex flex-wrap" v-if="prop.type != 'news'">
<div class="attachment-item mr-[10px] mb-[10px] w-[120px]" v-for="(item, index) in attachment.data"
:key="index" @click="selectedFile = item">
<div class="attachment-item mr-[10px] mb-[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" />
<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" />
<icon name="element Select" color="#fff" size="40px" />
</div>
</div>
</div>
@ -64,16 +61,14 @@
{{ 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" />
<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" />
<el-empty v-if="!attachment.loading" :description="t('upload.mediaEmpty')" :image-size="100" />
</div>
</el-scrollbar>
</div>
@ -198,8 +193,7 @@
heights[i] = item.clientHeight + 10
} else {
let minHeight = Math.min(...heights) //
let minIndex = heights.findIndex(item => item ===
minHeight) //
let minIndex = heights.findIndex(item => item === minHeight) //
let position = {}
position.top = minHeight + 10 + "px"
position.left = positions[minIndex].left

View File

@ -1,49 +1,44 @@
<template>
<!--公众号配置-->
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/wechat' })">
<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="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" :rules="formRules" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('wechatInfo') }}</h3>
<el-form-item :label="t('wechatName')" prop="wechat_name">
<el-input v-model.trim="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
</el-form-item>
<el-form-item :label="t('wechatOriginal')" prop="wechat_original">
<el-input v-model.trim="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
</el-form-item>
<el-form-item :label="t('wechatQrcode')" prop="qr_code">
<upload-image v-model="formData.qr_code" />
<div class="form-tip">{{ t('wechatQrcodeTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('wechatDevelopInfo') }}</h3>
<el-form-item :label="t('wechatAppid')" prop="app_id">
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable />
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable :readonly="formData.is_authorization"/>
<div class="form-tip">{{ t('wechatAppidTips') }}</div>
</el-form-item>
<el-form-item :label="t('wechatAppsecret')" prop="app_secret">
<el-form-item :label="t('wechatAppsecret')" prop="app_secret" v-if="!formData.is_authorization">
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
<el-form-item label="URL">
@ -76,7 +71,7 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[16px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<div class="flex">
<h3 class="panel-title !text-sm">{{ t('functionSetting') }}</h3>
</div>
@ -111,7 +106,6 @@
</template>
</el-input>
</el-form-item>
</el-card>
</el-form>
@ -124,11 +118,12 @@
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { reactive, ref, watch, computed } from 'vue'
import { t } from '@/lang'
import { getWechatConfig, getWechatStatic, editWechatConfig } from '@/app/api/wechat'
import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { ElMessage, FormInstance } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
@ -137,7 +132,7 @@ const pageName = route.meta.title
const loading = ref(true)
const formData = reactive<Record<string, string>>({
const formData = reactive<Record<string, any>>({
wechat_name: '',
wechat_original: '',
app_id: '',
@ -145,31 +140,34 @@ const formData = reactive<Record<string, string>>({
qr_code: '',
token: '',
encoding_aes_key: '',
encryption_type: 'not_encrypt'
encryption_type: 'not_encrypt',
is_authorization: 0
})
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
wechat_name: [
{ required: true, message: t('wechatNamePlaceholder'), trigger: 'blur' }
],
wechat_original: [
{ required: true, message: t('wechatOriginalPlaceholder'), trigger: 'blur' }
],
app_id: [
{ required: true, message: t('appidPlaceholder'), trigger: 'blur' }
],
app_secret: [
{ required: true, message: t('appSecretPlaceholder'), trigger: 'blur' }
],
token: [
{ required: true, message: t('tokenPlaceholder'), trigger: 'blur' }
],
encoding_aes_key: [
{ required: true, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
]
const formRules = computed(() => {
return {
wechat_name: [
{ required: true, message: t('wechatNamePlaceholder'), trigger: 'blur' }
],
wechat_original: [
{ required: true, message: t('wechatOriginalPlaceholder'), trigger: 'blur' }
],
app_id: [
{ required: true, message: t('appidPlaceholder'), trigger: 'blur' }
],
app_secret: [
{ required: !formData.is_authorization, message: t('appSecretPlaceholder'), trigger: 'blur' }
],
token: [
{ required: true, message: t('tokenPlaceholder'), trigger: 'blur' }
],
encoding_aes_key: [
{ required: true, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
]
}
})
/**

View File

@ -1,68 +1,60 @@
<template>
<div class="main-container">
<div class="detail-head">
<div class="left" @click="router.push({ path: '/channel/wechat' })">
<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-card class="box-card !border-none" shadow="never">
<!--发布教程-->
<div class="main-container">
<div class="mt-[20px]">
<div class="flex">
<div class="min-w-[60px]">
<span
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}--<el-button link type="primary"
@click="linkEvent">{{ t('writingTipsOne2') }}</el-button>, {{ t('writingTipsOne3') }}<span
class="text-primary">URL / Token / EncondingAESKey</span>{{ t('writingTipsOne4') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_1.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('writingTipsOne5') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_4.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_2.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span
class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span
class="text-primary">{{ t('writingTipsThree2') }}</span></p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_3.png" />
</div>
</div>
</div>
</div>
</el-card>
</div>
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-card class="box-card mt-[15px] pt-[20px] !border-none" shadow="never">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}--<el-button link type="primary"
@click="linkEvent">{{ t('writingTipsOne2') }}</el-button>, {{ t('writingTipsOne3') }}<span
class="text-primary">URL / Token / EncondingAESKey</span>{{ t('writingTipsOne4') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_1.png" />
</div>
<p class="flex items-center text-[14px] mt-[20px]">{{ t('writingTipsOne5') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_4.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">2</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsTwo1') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_2.png" />
</div>
</div>
</div>
<div class="flex mt-[40px]">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">3</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsThree1') }}<span class="text-primary">{{ t('writingTipsThree2') }}</span></p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_3.png" />
</div>
</div>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getWechatConfig } from '@/app/api/wechat'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRouter, useRoute } from 'vue-router'
const route = useRoute()

View File

@ -1,15 +1,12 @@
<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="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" :rules="formRules" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<el-form-item :label="t('ruleName')" prop="name">
@ -46,7 +43,7 @@
<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)"/>
<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>
@ -68,19 +65,18 @@
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
</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>
</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>
@ -88,6 +84,7 @@ 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 { ArrowLeft } from '@element-plus/icons-vue'
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'

View File

@ -1,85 +1,88 @@
<template>
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-page-title">{{ pageName }}</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="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="head w-full h-[70px]"></div>
<!--自定义菜单-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="menu-list h-[70px] flex border-t border-color">
<div class="py-[15px]">
<div class="flex h-full px-[10px] items-center justify-center border-r border-color">
<icon name="iconfont-iconjianpan" size="20px" color="#b1b2b3" />
</div>
</div>
<div class="flex-1 flex w-0">
<div class="menu-item py-[15px] flex items-center justify-center cursor-pointer"
:class="{ 'size-1': button.length == 1, 'size-2-3': button.length > 1, 'active': index == buttonIndex, 'curr': index == buttonIndex && subButtonIndex == -1 }"
v-for="(item, index) in button" :key="index" @click="selectButton(index)">
<div
class="menu-name px-[10px] border-r border-color w-full leading-[40px] text-base truncate text-center">
{{ item.name }}</div>
<div class="active-shade"></div>
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<!-- 子菜单 -->
<div class="sub-menu-wrap w-full bg-overlay border border-color rounded">
<div class="menu-item h-[50px] p-[10px] border-b border-color flex items-center justify-center cursor-pointer"
:class="{ 'curr': subIndex == subButtonIndex }"
v-for="(subItem, subIndex) in item.sub_button" :key="subIndex"
@click.stop="selectBubButton(index, subIndex)">
<div class="menu-name w-full text-base truncate text-center">{{ subItem.name }}</div>
<div class="active-shade"></div>
</div>
<!-- 添加子菜单 -->
<div class="add-menu flex items-center justify-center flex-1 cursor-pointer menu-item h-[50px]"
v-show="!item.sub_button || item.sub_button.length < 5"
@click.stop="addSubButton(index)">
<icon name="element-Plus" />
</div>
<el-tabs v-model="activeName" class="my-[20px]" @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="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="head w-full h-[70px]"></div>
<div class="menu-list h-[70px] flex border-t border-color">
<div class="py-[15px]">
<div class="flex h-full px-[10px] items-center justify-center border-r border-color">
<icon name="iconfont iconjianpan" size="20px" color="#b1b2b3" />
</div>
</div>
<!-- 添加菜单 -->
<div class="add-menu flex items-center justify-center flex-1 cursor-pointer menu-item"
v-show="button.length < 3" @click="addButton">
<icon name="element-Plus" />
<div class="flex-1 flex w-0">
<div class="menu-item py-[15px] flex items-center justify-center cursor-pointer"
:class="{ 'size-1': button.length == 1, 'size-2-3': button.length > 1, 'active': index == buttonIndex, 'curr': index == buttonIndex && subButtonIndex == -1 }"
v-for="(item, index) in button" :key="index" @click="selectButton(index)">
<div class="menu-name px-[10px] border-r border-color w-full leading-[40px] text-base truncate text-center">{{ item.name }}</div>
<div class="active-shade"></div>
<!-- 子菜单 -->
<div class="sub-menu-wrap w-full bg-overlay border border-color rounded">
<div class="menu-item h-[50px] p-[10px] border-b border-color flex items-center justify-center cursor-pointer"
:class="{ 'curr': subIndex == subButtonIndex }"
v-for="(subItem, subIndex) in item.sub_button" :key="subIndex"
@click.stop="selectBubButton(index, subIndex)">
<div class="menu-name w-full text-base truncate text-center">{{ subItem.name }}</div>
<div class="active-shade"></div>
</div>
<!-- 添加子菜单 -->
<div class="add-menu flex items-center justify-center flex-1 cursor-pointer menu-item h-[50px]"
v-show="!item.sub_button || item.sub_button.length < 5"
@click.stop="addSubButton(index)">
<icon name="element Plus" />
</div>
</div>
</div>
<!-- 添加菜单 -->
<div class="add-menu flex items-center justify-center flex-1 cursor-pointer menu-item" v-show="button.length < 3" @click="addButton">
<icon name="element Plus" />
</div>
</div>
</div>
</div>
</div>
<div class="flex-1">
<el-card class="box-card !border-none h-auto" shadow="never">
<template v-if="button.length">
<div class="flex-1">
<el-card class="box-card !border-none h-auto" shadow="never">
<template v-if="button.length">
<div v-for="(item, index) in button" :key="index">
<div v-show="index == buttonIndex && subButtonIndex == -1">
<menu-form :data="item" @delete="deleteButton" :index="index" ref="formRef" />
</div>
<div v-for="(item, index) in button" :key="index">
<div v-show="index == buttonIndex && subButtonIndex == -1">
<menu-form :data="item" @delete="deleteButton" :index="index" ref="formRef" />
</div>
<div v-for="(subItem, subIndex) in item.sub_button" :key="subIndex">
<div v-show="index == buttonIndex && subIndex == subButtonIndex">
<menu-form :data="subItem" @delete="deleteButton" :index="index" :sub-index="subIndex"
ref="formRef" />
<div v-for="(subItem, subIndex) in item.sub_button" :key="subIndex">
<div v-show="index == buttonIndex && subIndex == subButtonIndex">
<menu-form :data="subItem" @delete="deleteButton" :index="index" :sub-index="subIndex" ref="formRef" />
</div>
</div>
</div>
</div>
</template>
<div v-else class="py-[20px] leading">尚未添加自定义菜单点击左侧添加菜单为公众号创建菜单栏</div>
</el-card>
</template>
<div v-else class="py-[20px] leading">尚未添加自定义菜单点击左侧添加菜单为公众号创建菜单栏</div>
</el-card>
</div>
</div>
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="save()">{{ t('save') }}</el-button>
</div>
</div>
</div>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="save()">{{ t('save') }}</el-button>
</div>
</div>
</template>
@ -221,100 +224,74 @@ const save = async () => {
</script>
<style lang="scss" scoped>
.preview-wrap {
.head {
background: url('@/app/assets/images/wechat-menu-head-bg.png');
background-size: cover;
}
.preview-wrap {
.menu-item {
position: relative;
&.size-1 {
width: 50%;
.head {
background: url('@/app/assets/images/wechat-menu-head-bg.png');
background-size: cover;
}
&.size-2-3 {
width: 33.33%;
.menu-item {
position: relative;
&.size-1 {
width: 50%;
}
&.size-2-3 {
width: 33.33%;
}
&:nth-child(3)>.menu-name {
border-right: 0;
}
.active-shade {
position: absolute;
width: 100%;
height: 100%;
border: 1px solid var(--el-color-primary);
display: none;
left: 0;
top: 0;
}
&.curr {
background: var(--el-color-primary-light-9);
>.menu-name {
color: var(--el-color-primary);
}
&>.active-shade {
display: block;
}
}
&.active {
.sub-menu-wrap {
display: block !important;
}
}
}
&:nth-child(3)>.menu-name {
border-right: 0;
}
.active-shade {
position: absolute;
width: 100%;
height: 100%;
border: 1px solid var(--el-color-primary);
.sub-menu-wrap {
display: none;
left: 0;
position: absolute;
top: 0;
}
transform: translateY(calc(-100% - 15px));
&.curr {
background: var(--el-color-primary-light-9);
>.menu-name {
color: var(--el-color-primary);
}
&>.active-shade {
display: block;
}
}
&.active {
.sub-menu-wrap {
display: block !important;
.menu-item:nth-child(5) {
border-bottom: 0;
}
}
}
.sub-menu-wrap {
display: none;
position: absolute;
top: 0;
transform: translateY(calc(-100% - 15px));
.dark {
.menu-item:nth-child(5) {
border-bottom: 0;
.preview-wrap .head {
background: url('@/app/assets/images/wechat-menu-head-dark-bg.png');
background-size: cover;
}
}
}
.dark {
.preview-wrap .head {
background: url('@/app/assets/images/wechat-menu-head-dark-bg.png');
background-size: cover;
}
}
:deep(.el-tabs__item:hover) {
border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs__item) {
padding: 0;
}
:deep(.el-tabs__item+.el-tabs__item) {
margin-right: 20px;
margin-left: 20px;
// border-bottom: 2px solid var(--el-color-primary);
}
:deep(.el-tabs--top) {
.el-tabs__active-bar {
display: none;
}
.el-tabs__item.is-active {
border-bottom: 2px solid var(--el-color-primary);
}
.el-tabs__item.is-top:nth-child(2) {
margin-right: 20px;
}
}</style>
</style>

View File

@ -1,68 +1,77 @@
<template>
<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 class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ t('title') }}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @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>
<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 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 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 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>
</el-card>
</div>
</template>

View File

@ -1,68 +1,64 @@
<template>
<div class="main-container p-5 bg-[#fff] rounded-[4px]">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-page-title">{{ pageName }}</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>
<el-card class="box-card !border-none" shadow="never">
<!--模板消息-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="batchAcquisitionFn()">{{ t('batchAcquisition')
}}</el-button>
<el-button type="primary" class="w-[100px]" @click="batchAcquisitionFn()">{{ t('batchAcquisition') }}</el-button>
</div>
<div class="mt-[10px]">
<el-table :data="cronTableData.data" :span-method="templateSpan" size="large" v-loading="cronTableData.loading">
<template #empty>
<span>{{ !cronTableData.loading ? t('emptyData') : '' }}</span>
<el-tabs v-model="activeName" class="my-[20px]" @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>
<el-table :data="cronTableData.data" :span-method="templateSpan" size="large" v-loading="cronTableData.loading">
<template #empty>
<span>{{ !cronTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="addon_name" :label="t('addon')" min-width="120" />
<el-table-column prop="name" :show-overflow-tooltip="true" :label="t('name')" min-width="150" >
<template #default="{ row }">
<div class="flex items-center">
<span class="mr-[5px]">{{row.name }}</span>
<el-tooltip :content="row.wechat.tips" v-if="row.wechat.tips" placement="top">
<icon name="element WarningFilled" />
</el-tooltip>
</div>
</template>
<el-table-column prop="addon_name" :label="t('addon')" min-width="120" />
<el-table-column prop="name" :show-overflow-tooltip="true" :label="t('name')" min-width="150" >
<template #default="{ row }">
<div class="flex items-center">
<span class="mr-[5px]">{{row.name }}</span>
<el-tooltip :content="row.wechat.tips" v-if="row.wechat.tips" placement="top">
<icon name="element-WarningFilled" />
</el-tooltip>
</div>
</template>
</el-table-column>
</el-table-column>
<el-table-column :label="t('messageType')" min-width="100" align="center">
<template #default="{ row }">
<span>{{ row.message_type == 1 ? t('buyerNews') : t('sellerMessage') }}</span>
</template>
</el-table-column>
<el-table-column :label="t('messageType')" min-width="100" align="center">
<template #default="{ row }">
<span>{{ row.message_type == 1 ? t('buyerNews') : t('sellerMessage') }}</span>
</template>
</el-table-column>
<el-table-column :label="t('isStart')" min-width="100" align="center">
<template #default="{ row }">
{{ row.is_wechat == 1 ? t('startUsing') : t('statusDeactivate') }}
</template>
</el-table-column>
<el-table-column :label="t('isStart')" min-width="100" align="center">
<template #default="{ row }">
{{ row.is_wechat == 1 ? t('startUsing') : t('statusDeactivate') }}
</template>
</el-table-column>
<el-table-column :label="t('response')" min-width="180">
<template #default="{ row }">
<div v-for="(item, index) in row.wechat.content" :key="'a' + index" class="text-left">
{{ item.join("") }}</div>
</template>
</el-table-column>
<el-table-column :label="t('response')" min-width="180">
<template #default="{ row }">
<div v-for="(item, index) in row.wechat.content" :key="'a' + index" class="text-left">{{ item.join("") }}</div>
</template>
</el-table-column>
<el-table-column prop="wechat_template_id" :label="t('serialNumber')" min-width="140" />
<el-table-column :label="t('operation')" fixed="right" align="right" width="200">
<template #default="{ row }">
<el-button type="primary" link @click="infoSwitch(row)">{{ row.is_wechat == 1 ? t('close') :
t('open') }}</el-button>
<el-button type="primary" link @click="batchAcquisitionFn(row)">{{ t('regain') }}</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-table-column prop="wechat_template_id" :label="t('serialNumber')" min-width="140" />
<el-table-column :label="t('operation')" fixed="right" align="right" width="200">
<template #default="{ row }">
<el-button type="primary" link @click="infoSwitch(row)">{{ row.is_wechat == 1 ? t('close') : t('open') }}</el-button>
<el-button type="primary" link @click="batchAcquisitionFn(row)">{{ t('regain') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>

View File

@ -21,42 +21,34 @@
<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>
<el-button type="primary" @click="confirm()">{{ t('confirm') }}</el-button>
</span>
</template>
<el-dialog v-model="dialogVisible" :title="type != 'edit' ? t('addDictData') : t('editDictData')" width="480"
class="diy-dialog-wrap" :destroy-on-close="true">
<el-dialog v-model="dialogVisible" :title="type != 'edit' ? t('addDictData') : t('editDictData')" width="480" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form">
<el-form-item :label="t('name')">
<el-input v-model="name" disabled class="input-width" />
</el-form-item>
<el-form-item :label="t('dataName')" prop="name">
<el-input v-model="formData.name" clearable :placeholder="t('dataNamePlaceholder')"
class="input-width" />
<el-input v-model="formData.name" clearable :placeholder="t('dataNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('dataValue')" prop="value">
<el-input v-model="formData.value" clearable :placeholder="t('dataValuePlaceholder')"
class="input-width" />
<el-input v-model="formData.value" clearable :placeholder="t('dataValuePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<div>
<el-input-number v-model="formData.sort" ::step="1" step-strictly :value-on-clear="0" :min="0" class="input-width" />
<p class="text-[12px] text-[#a9a9a9] leading-normal mt-[5px]">{{ t('sortPlaceholder') }}</p>
</div>
<el-input-number v-model="formData.sort" ::step="1" step-strictly :value-on-clear="0" :min="0" class="input-width" />
<p class="text-[12px] text-[#a9a9a9] leading-normal mt-[5px]">{{ t('sortPlaceholder') }}</p>
</div>
</el-form-item>
<el-form-item :label="t('memo')">
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('momePlaceholder')"
class="input-width" />
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('momePlaceholder')" class="input-width" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="submit(formRef)">{{
t('confirm')
}}</el-button>
<el-button type="primary" @click="submit(formRef)">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
@ -94,11 +86,9 @@ const formRules = computed(() => {
return {
name: [
{ required: true, message: t('dataNamePlaceholder'), trigger: 'blur' }
],
value: [
{ required: true, message: t('dataValuePlaceholder'), trigger: 'blur' }
]
}
})
@ -107,10 +97,10 @@ const addEvent = () => {
formData.value = cloneDeep(initialFormData)
dialogVisible.value = true
}
const tabelIndex = ref(0)
const tableIndex = ref(0)
const editEvent = (row: any, index: number) => {
type.value = 'edit'
tabelIndex.value = index
tableIndex.value = index
formData.value = cloneDeep(initialFormData)
formData.value = Object.assign(formData.value, cloneDeep(row))
dialogVisible.value = true
@ -125,7 +115,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (type.value != 'edit') {
tableDate.value.push(cloneDeep(formData.value))
} else {
tableDate.value.splice(tabelIndex.value, 1, cloneDeep(formData.value))
tableDate.value.splice(tableIndex.value, 1, cloneDeep(formData.value))
}
tableDate.value.sort(function (a, b) { return b.sort - a.sort })
dialogVisible.value = false
@ -142,7 +132,6 @@ const deleteEvent = (index: number) => {
}
/**
* 确认
* @param formEl
*/
const confirm = async () => {
loading.value = true

View File

@ -1,25 +1,21 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateDict') : t('addDict')" width="480" class="diy-dialog-wrap"
:destroy-on-close="true">
<el-dialog v-model="showDialog" :title="formData.id ? t('updateDict') : t('addDict')" width="480" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('name')" prop="name">
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('key')" prop="key">
<el-input v-model="formData.key" clearable :placeholder="t('keyPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('memo')">
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('memoPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('name')" prop="name">
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('key')" prop="key">
<el-input v-model="formData.key" clearable :placeholder="t('keyPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('memo')">
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('memoPlaceholder')" class="input-width" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
@ -42,7 +38,6 @@ const initialFormData = {
name: '',
key: '',
memo: ''
}
const formData: Record<string, any> = reactive({ ...initialFormData })

View File

@ -1,4 +1,5 @@
<template>
<!--数据字典-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
@ -155,14 +156,4 @@ const resetForm = (formEl: FormInstance | undefined) => {
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
<style lang="scss" scoped></style>

View File

@ -101,12 +101,12 @@
</el-form-item>
<el-form-item :label="t('activeCubeSubTitleBgColor')">
<el-color-picker v-model="item.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('activeListFrameColor')">
<el-color-picker v-model="item.listFrame.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.listFrame.endColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</div>
@ -118,7 +118,7 @@
<el-form-item :label="t('activeCubeButtonColor')">
<el-color-picker v-model="item.moreTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.moreTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</div>
@ -128,7 +128,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
</div>
</div>
@ -160,7 +160,7 @@
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors"/>
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>

View File

@ -58,7 +58,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" @click="diyStore.editComponent.search.hotWord.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
</div>
@ -101,7 +101,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.tab.list.length > 1" @click="diyStore.editComponent.tab.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
</div>
@ -151,7 +151,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.swiper.list.length > 1" @click="diyStore.editComponent.swiper.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<el-form-item :label="t('link')">

View File

@ -36,7 +36,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<el-form-item :label="t('link')">

View File

@ -65,7 +65,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<el-form-item :label="t('link')">

View File

@ -19,7 +19,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<el-form-item :label="t('link')">

View File

@ -58,7 +58,7 @@
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<el-form-item :label="t('link')" v-if="diyStore.editComponent.showType == 'link'">

View File

@ -73,7 +73,7 @@
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style5.png" />
</div>
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-6' }" @click="selectStyle = 'style-6'">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style6.png" />
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style6.jpg" />
</div>
</div>
@ -94,7 +94,7 @@
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('pageBgColor')">
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('bgGradientAngle')">
@ -137,7 +137,7 @@
<script lang="ts" setup>
import { t } from '@/lang'
import { watch, ref, onMounted, computed } from 'vue'
import { watch, ref } from 'vue'
import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
@ -153,6 +153,10 @@ watch(
diyStore.global.imgWidth = image.width
diyStore.global.imgHeight = image.height
}
if(!diyStore.global.bgUrl){
diyStore.global.imgWidth = ''
diyStore.global.imgHeight = ''
}
}
)

View File

@ -10,7 +10,7 @@
</el-form-item>
<ul class="selected-template-list">
<li v-for="(item,i) in templateList" :key="i" :class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]" @click="changeTemplateList(i)">
<icon :name="'iconfont-' + item.src" size="16px"/>
<icon :name="'iconfont ' + item.src" size="16px"/>
</li>
</ul>
</el-form>

View File

@ -148,10 +148,4 @@ defineExpose({})
</script>
<style lang="scss">
.horz-blank-slider {
.el-slider__input {
width: 100px;
}
}</style>
<style lang="scss" scoped></style>

View File

@ -13,12 +13,14 @@
<!--<el-icon class="font-bold"><EditPen /></el-icon>-->
</div>
<div v-if="diyStore.type && diyStore.type != 'DIY_PAGE'">
<div v-if="diyStore.type && diyStore.type != 'DIY_PAGE'" class="flex items-center">
<span class="text-white mr-[10px] text-base">{{ t('templatePagePlaceholder') }}</span>
<el-select size="small" v-model="template" class="w-[180px]" :placeholder="t('templatePagePlaceholder')" @change="changeTemplatePage">
<el-option :label="t('templatePageEmpty')" value="" />
<el-option v-for="(item, key) in templatePages" :label="item.title" :value="key" :key="key"/>
</el-select>
<div class="w-[180px]">
<el-select size="small" v-model="template" :placeholder="t('templatePagePlaceholder')" @change="changeTemplatePage">
<el-option :label="t('templatePageEmpty')" value="" />
<el-option v-for="(item, key) in templatePages" :label="item.title" :value="key" :key="key"/>
</el-select>
</div>
</div>
<div class="flex-1"></div>
<el-button @click="preview()">{{ t('preview') }}</el-button>
@ -36,7 +38,7 @@
<ul class="flex flex-row flex-wrap">
<li v-for="(compItem, compKey) in item.list" :key="compKey" class="w-2/6 text-center cursor-pointer h-[65px]" :title="compItem.title" @click="diyStore.addComponent(compKey, compItem)">
<icon v-if="compItem.icon" :name="compItem.icon" size="20px" class="inline-block mt-[3px]" />
<icon v-else name="iconfont-iconkaifazujian" size="20px" class="inline-block mt-[3px]" />
<icon v-else name="iconfont iconkaifazujian" size="20px" class="inline-block mt-[3px]" />
<span class="block text-[12px] truncate">{{ compItem.title }}</span>
</li>
</ul>
@ -84,19 +86,19 @@
<ul class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
<el-tooltip effect="light" :content="t('moveUpComponent')" placement="right">
<icon name="iconfont-iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
<icon name="iconfont iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
</el-tooltip>
<el-tooltip effect="light" :content="t('moveDownComponent')" placement="right">
<icon name="iconfont-iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
<icon name="iconfont iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
</el-tooltip>
<el-tooltip effect="light" :content="t('copyComponent')" placement="right">
<icon name="iconfont-iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
<icon name="iconfont iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
</el-tooltip>
<el-tooltip effect="light" :content="t('delComponent')" placement="right">
<icon name="iconfont-icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
<icon name="iconfont icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
</el-tooltip>
<el-tooltip effect="light" :content="t('resetComponent')" placement="right">
<icon name="iconfont-iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
<icon name="iconfont iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
</el-tooltip>
</ul>
@ -145,7 +147,7 @@
<template v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
<el-form-item :label="t('bottomBgColor')">
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<div class="text-sm text-gray-400 ml-[90px] mb-[10px]">{{ t('bottomBgTips') }}</div>
@ -168,7 +170,7 @@
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
<el-color-picker v-model="diyStore.editComponent.componentStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.componentEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
@ -328,7 +330,7 @@ watch(
//
const changeTemplatePage = (value:any)=> {
//
if(diyStore.value.length) {
if (diyStore.value.length) {
ElMessageBox.confirm(t('changeTemplatePageTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
@ -344,13 +346,13 @@ const changeTemplatePage = (value:any)=> {
} else {
//
diyStore.init();
if(route.query.title) diyStore.global.title = diyStore.typeName
if (route.query.title) diyStore.global.title = diyStore.typeName
}
}).catch(() => {
//
template.value = oldTemplate.value;
});
}else{
} else {
if (value) {
let data = templatePages[value].data;
diyStore.global = data.global;
@ -360,7 +362,7 @@ const changeTemplatePage = (value:any)=> {
} else {
//
diyStore.init();
if(route.query.title) diyStore.global.title = diyStore.typeName
if (route.query.title) diyStore.global.title = diyStore.typeName
}
}
};
@ -402,6 +404,7 @@ initPage({
diyStore.type = data.type
diyStore.typeName = data.type_name
diyStore.templateName = data.template
template.value = data.template;
diyStore.isDefault = data.is_default
diyStore.pageMode = data.mode
if (data.value) {
@ -443,23 +446,6 @@ initPage({
}
}
//
if (data.addon_list) {
const addonModules = import.meta.glob('@/**/views/diy/components/*.vue')
for (let i = 0; i < data.addon_list.length; i++) {
const item = data.addon_list[i]
for (const [key, value] of Object.entries(addonModules)) {
const moduleName = key.split('/')
const addonName = moduleName[2]
if (item.key == addonName) {
const name = moduleName[moduleName.length - 1].replace('.vue', '')
const module = await value()
modules[name] = module.default
}
}
}
}
loadDiyTemplatePages(data.type);
//
@ -737,100 +723,104 @@ const settingTips = () => {
border: none;
}
.diy-view-wrap .preview-head{
.diy-view-wrap .preview-head {
padding: 28px 15px 0;
.content-wrap{
.content-wrap {
height: 30px;
}
&.style-1 {
.content-wrap {
.title-wrap {
&.style-1 {
.content-wrap {
.title-wrap {
height: 30px;
line-height: 30px;
}
}
}
}
}
}
&.style-2 {
.content-wrap {
.title-wrap {
display: flex;
&.style-2 {
.content-wrap {
.title-wrap {
display: flex;
align-items: center;
> div {
height: 30px;
line-height: 30px;
max-width: 150px;
font-size: 14px;
> div {
height: 30px;
line-height: 30px;
max-width: 150px;
font-size: 14px;
&:last-child {
overflow: hidden; //
text-overflow: ellipsis; //
white-space: nowrap; //
flex: 1;
max-width: 200px;
}
}
}
}
}
&:last-child {
overflow: hidden; //
text-overflow: ellipsis; //
white-space: nowrap; //
flex: 1;
max-width: 200px;
}
}
}
}
}
&.style-3 {
.content-wrap {
&.style-3 {
.content-wrap {
display: flex;
align-items: center;
.title-wrap {
height: 30px;
max-width: 85px;
margin-right: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.search {
flex: 1;
padding-right: 10px;
.title-wrap {
height: 30px;
max-width: 85px;
margin-right: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.search {
flex: 1;
padding-right: 10px;
padding-left: 31px;
position: relative;
background-color: #fff;
text-align: left;
border-radius: 30px;
height: 30px;
line-height: 30px;
border: 1px solid #eeeeee;
color: rgb(102, 102, 102);
display: flex;
align-items: center;
margin-right: 105px;
background-color: #fff;
text-align: left;
border-radius: 30px;
height: 30px;
line-height: 30px;
border: 1px solid #eeeeee;
color: rgb(102, 102, 102);
display: flex;
align-items: center;
margin-right: 105px;
overflow: hidden;
span{
span {
overflow: hidden; //
text-overflow: ellipsis; //
white-space: nowrap; //
}
.iconfont {
color: #909399;
font-size: 16px;
margin-right: 5px;
}
}
}
}
&.style-4 {
.content-wrap {
.iconfont {
color: #909399;
font-size: 16px;
margin-right: 5px;
}
}
}
}
&.style-4 {
.content-wrap {
display: flex;
align-items: center;
.title-wrap {
flex: none;
margin: 0 5px;
max-width: 180px;
font-size: 14px;
}
}
}
.title-wrap {
flex: none;
margin: 0 5px;
max-width: 180px;
font-size: 14px;
}
}
}
}
</style>

View File

@ -1,67 +1,67 @@
<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]">
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
<iframe :id="'previewIframe_' + type" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
<div class="flex flex-wrap min-w-[1200px]" v-if="page.use_template">
<div class="page-item relative w-[340px] mr-[40px] pt-[90px] pb-[20px] bg-[#f7f7f7] bg-no-repeat">
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] w-[130px] text-[14px] truncate text-center">{{ page.use_template.title }}</p>
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
<iframe :id="'previewIframe_' + type" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
</div>
<div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
</div>
</div>
</div>
<div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
</div>
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
</div>
<div class="w-[700px]">
<div class="flex flex-wrap">
<diy-link v-model="link" :ignore="['DIY_LINK']" @success="changePage">
<el-button type="primary">{{ t('changePage') }}</el-button>
</diy-link>
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
</div>
<div class="info-wrap">
<div class="mt-[20px] p-[20px] flex items-center justify-between bg">
<div>
<div class="font-bold">{{ t('H5') }}</div>
<el-form label-width="40px" class="mt-[5px]">
<el-form-item :label="t('link')" class="mb-[5px]">
<el-input readonly :value="page.shareUrl" class="!w-[390px]">
<template #append>
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
</div>
<div class="text-center">
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
</div>
</div>
</div>
</div>
</div>
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
</div>
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
</div>
<div class="w-[700px]">
<div class="flex flex-wrap">
<diy-link v-model="link" :ignore="['DIY_LINK']" @success="changePage">
<el-button type="primary">{{ t('changePage') }}</el-button>
</diy-link>
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
</div>
<div class="info-wrap">
<div class="mt-[20px] bg-[#F7F8FA] p-[20px] flex items-center justify-between">
<div>
<div class="font-bold">{{ t('H5') }}</div>
<el-form label-width="40px" class="mt-[5px]">
<el-form-item :label="t('link')" class="mb-[5px]">
<el-input readonly :value="page.shareUrl" class="!w-[390px]">
<template #append>
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
</div>
<div class="text-center">
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
</div>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
@ -327,19 +327,19 @@ watch(copied, () => {
</script>
<style lang="scss" scoped>
.page-item {
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
.page-item {
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
.popup-wrap {
display: none;
}
.popup-wrap {
display: none;
}
&:hover {
.popup-wrap:not(.disabled) {
display: block !important;
&:hover {
.popup-wrap:not(.disabled) {
display: block !important;
}
}
}
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<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>
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true">{{ t('addDiyPage') }}</el-button>
@ -31,7 +32,6 @@
</el-card>
<el-table :data="diyPageTableData.data" size="large" v-loading="diyPageTableData.loading">
<template #empty>
<span>{{ !diyPageTableData.loading ? t('emptyData') : '' }}</span>
</template>
@ -130,9 +130,10 @@ import { getApps,getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const pageType: any = reactive({}) //
//
@ -344,5 +345,4 @@ const resetForm = (formEl: FormInstance | undefined) => {
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>

View File

@ -1,87 +1,86 @@
<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]">
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex flex-wrap min-w-[1200px]" v-if="page.use_template">
<div class="page-item relative w-[340px] mr-[40px] pt-[90px] pb-[20px] bg-[#f7f7f7] bg-no-repeat">
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] w-[130px] text-[14px] truncate text-center">{{ page.use_template.title }}</p>
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
<iframe :id="'previewIframe_' + type" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
<iframe :id="'previewIframe_' + type" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
</div>
<div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
</div>
</div>
</div>
<div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
</div>
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
</div>
<div class="w-[700px]">
<div class="flex flex-wrap">
<!-- 多应用切换启动页 -->
<el-button type="primary" @click="showDialog = true" v-if="siteApps.length > 1">{{ t('changePage') }}</el-button>
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
</div>
<div class="info-wrap">
<div class="mt-[20px] p-[20px] flex items-center justify-between bg">
<div>
<div class="font-bold">{{ t('H5') }}</div>
<el-form label-width="40px" class="mt-[5px]">
<el-form-item :label="t('link')" class="mb-[5px]">
<el-input readonly :value="page.shareUrl" class="!w-[400px]">
<template #append>
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
</div>
<div class="text-center">
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
</div>
</div>
</div>
</div>
</div>
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
</div>
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
</div>
<div class="w-[700px]">
<div class="flex flex-wrap">
<!-- 多应用切换启动页 -->
<el-button type="primary" @click="showDialog = true" v-if="siteApps.length > 1">{{ t('changePage') }}</el-button>
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
</div>
<div class="info-wrap">
<div class="mt-[20px] bg-[#F7F8FA] p-[20px] flex items-center justify-between">
<div>
<div class="font-bold">{{ t('H5') }}</div>
<el-form label-width="40px" class="mt-[5px]">
<el-form-item :label="t('link')" class="mb-[5px]">
<el-input readonly :value="page.shareUrl" class="!w-[400px]">
<template #append>
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
</div>
<div class="text-center">
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
</div>
<el-dialog v-model="showDialog" :title="t('pageSelectTips')" width="400px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
<div class="flex items-start">
<el-scrollbar class="pl-4 h-[300px] flex-1">
<div class="flex flex-wrap">
<div v-for="(item, key) in pageType" :key="key"
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
:class="[key == link.name ? 'border-primary text-primary' : '']"
@click="changeLink(key,item)">{{ item.title }}
</div>
</div>
</el-scrollbar>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changePage()">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</el-card>
</div>
<el-dialog v-model="showDialog" :title="t('pageSelectTips')" width="400px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
<div class="flex items-start">
<el-scrollbar class="pl-4 h-[300px] flex-1">
<div class="flex flex-wrap">
<div v-for="(item, key) in pageType" :key="key"
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
:class="[key == link.name ? 'border-primary text-primary' : '']"
@click="changeLink(key,item)">{{ item.title }}
</div>
</div>
</el-scrollbar>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changePage()">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
@ -371,19 +370,19 @@ watch(copied, () => {
</script>
<style lang="scss" scoped>
.page-item {
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
.page-item {
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
.popup-wrap {
display: none;
}
.popup-wrap {
display: none;
}
&:hover {
.popup-wrap:not(.disabled) {
display: block !important;
&:hover {
.popup-wrap:not(.disabled) {
display: block !important;
}
}
}
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<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>
@ -27,6 +28,7 @@
<template #empty>
<span>{{ !diyRouteTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="title" :label="t('title')" min-width="70" />
<el-table-column prop="addon_title" :label="t('forAddon')" min-width="70">
<template #default="{ row }">
@ -98,11 +100,12 @@ import { useRoute, useRouter } from 'vue-router'
import { useClipboard } from '@vueuse/core'
import { getUrl } from '@/app/api/sys'
const pageTemplate: any = reactive({})
const router = useRouter()
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const pageTemplate: any = reactive({})
const formRef = ref<FormInstance>()
const dialogVisible = ref(false)
@ -127,7 +130,7 @@ getDomain()
const apps: any = reactive({}) //
getDiyRouteAppList({}).then(res=>{
getDiyRouteAppList().then(res=>{
if(res.data){
for (const key in res.data) {
apps[key] = res.data[key];

View File

@ -1,12 +1,12 @@
<template>
<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-table class="mt-[20px]" :data="bottomNavTableData.data" size="large" v-loading="bottomNavTableData.loading">
<template #empty>
<span>{{ !bottomNavTableData.loading ? t('emptyData') : '' }}</span>
</template>
@ -24,8 +24,8 @@
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="bottomNavTableData.page" v-model:page-size="bottomNavTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="bottomNavTableData.total"
@ -43,8 +43,8 @@
import { getDiyBottomList } from '@/app/api/diy'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const bottomNavTableData: any = reactive({
@ -86,5 +86,4 @@
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>

View File

@ -1,9 +1,13 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-loading="loading">
<div class="flex">
<div class="w-[360px] h-[400px] absolute mr-[30px] border-[1px] border-gray-300">
<div class="flex items-center justify-between absolute h-[60px] left-[0px] right-[0px] bottom-[0px] border-[1px] border-primary" :style="{ 'backgroundColor': diyBottomData.value.backgroundColor }">
<div class="flex items-center justify-between absolute h-[60px] left-[0px] right-[0px] bottom-[0px] border-[1px] border-primary" :style="{ 'backgroundColor': diyBottomData.value.backgroundColor }">
<div class="flex flex-1 flex-col items-center justify-center" v-for="(item, index) in diyBottomData.value.list" :key="'b' + index">
<el-image class="w-[22px] h-[22px] mb-[5px] leading-1" :src="img(item.iconPath)" :fit="contain" v-if="['1', '2'].includes(diyBottomData.value.type.toString())">
<template #error>
@ -41,7 +45,7 @@
</div>
</el-form-item>
<el-form-item :label="t('navTitleOne')">
<el-input class="w-[215px]" v-model="item.text" :placeholder="t('titleContent')" maxlength="5" show-word-limit />
<el-input class="!w-[215px]" v-model="item.text" :placeholder="t('titleContent')" maxlength="5" show-word-limit />
</el-form-item>
<el-form-item :label="t('navLinkOne')">
<diy-link v-model="item.link"/>
@ -103,16 +107,18 @@ import { ref, reactive, onMounted, nextTick } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import type { FormInstance, ElNotification } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { getDiyBottomConfig, setDiyBottomConfig } from '@/app/api/diy'
import Sortable from 'sortablejs'
import { range } from 'lodash-es'
import { useRoute,useRouter } from 'vue-router'
const activeName = ref<string>('navPicture')
const loading = ref<boolean>(false)
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref<string>('navPicture')
const loading = ref<boolean>(false)
route.query.key = route.query.key || '';
//

View File

@ -1,167 +1,169 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<!--财务流水-->
<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-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.pay ? accountStat.pay.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalPay') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.refund ? accountStat.refund.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalRefund') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.transfer ? accountStat.transfer.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalTransfer') }}</span>
</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="siteAccountLogTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('type')" class="items-center" prop="type">
<el-select v-model="siteAccountLogTable.searchParam.type" class="m-2" :placeholder="t('accountType')">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none !px-[35px]" shadow="never">
<el-row class="flex">
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.pay ? accountStat.pay.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalPay') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.refund ? accountStat.refund.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalRefund') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.transfer ? accountStat.transfer.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalTransfer') }}</span>
</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="siteAccountLogTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('type')" class="items-center" prop="type">
<el-select v-model="siteAccountLogTable.searchParam.type" class="m-2" :placeholder="t('accountType')">
<el-option :label="t('all')" value="" />
<el-option v-for="(item, index) in accountType" :key="index" :label="item" :value="index" />
</el-select>
</el-form-item>
<el-form-item :label="t('tradeNo')" prop="trade_no">
<el-input v-model="siteAccountLogTable.searchParam.trade_no" :placeholder="t('tradeNoPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="siteAccountLogTable.searchParam.create_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" />
</el-form-item>
<el-option v-for="(item, index) in accountType" :key="index" :label="item" :value="index" />
</el-select>
</el-form-item>
<el-form-item :label="t('tradeNo')" prop="trade_no">
<el-input v-model="siteAccountLogTable.searchParam.trade_no" :placeholder="t('tradeNoPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="siteAccountLogTable.searchParam.create_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadSiteAccountLogList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<el-form-item>
<el-button type="primary" @click="loadSiteAccountLogList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="siteAccountLogTable.data" size="large" v-loading="siteAccountLogTable.loading">
<template #empty>
<span>{{ !siteAccountLogTable.loading ? t('emptyData') : '' }}</span>
</template>
<div class="mt-[10px]">
<el-table :data="siteAccountLogTable.data" size="large" v-loading="siteAccountLogTable.loading">
<template #empty>
<span>{{ !siteAccountLogTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="trade_no" :label="t('tradeNo')" min-width="120" />
<el-table-column prop="type_name" :label="t('type')" min-width="120" />
<el-table-column prop="money" :label="t('money')" min-width="120" align="right" />
<el-table-column :label="t('createTime')" min-width="150" align="center">
<template #default="{ row }">
{{ row.create_time || '' }}
</template>
</el-table-column>
<el-table-column prop="trade_no" :label="t('tradeNo')" min-width="120" />
<el-table-column prop="type_name" :label="t('type')" min-width="120" />
<el-table-column prop="money" :label="t('money')" min-width="120" align="right" />
<el-table-column :label="t('createTime')" min-width="150" align="center">
<template #default="{ row }">
{{ row.create_time || '' }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
</template>
</el-table-column>
</el-table>
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
</template>
</el-table-column>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="siteAccountLogTable.page"
v-model:page-size="siteAccountLogTable.limit" layout="total, sizes, prev, pager, next, jumper"
:total="siteAccountLogTable.total" @size-change="loadSiteAccountLogList()"
@current-change="loadSiteAccountLogList" />
</div>
</div>
</el-card>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="siteAccountLogTable.page"
v-model:page-size="siteAccountLogTable.limit" layout="total, sizes, prev, pager, next, jumper"
:total="siteAccountLogTable.total" @size-change="loadSiteAccountLogList()"
@current-change="loadSiteAccountLogList" />
</div>
</div>
</el-card>
<el-dialog v-model="showDialog" :title="t('accountDetail')" width="550px" :destroy-on-close="true">
<el-form :model="formData" label-width="110px" ref="formRef" class="page-form">
<el-dialog v-model="showDialog" :title="t('accountDetail')" width="550px" :destroy-on-close="true">
<el-form :model="formData" label-width="110px" ref="formRef" class="page-form">
<!-- <el-form-item :label="t('tradeNo')">-->
<!-- <div class="input-width"> {{ formData.trade_no }} </div>-->
<!-- </el-form-item>-->
<el-form-item :label="t('type')">
<div class="input-width"> {{ formData.type_name }} </div>
</el-form-item>
<el-form-item :label="t('money')">
<div class="input-width"> {{ formData.money }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.create_time }} </div>
</el-form-item>
<div v-if="formData.type == 'transfer'">
<el-form-item :label="t('transferNo')">
<div class="input-width"> {{ formData.pay_info.transfer_no }} </div>
</el-form-item>
<el-form-item :label="t('transferTime')">
<div class="input-width"> {{ formData.pay_info.transfer_time }} </div>
</el-form-item>
<el-form-item :label="t('transferType')">
<div class="input-width"> {{ formData.pay_info.transfer_type }} </div>
</el-form-item>
<el-form-item :label="t('transferMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('transferRemark')">
<div class="input-width"> {{ formData.pay_info.remark }} </div>
</el-form-item>
</div>
<div v-if="formData.type == 'refund'">
<el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item>
<el-form-item :label="t('refundMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('failReason')">
<div class="input-width"> {{ formData.pay_info.fail_reason }} </div>
</el-form-item>
</div>
<div v-if="formData.type == 'pay'">
<el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item>
<el-form-item :label="t('money')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('body')">
<div class="input-width"> {{ formData.pay_info.body }} </div>
</el-form-item>
</div>
<el-form-item :label="t('type')">
<div class="input-width"> {{ formData.type_name }} </div>
</el-form-item>
<el-form-item :label="t('money')">
<div class="input-width"> {{ formData.money }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.create_time }} </div>
</el-form-item>
<div v-if="formData.type == 'transfer'">
<el-form-item :label="t('transferNo')">
<div class="input-width"> {{ formData.pay_info.transfer_no }} </div>
</el-form-item>
<el-form-item :label="t('transferTime')">
<div class="input-width"> {{ formData.pay_info.transfer_time }} </div>
</el-form-item>
<el-form-item :label="t('transferType')">
<div class="input-width"> {{ formData.pay_info.transfer_type }} </div>
</el-form-item>
<el-form-item :label="t('transferMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('transferRemark')">
<div class="input-width"> {{ formData.pay_info.remark }} </div>
</el-form-item>
</div>
<div v-if="formData.type == 'refund'">
<el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item>
<el-form-item :label="t('refundMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('failReason')">
<div class="input-width"> {{ formData.pay_info.fail_reason }} </div>
</el-form-item>
</div>
<div v-if="formData.type == 'pay'">
<el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item>
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item>
<el-form-item :label="t('money')">
<div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item>
<el-form-item :label="t('body')">
<div class="input-width"> {{ formData.pay_info.body }} </div>
</el-form-item>
</div>
</el-form>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="showDialog = false">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="showDialog = false">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
@ -256,8 +258,8 @@ const detailEvent = (info:any) => {
interface AccountStat{
pay: number,
refund: number,
transfer: number
refund: number,
transfer: number
}
const accountStat = ref<AccountStat>({

View File

@ -1,10 +1,13 @@
<template>
<!--会员提现-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-card class="box-card !border-none !px-[35px]" shadow="never">
<el-row class="flex">
<el-col :span="12">
<div class="statistic-card">
@ -141,7 +144,6 @@
@size-change="loadOrderList()" @current-change="loadOrderList" />
</div>
</div>
</el-card>
<!-- 详情 -->
@ -169,6 +171,7 @@
<div class="input-width"> {{ cashOutInfo.status_name }} </div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="cashOutShowDialog = false">{{ t('confirm') }}</el-button>
@ -356,7 +359,6 @@ const transferFn = (data:any) => {
* 详情
* @param data
*/
const cashOutShowDialog = ref(false)
const cashOutInfo = ref({
nickname: '',
@ -394,7 +396,6 @@ const cashOutAuditFn = (data:any) => {
/**
* 拒绝审核
* @param data
*/
const confirm = () => {
auditShowDialog.value = false

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