This commit is contained in:
wangchen147 2024-01-11 15:57:27 +08:00
parent 045f63e74d
commit 8916a9662d
910 changed files with 10307 additions and 8733 deletions

View File

@ -1,6 +1,5 @@
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
export {} export {}
declare global { declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElNotification: typeof import('element-plus/es')['ElNotification'] const ElNotification: typeof import('element-plus/es')['ElNotification']
} }

View File

@ -5,7 +5,7 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build && node publish.cjs",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
@ -55,4 +55,4 @@
"vite": "4.1.0", "vite": "4.1.0",
"vue-tsc": "1.0.24" "vue-tsc": "1.0.24"
} }
} }

39
admin/publish.cjs Normal file
View File

@ -0,0 +1,39 @@
const fs = require('fs')
const publish = () => {
const src = './dist'
const dest = '../niucloud/public/admin'
solve()
// 目标目录不存在停止复制
try {
const dir = fs.readdirSync(dest)
} catch (e) {
return
}
// 删除目标目录下文件
fs.rm(dest, { recursive: true }, err => {
if(err) {
console.log(err)
return
}
fs.cp(src, dest, { recursive: true }, (err) => {
if (err) {
console.error(err)
}
})
})
}
const solve = () => {
const fn = './dist/index.html'
const fc = fs.readFileSync(fn, 'utf-8')
let text = new String(fc)
text = text.replaceAll('./assets/', '/admin/assets/')
fs.writeFileSync(fn, text, 'utf8')
}
publish()

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
* *
* @returns * @returns
*/ */
export function getUserInfo(type: string) { export function getUserInfo() {
return request.get(`auth/get`) return request.get(`auth/get`)
} }

View File

@ -119,8 +119,8 @@ export function deleteSiteGroup(group_id: number) {
* @param params * @param params
* @returns * @returns
*/ */
export function getSiteGroupAll(params: Record<string, any>) { export function getSiteGroupAll(params: Record<string, any> = {}) {
return request.get(`site/group/all`, params) return request.get(`site/group/all`)
} }
/***************************************************** 当前站点用户 *************************************************/ /***************************************************** 当前站点用户 *************************************************/

View File

@ -675,3 +675,20 @@ export function getAddonList() {
export function getWapIndexList(params: Record<string, any>) { export function getWapIndexList(params: Record<string, any>) {
return request.get('sys/config/wap_index', { params }) return request.get('sys/config/wap_index', { params })
} }
/**
* key
* @returns
*/
export function getDeveloperToken() {
return request.get('sys/config/developer_token')
}
/**
* key
* @param params
* @returns
*/
export function setDeveloperToken(params: Record<string, any>) {
return request.put(`sys/config/developer_token`, params, { showSuccessMessage: true })
}

View File

@ -175,3 +175,10 @@ export function getGeneratorTableColumn(params: any) {
export function generatorCheckFile(params: Record<string, any>) { export function generatorCheckFile(params: Record<string, any>) {
return request.get(`generator/check_file`, {params}) return request.get(`generator/check_file`, {params})
} }
/**
*
*/
export function getGeneratorModelTableColumn(params: any) {
return request.get(`generator/model_table_column`, {params})
}

View File

@ -265,4 +265,7 @@ defineExpose({
.table-head-bg { .table-head-bg {
background-color: var(--el-table-header-bg-color); background-color: var(--el-table-header-bg-color);
} }
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style> </style>

View File

@ -19,7 +19,7 @@
<div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index"> <div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index">
<div class="font-bold text-lg">{{ item.version_no }}</div> <div class="font-bold text-lg">{{ item.version_no }}</div>
<div class="mt-[5px]">{{ item.release_time }}</div> <div class="mt-[5px]">{{ item.release_time }}</div>
<div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5]" v-if="item.upgrade_log" v-html="item.upgrade_log"></div> <div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5] whitespace-pre" v-if="item.upgrade_log" v-html="item.upgrade_log"></div>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
@ -233,7 +233,7 @@ const open = (addonKey: string = '') => {
} }
getUpgradeContent(addonKey).then(({ data }) => { getUpgradeContent(addonKey).then(({ data }) => {
upgradeContent.value = data upgradeContent.value = data
if (data.version == data.last_version) { if (!data.version_list.length) {
ElMessage({ message: '已经是最新版本了', type: 'error' }) ElMessage({ message: '已经是最新版本了', type: 'error' })
return return
} }
@ -316,4 +316,7 @@ defineExpose({
.table-head-bg { .table-head-bg {
background-color: var(--el-table-header-bg-color); background-color: var(--el-table-header-bg-color);
} }
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style> </style>

View File

@ -1,25 +1,28 @@
{ {
"menuName": "菜单名称", "menuName": "菜单名称",
"menuType": "类型", "menuType": "类型",
"authId": "权限标识", "authId": "api路径",
"menuTypeDir": "目录", "menuTypeDir": "目录",
"menuTypeMenu": "菜单", "menuTypeMenu": "菜单",
"menuTypeButton": "按钮", "menuTypeButton": "按钮",
"menuDeleteTips": "确定要删除该菜单吗", "menuDeleteTips": "删除菜单会删除当前菜单以及该菜单下所有子菜单,是否确认删除",
"addMenu": "添加菜单", "addMenu": "添加菜单",
"updateMenu": "编辑菜单", "updateMenu": "编辑菜单",
"routePath": "路由路径", "routePath": "路由路径",
"viewPath": "组件路径", "viewPath": "组件路径",
"addon":"选择应用",
"parentMenu": "父级菜单", "parentMenu": "父级菜单",
"menuIcon": "菜单图标", "menuIcon": "菜单图标",
"sort":"权重", "sort":"权重",
"menuKey":"菜单标识", "menuKey":"权限标识",
"menuNamePlaceholder": "请输入菜单名称", "menuNamePlaceholder": "请输入菜单名称",
"menuKeyPlaceholder": "请输入菜单标识", "menuKeyPlaceholder": "请输入权限标识",
"menuKeyValidata":"菜单标识只能使用字母数字下划线并且开头不能为数字", "menuKeyValidata":"菜单标识只能使用字母数字下划线并且开头不能为数字",
"routePathPlaceholder": "请输入路由路径", "routePathPlaceholder": "请输入路由路径",
"viewPathPlaceholder": "请输入组件路径", "viewPathPlaceholder": "请输入组件路径",
"authIdPlaceholder": "请输入权限标识", "authIdPlaceholder": "请输入api路径",
"selectIconPlaceholder": "请选择菜单图标", "selectIconPlaceholder": "请选择菜单图标",
"topLevel": "顶级" "topLevel": "顶级",
} "menuShortName":"菜单短标题",
"menuShortNamePlaceholder":"请输入菜单短标题"
}

View File

@ -21,5 +21,10 @@
"viewPathPlaceholder": "请输入组件路径", "viewPathPlaceholder": "请输入组件路径",
"authIdPlaceholder": "请输入权限标识", "authIdPlaceholder": "请输入权限标识",
"selectIconPlaceholder": "请选择菜单图标", "selectIconPlaceholder": "请选择菜单图标",
"topLevel": "顶级" "topLevel": "顶级",
"menuShortName":"菜单短标题",
"menuShortNamePlaceholder":"请输入菜单短标题",
"addon":"选择应用",
"system":"系统菜单",
"application":"应用菜单"
} }

View File

@ -0,0 +1,5 @@
{
"developerTokenEdit":"开发者KEY设置",
"tokenPlaceholder":"请输入开发者令牌",
"tokenTips": "开发者KEY可以在已安装的框架中设置。框架安装并配置好开发者KEY后开发者自己开发的应用和插件会像普通授权插件一样可以安装使用特别是当开发者发布自己开发的插件或应用时尚在未发布状态时开发者也可以对其进行安装测试"
}

View File

@ -18,7 +18,9 @@
"reset": "重置", "reset": "重置",
"search": "搜索", "search": "搜索",
"foldText":"展开/折叠", "foldText":"展开/折叠",
"mainApp": "套餐主应用", "mainApp": "套餐内含应用",
"mainAppPlaceholder": "请选择套餐主应用", "mainAppPlaceholder": "请选择套餐内包含的应用",
"containAddon": "套餐内含插件" "containAddon": "套餐内含插件",
"appListEmpty": "没有可选择的应用",
"addonListEmpty": "没有可选择的插件"
} }

View File

@ -131,6 +131,13 @@
"setUp":"设置", "setUp":"设置",
"dictType":"数据字典", "dictType":"数据字典",
"dictTypePlaceholder":"请选择数据字典", "dictTypePlaceholder":"请选择数据字典",
"dictTypePlaceholder1":"部分字段未选择数据字典" "dictTypePlaceholder1":"部分字段未选择数据字典",
"remotePullDown": "远程下拉",
"remotePullDownValue":"远程下拉value字段",
"remotePullDownValuePlaceholder":"请选择远程下拉value字段",
"remotePullDownLabel":"远程下拉标题字段",
"remotePullDownLabelPlaceholder":"请选择远程下拉label字段",
"selectType":"下拉类型"
} }

View File

@ -98,9 +98,9 @@
<el-card class="box-card !border-none " shadow="never" v-if="!loading"> <el-card class="box-card !border-none " shadow="never" v-if="!loading">
<div class="text-[20px] mb-[20px]">历史版本</div> <div class="text-[20px] mb-[20px]">历史版本</div>
<el-timeline> <el-timeline>
<el-timeline-item :timestamp="item.release_time + ' 版本:' + item.version_no" v-for="item in frameworkVersionList" type="primary" :hollow="true" placement="top"> <el-timeline-item :timestamp="item['release_time'] + ' 版本:' + item['version_no']" v-for="(item,index) in frameworkVersionList" type="primary" :hollow="true" placement="top" :key="index">
<div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap" v-if="item.upgrade_log"> <div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap whitespace-pre" v-if="item['upgrade_log']">
<div v-html="item.upgrade_log"></div> <div v-html="item['upgrade_log']"></div>
</div> </div>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
@ -117,16 +117,13 @@ import { t } from '@/lang'
import { getVersions } from '@/app/api/auth' import { getVersions } from '@/app/api/auth'
import { getAuthinfo, setAuthinfo, getFrameworkVersionList } from '@/app/api/module' import { getAuthinfo, setAuthinfo, getFrameworkVersionList } from '@/app/api/module'
import { ElMessageBox, FormInstance, FormRules } from 'element-plus' import { ElMessageBox, FormInstance, FormRules } from 'element-plus'
import { useRoute } from 'vue-router'
import Upgrade from '@/app/components/upgrade/index.vue' import Upgrade from '@/app/components/upgrade/index.vue'
import CloudBuild from '@/app/components/cloud-build/index.vue' import CloudBuild from '@/app/components/cloud-build/index.vue'
const route = useRoute() const upgradeRef = ref<any>(null)
const pageName = route.meta.title const cloudBuildRef = ref<any>(null)
const upgradeRef = ref(null) const getAuthCodeDialog: Record<string, any> | null = ref(null)
const cloudBuildRef = ref(null)
const getAuthCodeDialog = ref(null)
const authCodeApproveDialog = ref(false) const authCodeApproveDialog = ref(false)
const isCheck = ref(false) const isCheck = ref(false)
const frameworkVersionList = ref([]) const frameworkVersionList = ref([])
@ -138,77 +135,87 @@ const getFrameworkVersionListFn = () => {
} }
getFrameworkVersionListFn() getFrameworkVersionListFn()
const newVersion = computed(() => { const newVersion:any = computed(() => {
return frameworkVersionList.value.length ? frameworkVersionList.value[0] : null return frameworkVersionList.value.length ? frameworkVersionList.value[0] : null
}) })
const hideAuthCode = (res) => { const hideAuthCode = (res:any) => {
const authCode = JSON.parse(JSON.stringify(res)) const authCode = JSON.parse(JSON.stringify(res))
const data = authCode.slice(0, authCode.length / 2) + authCode.slice(authCode.length / 2, authCode.length - 1).replace(/./g, '*') const data = authCode.slice(0, authCode.length / 2) + authCode.slice(authCode.length / 2, authCode.length - 1).replace(/./g, '*')
return data return data
} }
const authCodeApproveFn = () => { const authCodeApproveFn = () => {
authCodeApproveDialog.value = true authCodeApproveDialog.value = true
} }
const authinfo = ref('') interface AuthInfo {
company_name: string,
site_address: string,
auth_code: string
}
const authinfo = ref<AuthInfo>({
company_name: '',
site_address: '',
auth_code: ''
})
const loading = ref(true) const loading = ref(true)
const saveLoading = ref(false) const saveLoading = ref(false)
const checkAppMange = () => { const checkAppMange = () => {
getAuthinfo() getAuthinfo()
.then((res) => { .then((res) => {
loading.value = false loading.value = false
if (res.data.data && res.data.data.length != 0) { if (res.data.data && res.data.data.length != 0) {
authinfo.value = res.data.data authinfo.value = res.data.data
authCodeApproveDialog.value = false authCodeApproveDialog.value = false
} }
}) })
.catch(() => { .catch(() => {
loading.value = false loading.value = false
authCodeApproveDialog.value = false authCodeApproveDialog.value = false
}) })
} }
checkAppMange() checkAppMange()
const formData = reactive<Record<string, string>>({ const formData = reactive<Record<string, string>>({
auth_code: '', auth_code: '',
auth_secret: '' auth_secret: ''
}) })
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
// //
const formRules = reactive<FormRules>({ const formRules = reactive<FormRules>({
auth_code: [ auth_code: [
{ required: true, message: t('authCodePlaceholder'), trigger: 'blur' } { required: true, message: t('authCodePlaceholder'), trigger: 'blur' }
], ],
auth_secret: [ auth_secret: [
{ required: true, message: t('authSecretPlaceholder'), trigger: 'blur' } { required: true, message: t('authSecretPlaceholder'), trigger: 'blur' }
] ]
}) })
const save = async (formEl: FormInstance | undefined) => { const save = async (formEl: FormInstance | undefined) => {
if (saveLoading.value || !formEl) return if (saveLoading.value || !formEl) return
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
saveLoading.value = true saveLoading.value = true
setAuthinfo(formData) setAuthinfo(formData)
.then(() => { .then(() => {
saveLoading.value = false saveLoading.value = false
checkAppMange() checkAppMange()
}) })
.catch(() => { .catch(() => {
saveLoading.value = false saveLoading.value = false
authCodeApproveDialog.value = false authCodeApproveDialog.value = false
}) })
} }
}) })
} }
const market = () => { const market = () => {
window.open('https://www.niucloud.com/app') window.open('https://www.niucloud.com/app')
} }
const versions = ref('') const versions = ref('')

View File

@ -1,111 +1,83 @@
<template> <template>
<div class="main-container w-full bg-white" v-loading="loading"> <div class="main-container w-full bg-white" v-loading="loading">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-[20px]">应用管理</span> <span class="text-[20px]">应用管理</span>
<el-form :inline="true" :model="appList.search" ref="searchFormRef"> </div>
<el-form-item :label="t('appName')" prop="title"> <div class="flex flex-wrap plug-list pb-10 plug-large" v-if="appList.length">
<el-input v-model="appList.search.title" :placeholder="t('appNamePlaceholder')" /> <div v-for="(item, index) in appList" :key="index + 'b'">
</el-form-item> <div
<el-form-item> class="relative app-item cursor-pointer px-4 mr-4 mt-[20px] bg-[#f7f7f7] border-[1px] hover:border-primary">
<el-button type="primary" @click="getAppList()">{{ t('search') }}</el-button> <div @click="toLink(item.key)" class="flex py-5 items-center">
</el-form-item> <div class="flex justify-center items-center">
</el-form> <el-image class="w-[40px] h-[40px]" :src="img(item.icon)" fit="contain">
</div> <template #error>
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="appList.list.length"> <div class="image-slot">
<div v-for="(item, index) in appList.list" :key="index + 'b'"> <img class="w-[50px] h-[50px]"
<div src="@/app/assets/images/index/app_default.png" />
class="relative app-item cursor-pointer px-4 mr-4 mt-[20px] bg-[#f7f7f7] border-[1px] hover:border-primary"> </div>
<div @click="toLink(item.key)" class="flex py-5 items-center"> </template>
<div class="flex justify-center items-center"> </el-image>
<el-image class="w-[40px] h-[40px]" :src="img(item.icon)" fit="contain"> </div>
<template #error> <div class="flex flex-col justify-between text-left w-[190px]">
<div class="image-slot"> <p class="app-text w-[190px] text-[17px] text-[#222] pl-3">{{ item.title }}</p>
<img class="w-[50px] h-[50px]" </div>
src="@/app/assets/images/index/app_default.png" /> </div>
</div> </div>
</template> </div>
</el-image> </div>
</div> <div class="empty flex items-center justify-center" v-if="!loading && !appList.length">
<div class="flex flex-col justify-between text-left w-[190px]"> <el-empty :description="t('emptyAppData')" />
<p class="app-text w-[190px] text-[17px] text-[#222] pl-3">{{ item.title }}</p> </div>
</div> </el-card>
</div> </div>
</div>
</div>
</div>
<div class="empty flex items-center justify-center" v-if="!loading && !appList.list.length">
<el-empty :description="t('emptyAppData')" />
</div>
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive } from 'vue' import { ref } from 'vue'
import { getSiteAddons } from '@/app/api/site' import { getSiteAddons } from '@/app/api/site'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { findFirstValidRoute } from '@/router/routers'
import useUserStore from '@/stores/modules/user' import useUserStore from '@/stores/modules/user'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { t } from '@/lang' import { t } from '@/lang'
const userStore = useUserStore() const addonIndexRoute = useUserStore().addonIndexRoute
const router = useRouter() const router = useRouter()
const appList = reactive({ const appList = ref<Record<string, any>[]>([])
list: [],
search: {
title: ''
}
})
const loading = ref(true) const loading = ref(true)
const getAppList = async () => { const getAppList = async () => {
const res = await getSiteAddons({ title: appList.search.title }) const res = await getSiteAddons()
appList.list = res.data appList.value = res.data
loading.value = false loading.value = false
} }
getAppList()
const appLink = ref({})
const getAppLink = () => {
userStore.routers.forEach((item, index) => {
if (item.meta.addon != '') {
if (item.children && item.children.length) {
appLink.value[item.meta.addon] = findFirstValidRoute(item.children)
} else {
appLink.value[item.meta.addon] = item.name
}
}
})
getAppList()
}
getAppLink()
const toLink = (addon: string) => { const toLink = (addon: string) => {
appLink.value[addon] && router.push({ name: appLink.value[addon] }) addonIndexRoute[addon] && router.push({ name: addonIndexRoute[addon] })
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.main-container, .main-container,
.empty { .empty {
min-height: calc(100vh - 84px); min-height: calc(100vh - 84px);
} }
.app-text { .app-text {
overflow: hidden; overflow: hidden;
/* 超出部分隐藏 */ /* 超出部分隐藏 */
white-space: nowrap; white-space: nowrap;
/* 禁止文本换行 */ /* 禁止文本换行 */
text-overflow: ellipsis; text-overflow: ellipsis;
/* 显示省略号 */ /* 显示省略号 */
} }
.app-item:hover .with-ite { .app-item:hover .with-ite {
display: block; display: block;
} }
.el-form-item { .el-form-item {
margin-bottom: 0px !important; margin-bottom: 0px !important;
} }
</style> </style>

View File

@ -4,7 +4,7 @@
<div class="flex justify-between items-center h-[32px] mb-4"> <div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[26px] text-[#222] font-600">{{ t('localAppText') }}</span> <span class="text-[26px] text-[#222] font-600">{{ t('localAppText') }}</span>
<div class="w-[247px]"> <div class="w-[247px]">
<el-input :placeholder="t('search')" v-model="search_name" @keyup.enter="query"> <el-input :placeholder="t('search')" v-model="searchName" @keyup.enter="query">
<template #suffix> <template #suffix>
<el-icon class="el-input__icon cursor-pointer" size="14px" @click="query"> <el-icon class="el-input__icon cursor-pointer" size="14px" @click="query">
<search /> <search />
@ -15,18 +15,18 @@
</div> </div>
<div class="flex mt-[24px]"> <div class="flex mt-[24px]">
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'installed' }" <div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'installed' }"
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]" class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
@click="activeName = 'installed'"> @click="activeName = 'installed'">
{{ t('installLabel') }} {{ t('installLabel') }}
</div> </div>
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'uninstalled' }" <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]" 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'"> @click="activeName = 'uninstalled'">
{{ t('uninstalledLabel') }} {{ t('uninstalledLabel') }}
</div> </div>
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'all' }" <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]" 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'"> @click="activeName = 'all'">
{{ t('buyLabel') }} {{ t('buyLabel') }}
</div> </div>
</div> </div>
@ -35,8 +35,8 @@
<el-table-column :label="t('appName')" align="left" width="320"> <el-table-column :label="t('appName')" align="left" width="320">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center" <div class="flex items-center"
:class="{ 'cursor-pointer': row.type == 'app' && Object.keys(row.install_info).length }" :class="{ 'cursor-pointer': row.type == 'app' && Object.keys(row.install_info).length }"
@click="itemPath(row)"> @click="itemPath(row)">
<el-image class="w-[54px] h-[54px]" :src="row.icon" fit="contain"> <el-image class="w-[54px] h-[54px]" :src="row.icon" fit="contain">
<template #error> <template #error>
<img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt=""> <img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt="">
@ -73,7 +73,7 @@
<el-table-column :label="t('type')" align="left" min-width="100"> <el-table-column :label="t('type')" align="left" min-width="100">
<template #default="{ row }"> <template #default="{ row }">
<span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon') <span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon')
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="" :label="t('author')" align="left" min-width="100"> <el-table-column prop="" :label="t('author')" align="left" min-width="100">
@ -84,21 +84,21 @@
<el-table-column :label="t('operation')" fixed="right" align="right" width="150"> <el-table-column :label="t('operation')" fixed="right" align="right" width="150">
<template #default="{ row }"> <template #default="{ row }">
<el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{ <el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{
t('detail') }}</el-button> t('detail') }}</el-button>
<el-button class="!text-[13px]" v-if="row.install_info && Object.keys(row.install_info)?.length" <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> 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" <el-button class="!text-[13px]" v-else-if="row.is_download && row.install_info <= 0"
type="primary" link @click="installAddonFn(row.key)">{{ t('install') type="primary" link @click="installAddonFn(row.key)">{{ t('install')
}}</el-button> }}</el-button>
<el-button class="!text-[13px]" v-else :loading="downloading == row.key" <el-button class="!text-[13px]" v-else :loading="downloading == row.key"
:disabled="downloading != ''" type="primary" link @click.stop="downEvent(row)">{{ :disabled="downloading != ''" type="primary" link @click.stop="downEvent(row)">{{
t('down') }}</el-button> t('down') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-empty class="mx-auto overview-empty" <el-empty class="mx-auto overview-empty"
v-if="!localList.installed.length && !loading && activeName == 'installed'"> v-if="!localList.installed.length && !loading && activeName == 'installed'">
<template #image> <template #image>
<div class="w-[230px] mx-auto"> <div class="w-[230px] mx-auto">
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""> <img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
@ -109,7 +109,7 @@
</template> </template>
</el-empty> </el-empty>
<el-empty class="mx-auto overview-empty" <el-empty class="mx-auto overview-empty"
v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'"> v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
<template #image> <template #image>
<div class="w-[230px] mx-auto"> <div class="w-[230px] mx-auto">
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""> <img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
@ -124,20 +124,20 @@
</template> </template>
</el-empty> </el-empty>
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'" <div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'"
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6"> class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权请先绑定授权</div> <div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权请先绑定授权</div>
<div class="flex flex-1 flex-wrap justify-center relative"> <div class="flex flex-1 flex-wrap justify-center relative">
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" <el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
@click="authCodeApproveFn">授权码认证</el-button> @click="authCodeApproveFn">授权码认证</el-button>
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" <el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click"
class="mt-[8px]"> class="mt-[8px]">
<div class="px-[18px] py-[8px]"> <div class="px-[18px] py-[8px]">
<p class="leading-[32px] text-[14px]"> <p class="leading-[32px] text-[14px]">
您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务</p> 您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务</p>
<div class="flex justify-end mt-[36px]"> <div class="flex justify-end mt-[36px]">
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button> <el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
<el-button class="w-[100px] !h-[48px]" plain <el-button class="w-[100px] !h-[48px]" plain
@click="getAuthCodeDialog.hide()">关闭</el-button> @click="getAuthCodeDialog.hide()">关闭</el-button>
</div> </div>
</div> </div>
<template #reference> <template #reference>
@ -154,13 +154,13 @@
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<el-form-item prop="auth_code"> <el-form-item prop="auth_code">
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')" <el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')"
class="input-width" clearable size="large" /> class="input-width" clearable size="large" />
</el-form-item> </el-form-item>
<div class="mt-[20px]"> <div class="mt-[20px]">
<el-form-item prop="auth_secret"> <el-form-item prop="auth_secret">
<el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" <el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')"
class="input-width" size="large" /> class="input-width" size="large" />
</el-form-item> </el-form-item>
</div> </div>
@ -168,7 +168,7 @@
<div class="mt-[20px]"> <div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" <el-button type="primary" class="w-full" size="large" :loading="saveLoading"
@click="save(formRef)">{{ t('confirm') }}</el-button> @click="save(formRef)">{{ t('confirm') }}</el-button>
</div> </div>
<div class="mt-[10px] text-right"> <div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button> <el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
@ -201,7 +201,7 @@
<!-- 安装弹窗 --> <!-- 安装弹窗 -->
<el-dialog v-model="installShowDialog" :title="t('addonInstall')" width="850px" :close-on-click-modal="false" <el-dialog v-model="installShowDialog" :title="t('addonInstall')" width="850px" :close-on-click-modal="false"
:close-on-press-escape="false" :before-close="installShowDialogClose"> :close-on-press-escape="false" :before-close="installShowDialogClose">
<el-steps :space="200" :active="installStep" finish-status="success" align-center> <el-steps :space="200" :active="installStep" finish-status="success" align-center>
<el-step :title="t('envCheck')" class="flex-1" /> <el-step :title="t('envCheck')" class="flex-1" />
<el-step :title="t('installProgress')" class="flex-1" /> <el-step :title="t('installProgress')" class="flex-1" />
@ -225,7 +225,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in installCheckResult.dir.is_readable"> v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -242,7 +242,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in installCheckResult.dir.is_write"> v-for="(item, index) in installCheckResult.dir.is_write" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -265,13 +265,13 @@
<div class="flex justify-end"> <div class="flex justify-end">
<el-tooltip effect="dark" :content="t('installTips')" placement="top"> <el-tooltip effect="dark" :content="t('installTips')" placement="top">
<el-button type="default" :disabled="!installCheckResult.is_pass || cloudInstalling" <el-button type="default" :disabled="!installCheckResult.is_pass || cloudInstalling"
:loading="localInstalling" @click="handleInstall">{{ :loading="localInstalling" @click="handleInstall">{{
t('localInstall') t('localInstall')
}}</el-button> }}</el-button>
</el-tooltip> </el-tooltip>
<el-tooltip effect="dark" :content="t('cloudInstallTips')" placement="top"> <el-tooltip effect="dark" :content="t('cloudInstallTips')" placement="top">
<el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling" <el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling"
:loading="cloudInstalling" @click="handleCloudInstall">{{ :loading="cloudInstalling" @click="handleCloudInstall">{{
t('cloudInstall') t('cloudInstall')
}}</el-button> }}</el-button>
</el-tooltip> </el-tooltip>
@ -279,19 +279,19 @@
</div> </div>
<div v-show="installStep == 2" class="h-[50vh] mt-[20px]"> <div v-show="installStep == 2" class="h-[50vh] mt-[20px]">
<terminal name="my-terminal" :context="currAddon" :init-log="null" :show-header="false" <terminal name="my-terminal" :context="currAddon" :init-log="null" :show-header="false"
:show-log-time="true" /> :show-log-time="true" />
</div> </div>
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col"> <div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result> <el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
<!-- 提示信息 --> <!-- 提示信息 -->
<div v-for="item in installAfterTips" class="mb-[10px]"> <div v-for="(item, index) in installAfterTips" class="mb-[10px]" :key="index">
<el-alert :title="item" type="error" :closable="false" /> <el-alert :title="item" type="error" :closable="false" />
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog v-model="uninstallShowDialog" :title="t('addonUninstall')" width="850px" <el-dialog v-model="uninstallShowDialog" :title="t('addonUninstall')" width="850px"
:close-on-click-modal="false" :close-on-press-escape="false"> :close-on-click-modal="false" :close-on-press-escape="false">
<el-scrollbar max-height="50vh"> <el-scrollbar max-height="50vh">
<div class="min-h-[150px]"> <div class="min-h-[150px]">
<div class="bg-[#fff] my-3" v-if="uninstallCheckResult.dir"> <div class="bg-[#fff] my-3" v-if="uninstallCheckResult.dir">
@ -309,7 +309,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in uninstallCheckResult.dir.is_readable"> v-for="(item, index) in uninstallCheckResult.dir.is_readable" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -325,7 +325,8 @@
</span> </span>
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in uninstallCheckResult.dir.is_write"> <el-row class="pb-[10px] items pl-[15px]"
v-for="(item, index) in uninstallCheckResult.dir.is_write" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -355,20 +356,22 @@ import { ref, reactive, watch, h } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon' import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon'
import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module' import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
import { ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus' import { ElMessageBox, ElNotification, FormInstance, FormRules, NotificationHandle } from 'element-plus'
import { img } from '@/utils/common' // import { img } from '@/utils/common'
import { Terminal, api as terminalApi } from 'vue-web-terminal' import { Terminal, api as terminalApi } from 'vue-web-terminal'
import { findFirstValidRoute } from '@/router/routers' import { findFirstValidRoute } from '@/router/routers'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import useUserStore from '@/stores/modules/user' import useUserStore from '@/stores/modules/user'
import { AnyObject } from '@/types/global'
const router = useRouter() const router = useRouter()
const activeName = ref('installed') const activeName = ref('installed')
const loading = ref<Boolean>(true) const loading = ref<Boolean>(true)
const downloading = ref('') const downloading = ref('')
const installAfterTips = ref<string[]>([]) const installAfterTips = ref<string[]>([])
const userStore = useUserStore() const userStore: any = useUserStore()
const downEvent = (param: Record<string, any>) => { const downEvent = (param: Record<string, any>) => {
if (downloading.value) return if (downloading.value) return
@ -395,25 +398,29 @@ getAuthinfo().then(res => {
* 本地下载的插件列表 * 本地下载的插件列表
*/ */
// input // input
const search_name = ref('') const searchName = ref('')
// //
const info = ref({ const info:AnyObject = ref<{
installed: never[];
uninstalled: never[];
all: never[];
}>({
installed: [], installed: [],
uninstalled: [], uninstalled: [],
all: [] all: []
}) })
const query = () => { const query = () => {
if (search_name.value == '' || search_name.value == null) { if (searchName.value == '' || searchName.value == null) {
info.value.installed = localList.value.installed info.value.installed = localList.value.installed
info.value.uninstalled = localList.value.uninstalled info.value.uninstalled = localList.value.uninstalled
info.value.all = localList.value.all info.value.all = localList.value.all
return false return false
} }
info.value.installed = localList.value.installed.filter((el: any) => el.title.indexOf(search_name.value) != -1) 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(search_name.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(search_name.value) != -1) info.value.all = localList.value.all.filter((el: any) => el.title.indexOf(searchName.value) != -1)
} }
const localList = ref({ const localList:AnyObject = ref({
installed: [], installed: [],
uninstalled: [], uninstalled: [],
all: [], all: [],
@ -423,7 +430,7 @@ const localList = ref({
const localListFn = () => { const localListFn = () => {
loading.value = true loading.value = true
getAddonLocal({}).then(res => { getAddonLocal({}).then(res => {
const data = res.data.list const data:any = res.data.list
localList.value.error = res.data.error localList.value.error = res.data.error
localList.value.installed = [] localList.value.installed = []
localList.value.uninstalled = [] localList.value.uninstalled = []
@ -438,7 +445,7 @@ const localListFn = () => {
} }
} }
query() query()
userStore.routers.forEach((item, index) => { userStore.routers.forEach((item:AnyObject, index:number) => {
if (item.children && item.children.length) { if (item.children && item.children.length) {
item.name = findFirstValidRoute(item.children) item.name = findFirstValidRoute(item.children)
appLink.value[item.meta.app] = findFirstValidRoute(item.children) appLink.value[item.meta.app] = findFirstValidRoute(item.children)
@ -478,7 +485,7 @@ const installShowDialog = ref(false)
const installStep = ref(1) const installStep = ref(1)
// //
const installCheckResult = ref({}) const installCheckResult = ref<AnyObject>({})
/** /**
* 安装 * 安装
@ -499,7 +506,7 @@ const installAddonFn = (key: string) => {
/** /**
* 获取正在进行的安装任务 * 获取正在进行的安装任务
*/ */
let notificationEl = null let notificationEl: NotificationHandle | null | any = null
const getInstallTask = (first: boolean = true) => { const getInstallTask = (first: boolean = true) => {
getAddonInstalltask().then(res => { getAddonInstalltask().then(res => {
if (res.data) { if (res.data) {
@ -614,7 +621,7 @@ const getCloudInstallLog = () => {
.then(res => { .then(res => {
const data = res.data.data ?? [] const data = res.data.data ?? []
if (data[0] && data[0].length && installShowDialog.value == true) { if (data[0] && data[0].length && installShowDialog.value == true) {
data[0].forEach(item => { data[0].forEach((item: { action: string; code: number; msg: any }) => {
if (!installLog.includes(item.action)) { if (!installLog.includes(item.action)) {
terminalApi.pushMessage('my-terminal', { content: `正在执行:${item.action}` }) terminalApi.pushMessage('my-terminal', { content: `正在执行:${item.action}` })
installLog.push(item.action) installLog.push(item.action)
@ -639,7 +646,7 @@ watch(currAddon, (nval) => {
const uninstallShowDialog = ref(false) const uninstallShowDialog = ref(false)
// //
const uninstallCheckResult = ref({}) const uninstallCheckResult = ref<AnyObject>({})
/** /**
* 卸载 * 卸载
@ -698,7 +705,7 @@ const getAddonDetialFn = (data: AnyObject) => {
// //
const authCodeApproveDialog = ref(false) const authCodeApproveDialog = ref(false)
const authinfo = ref('') const authinfo = ref('')
const getAuthCodeDialog = ref(null) const getAuthCodeDialog: Record<string, any> | null = ref(null)
const saveLoading = ref(false) const saveLoading = ref(false)
const checkAppMange = () => { const checkAppMange = () => {
getAuthinfo() getAuthinfo()

View File

@ -1,6 +1,7 @@
<template> <template>
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true"> <el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
<el-form :model="formData" label-width="90px" 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-form-item :label="t('menuName')" prop="menu_name">
<el-input v-model="formData.menu_name" :placeholder="t('menuNamePlaceholder')" class="input-width" /> <el-input v-model="formData.menu_name" :placeholder="t('menuNamePlaceholder')" class="input-width" />
</el-form-item> </el-form-item>
@ -16,13 +17,21 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="t('parentMenu')" prop="parent_key"> <el-form-item :label="t('addon')" prop="addon" v-show="formData.app_type == 'site'">
<el-select v-model="formData.parent_key" placeholder="Select" class="input-width"> <el-select v-model="formData.addon" placeholder="Select" class="input-width" @change="addonChange">
<el-option :label="t('topLevel')" value="" /> <el-option v-for="(item, index) in addonLst" :label="item.title" :value="item.key" :key="index" />
<select-menu-item :menu="item" v-for="(item, index) in prop.menuTree" :key="index" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('parentMenu')" prop="parent_key">
<el-tree-select class="input-width" v-if="formData.addon != ''" v-model="formData.parent_key"
:props="{ label: 'menu_name', value: 'menu_key' }" :data="addonMenuList" check-strictly
:render-after-expand="false" />
<el-tree-select class="input-width" v-else v-model="formData.parent_key"
:props="{ label: 'menu_name', value: 'menu_key' }" :data="sysMenuList" check-strictly
:render-after-expand="false" />
</el-form-item>
<el-form-item :label="t('routePath')" prop="router_path" v-show="formData.menu_type != 2"> <el-form-item :label="t('routePath')" prop="router_path" v-show="formData.menu_type != 2">
<el-input v-model="formData.router_path" :placeholder="t('routePathPlaceholder')" class="input-width" /> <el-input v-model="formData.router_path" :placeholder="t('routePathPlaceholder')" class="input-width" />
</el-form-item> </el-form-item>
@ -34,7 +43,7 @@
<el-form-item :label="t('authId')" prop="api_url" v-show="formData.menu_type != 0"> <el-form-item :label="t('authId')" prop="api_url" v-show="formData.menu_type != 0">
<el-input v-model="formData.api_url" :placeholder="t('authIdPlaceholder')" class="input-width"> <el-input v-model="formData.api_url" :placeholder="t('authIdPlaceholder')" class="input-width">
<template #append> <template #append>
<el-select class="w-[90px] border-none" v-model="method"> <el-select class="w-[90px] border-none" v-model="formData.methods">
<el-option label="POST" value="post" /> <el-option label="POST" value="post" />
<el-option label="GET" value="get" /> <el-option label="GET" value="get" />
<el-option label="PUT" value="put" /> <el-option label="PUT" value="put" />
@ -64,6 +73,11 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="t('menuShortName')">
<el-input v-model="formData.menu_short_name" :placeholder="t('menuShortNamePlaceholder')"
class="input-width" />
</el-form-item>
<el-form-item :label="t('sort')"> <el-form-item :label="t('sort')">
<el-input-number v-model="formData.sort" :min="0" /> <el-input-number v-model="formData.sort" :min="0" />
</el-form-item> </el-form-item>
@ -72,7 +86,7 @@
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> <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> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -82,13 +96,12 @@
import { ref, reactive, computed } from 'vue' import { ref, reactive, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import selectMenuItem from './select-menu-item.vue' import { addMenu, editMenu, getMenuInfo, getSystemMenu, getAddonMenu } from '@/app/api/sys'
import { addMenu, editMenu, getMenuInfo } from '@/app/api/sys' import { getAddonDevelop } from '@/app/api/tools'
const showDialog = ref(false) const showDialog = ref(false)
const method = ref('post')
const loading = ref(false) const loading = ref(false)
let popTitle: string = ''; let popTitle: string = ''
/** /**
* 表单数据 * 表单数据
@ -102,22 +115,20 @@ const initialFormData = {
api_url: '', api_url: '',
router_path: '', router_path: '',
view_path: '', view_path: '',
methods: '', methods: 'post',
sort: '', sort: '',
status: 1, status: 1,
is_show: 1, is_show: 1,
menu_key: '', menu_key: '',
app_type: '' app_type: '',
addon: '',
menu_short_name: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
const prop = defineProps({ const addonLst = ref<Array<any>>([])
menuTree: { const sysMenuList = ref<Array<any>>([])
type: Array, const addonMenuList = ref<Array<any>>([])
default: () => []
}
})
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const validataMenuKey = (val: string) => { const validataMenuKey = (val: string) => {
@ -143,7 +154,7 @@ const formRules = computed(() => {
trigger: 'blur' trigger: 'blur'
} }
], ],
//return /^([a-zA-Z_$])([a-zA-Z0-9_$])*$/.test(val) // return /^([a-zA-Z_$])([a-zA-Z0-9_$])*$/.test(val)
router_path: [ router_path: [
{ required: formData.menu_type != 2, message: t('routePathPlaceholder'), trigger: 'blur' } { required: formData.menu_type != 2, message: t('routePathPlaceholder'), trigger: 'blur' }
], ],
@ -154,11 +165,40 @@ const formRules = computed(() => {
{ required: formData.menu_type != 2, message: t('selectIconPlaceholder'), trigger: 'blur' } { required: formData.menu_type != 2, message: t('selectIconPlaceholder'), trigger: 'blur' }
], ],
api_url: [ api_url: [
{ required: formData.menu_type == 2, message: t('selectIconPlaceholder'), trigger: 'blur' } { required: formData.menu_type == 2, message: t('authIdPlaceholder'), trigger: 'blur' }
] ]
} }
}) })
//
const getAddonDevelopFn = async () => {
const { data } = await getAddonDevelop({})
addonLst.value = [{ title: '系统', key: '' }]
addonLst.value.push(...data)
}
//
const getSystemMenuFn = async () => {
const { data } = await getSystemMenu()
sysMenuList.value = [{ menu_name: '顶级', menu_key: '' }]
sysMenuList.value.push(...data)
}
//
const getAddonMenuFn = async (key: any) => {
const { data } = await getAddonMenu(key)
addonMenuList.value = data
}
//
const addonChange = async (val: any) => {
formData.parent_key = ''
if (val != '') {
await getAddonMenuFn(val)
formData.parent_key = addonMenuList.value[0].menu_key
}
}
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
/** /**
@ -174,7 +214,7 @@ const confirm = async (formEl: FormInstance | undefined) => {
loading.value = true loading.value = true
const data = formData const data = formData
data.api_url = data.api_url ? `${data.api_url}/${method.value}` : '' data.api_url = data.api_url ? `${data.api_url}/${formData.methods}` : ''
save(data).then(res => { save(data).then(res => {
loading.value = false loading.value = false
@ -182,7 +222,6 @@ const confirm = async (formEl: FormInstance | undefined) => {
emit('complete') emit('complete')
}).catch(() => { }).catch(() => {
loading.value = false loading.value = false
// showDialog.value = false
}) })
} }
}) })
@ -192,17 +231,21 @@ const setFormData = async (row: any = null) => {
loading.value = true loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
popTitle = t('addMenu') popTitle = t('addMenu')
getAddonDevelopFn()
getSystemMenuFn()
if (row.menu_key) { if (row.menu_key) {
popTitle = t('updateMenu') popTitle = t('updateMenu')
const data = await (await getMenuInfo(row.menu_key)).data const data = await (await getMenuInfo(row.app_type, row.menu_key)).data
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key] if (data[key] != undefined) formData[key] = data[key]
}) })
if (formData.addon != '') getAddonMenuFn(formData.addon)
} else { } else {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (row[key] != undefined) formData[key] = row[key] if (row[key] != undefined) formData[key] = row[key]
}) })
} }
loading.value = false loading.value = false
} }

View File

@ -47,7 +47,7 @@ const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
const isOpen = ref(true) const isOpen = ref(true)
let popTitle: string = ''; let popTitle: string = ''
// //
const menus = ref<Record<string, any>[]>([]) const menus = ref<Record<string, any>[]>([])
@ -55,7 +55,6 @@ getSiteMenus().then((res) => {
menus.value = res.data menus.value = res.data
}) })
// //
const selectAll = ref(false) const selectAll = ref(false)
const checkStrictly = ref(false) const checkStrictly = ref(false)
@ -73,28 +72,27 @@ const handleCheckChange = debounce((e) => {
}) })
const menuAction = () => { const menuAction = () => {
if(isOpen.value){ if (isOpen.value) {
collapseAll(menus.value); collapseAll(menus.value)
isOpen.value = false; isOpen.value = false
}else{ } else {
unFoldAll(menus.value); unFoldAll(menus.value)
isOpen.value = true; isOpen.value = true
} }
} }
// //
const unFoldAll = (data:any) => { const unFoldAll = (data:any) => {
Object.keys(data).forEach((key:string|any) => { Object.keys(data).forEach((key:string|any) => {
treeRef.value.store.nodesMap[data[key]['menu_key']].expanded = true; treeRef.value.store.nodesMap[data[key].menu_key].expanded = true
if(data[key].children && data[key].children.length > 0) collapseAll(data[key].children); if (data[key].children && data[key].children.length > 0) collapseAll(data[key].children)
}) })
} }
// //
const collapseAll = (data:any) => { const collapseAll = (data:any) => {
Object.keys(data).forEach((key:string|any) => { Object.keys(data).forEach((key:string|any) => {
treeRef.value.store.nodesMap[data[key]['menu_key']].expanded = false; treeRef.value.store.nodesMap[data[key].menu_key].expanded = false
if(data[key].children && data[key].children.length > 0) collapseAll(data[key].children); if (data[key].children && data[key].children.length > 0) collapseAll(data[key].children)
}) })
} }
/** /**
@ -143,7 +141,7 @@ const confirm = async (formEl: FormInstance | undefined) => {
loading.value = true loading.value = true
const data = Object.assign({}, formData) const data = Object.assign({}, formData)
data.rules = data.rules.concat(treeRef.value.getHalfCheckedKeys()); data.rules = data.rules.concat(treeRef.value.getHalfCheckedKeys())
save(data).then(res => { save(data).then(res => {
loading.value = false loading.value = false
@ -167,42 +165,37 @@ const setFormData = async (row: any = null) => {
popTitle = t('updateRole') popTitle = t('updateRole')
const data = await (await getRoleInfo(row.role_id)).data const data = await (await getRoleInfo(row.role_id)).data
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) { if (data[key] != undefined) {
if(key == 'rules'){ if (key == 'rules') {
var arr = data.rules; const arr = data.rules
var newArr:any = []; const newArr:any = []
Object.keys(data.rules).forEach( (i) => { Object.keys(data.rules).forEach((i) => {
checked(data.rules[i],menus.value,newArr) checked(data.rules[i], menus.value, newArr)
} ) })
formData[key] = newArr; formData[key] = newArr
} else {
}else{
formData[key] = data[key] formData[key] = data[key]
} }
} }
}) })
} }
loading.value = false loading.value = false
} }
function checked (menuKey:string, data:any, newArr:any) {
function checked(menu_key:string,data:any,newArr:any) { Object.keys(data).forEach((key:string) => {
Object.keys(data).forEach( (key:string) =>{ const item = data[key]
let item = data[key] if (item.menu_key == menuKey) {
if(item.menu_key == menu_key){ if (!item.children || item.children.length == 0) {
if(!item.children || item.children.length == 0){
newArr.push(item.menu_key) newArr.push(item.menu_key)
} }
}else{ } else {
if(item.children && item.children.length > 0){ if (item.children && item.children.length > 0) {
checked(menu_key,item.children,newArr) checked(menuKey, item.children, newArr)
} }
} }
} ) })
} }
defineExpose({ defineExpose({

View File

@ -69,15 +69,16 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed, toRaw, watch } from 'vue' import { ref, reactive, computed, toRaw } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { getUserInfo, getAllUserList } from '@/app/api/user' import { getUserInfo, getAllUserList } from '@/app/api/user'
import { addUser, editUser } from '@/app/api/site' import { addUser, editUser } from '@/app/api/site'
import { allRole } from '@/app/api/sys' import { allRole } from '@/app/api/sys'
import { img, deepClone } from '@/utils/common' import { img, deepClone } from '@/utils/common'
import { AnyObject } from '@/types/global'
const userList = ref([]) const userList = ref<AnyObject>([])
const uid = ref<number | string>('') const uid = ref<number | string>('')
const selectUser = (value: any) => { const selectUser = (value: any) => {
@ -165,7 +166,7 @@ const emit = defineEmits(['complete'])
const roles = ref<Record<string, any>>([]) const roles = ref<Record<string, any>>([])
allRole().then(res => { allRole().then(res => {
roles.value = res.data roles.value = res.data
roles.value.forEach(element => { roles.value.forEach((element:any) => {
element.role_id = element.role_id.toString() element.role_id = element.role_id.toString()
}) })
}) })

View File

@ -4,7 +4,7 @@
<span v-html="`${menuLevel}${prop.menu.menu_name}`"></span> <span v-html="`${menuLevel}${prop.menu.menu_name}`"></span>
</el-option> </el-option>
<template v-if="prop.menu.children"> <template v-if="prop.menu.children">
<select-menu-item :menu="item" v-for="item in prop.menu.children" :level="prop.level + 1" /> <select-menu-item :menu="item" v-for="(item,index) in prop.menu.children" :level="prop.level + 1" :key="index" />
</template> </template>
</template> </template>
</template> </template>
@ -12,7 +12,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed } from 'vue'
const prop = defineProps({ const prop:any = defineProps({
menu: Object, menu: Object,
level: { level: {
type: Number, type: Number,
@ -31,4 +31,4 @@ const menuLevel = computed(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

View File

@ -21,26 +21,40 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed } from 'vue' import { ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' // import type { FormInstance } from 'element-plus'
import { getLogInfo } from '@/app/api/site' import { getLogInfo } from '@/app/api/site'
const showDialog = ref(false) const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
const logData = ref([]) interface LogData {
username: string
ip: string,
url: string,
type: string,
params:any
}
const logData = ref<LogData>({
username: '',
ip: '',
url: '',
type: '',
params: ''
})
const getLogDetail = async () => { const getLogDetail = async () => {
logData.value = await (await getLogInfo(id)).data logData.value = await (await getLogInfo(id)).data
loading.value = false loading.value = false
} }
let id = 0; let id = 0
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true loading.value = true
if (row) { if (row) {
id = row.id; id = row.id
getLogDetail(); getLogDetail()
} }
} }

View File

@ -56,30 +56,27 @@ import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getLogList } from '@/app/api/site' import { getLogList } from '@/app/api/site'
import UserLogDetail from '@/app/views/auth/components/user-log-detail.vue' import UserLogDetail from '@/app/views/auth/components/user-log-detail.vue'
import { useRoute } from 'vue-router'
import { FormInstance } from 'element-plus' import { FormInstance } from 'element-plus'
const route = useRoute() const sysUserLogTableData = reactive({
const pageName = route.meta.title;
let sysUserLogTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
ip:"", ip: '',
username:"", username: '',
url: ''
} }
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadSysUserLogList(); loadSysUserLogList()
} }
/** /**
* 获取管理员操作记录表列表 * 获取管理员操作记录表列表
@ -91,7 +88,7 @@ const loadSysUserLogList = (page: number = 1) => {
getLogList({ getLogList({
page: sysUserLogTableData.page, page: sysUserLogTableData.page,
limit: sysUserLogTableData.limit, limit: sysUserLogTableData.limit,
...sysUserLogTableData.searchParam ...sysUserLogTableData.searchParam
}).then(res => { }).then(res => {
sysUserLogTableData.loading = false sysUserLogTableData.loading = false
sysUserLogTableData.data = res.data.data sysUserLogTableData.data = res.data.data
@ -106,7 +103,7 @@ const userLogDetailDialog: Record<string, any> | null = ref(null)
* 查看详情 * 查看详情
* @param data * @param data
*/ */
const detailEvent = (data: any) => { const detailEvent = (data: any) => {
userLogDetailDialog.value.setFormData(data) userLogDetailDialog.value.setFormData(data)
userLogDetailDialog.value.showDialog = true userLogDetailDialog.value.showDialog = true
} }

View File

@ -1,6 +1,13 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addMenu') }}
</el-button>
</div>
<el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading"> <el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading">
<template #empty> <template #empty>
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span> <span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
@ -22,19 +29,19 @@
<el-table-column :label="t('status')" min-width="120" align="center"> <el-table-column :label="t('status')" min-width="120" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag> <el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{t('statusDeactivate') }}</el-tag> <el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate') }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sort" :label="t('sort')" min-width="100" /> <el-table-column prop="sort" :label="t('sort')" min-width="100" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="130"> <el-table-column :label="t('operation')" align="right" fixed="right" width="130">
<template #default="{ row }"> <template #default="{ row }">
<!-- <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete') }}</el-button> --> <el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<edit-menu ref="editMenuDialog" :menu-tree="menusTableData.data" @complete="getMenuList" /> <edit-menu ref="editMenuDialog" :menu-tree="menusTableData.data" @complete="getMenuList" app-type="admin" />
</el-card> </el-card>
</div> </div>
</template> </template>
@ -45,11 +52,10 @@ import { getMenus, deleteMenu } from '@/app/api/sys'
import { t } from '@/lang' import { t } from '@/lang'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import EditMenu from '@/app/views/auth/components/edit-menu.vue' import EditMenu from '@/app/views/auth/components/edit-menu.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const menusTableData = reactive({ const menusTableData = reactive({
loading: true, loading: true,
data: [] data: []
@ -91,7 +97,7 @@ const editEvent = (data: any) => {
/** /**
* 删除菜单 * 删除菜单
*/ */
const deleteEvent = (menu_key: string) => { const deleteEvent = (key: string) => {
ElMessageBox.confirm(t('menuDeleteTips'), t('warning'), ElMessageBox.confirm(t('menuDeleteTips'), t('warning'),
{ {
confirmButtonText: t('confirm'), confirmButtonText: t('confirm'),
@ -99,7 +105,7 @@ const deleteEvent = (menu_key: string) => {
type: 'warning' type: 'warning'
} }
).then(() => { ).then(() => {
deleteMenu(menu_key).then(res => { deleteMenu('admin', key).then(() => {
getMenuList() getMenuList()
}).catch(() => { }).catch(() => {
}) })

View File

@ -52,27 +52,23 @@ import { getRoleList, deleteRole } from '@/app/api/sys'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox, FormInstance } from 'element-plus'
import EditRole from '@/app/views/auth/components/edit-role.vue' import EditRole from '@/app/views/auth/components/edit-role.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
const roleTableData = reactive({ const roleTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
seach:'' seach: ''
} }
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadRoleList(); loadRoleList()
} }
/** /**
* 获取角色列表 * 获取角色列表

View File

@ -1,39 +1,91 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]"></span>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addMenu') }}
</el-button>
</div>
<el-table :data="menusTableData.data" row-key="menu_key" size="large" v-loading="menusTableData.loading"> <el-tabs v-model="active">
<template #empty> <el-tab-pane :label="t('system')" name="system">
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span> <el-table :data="menusTableData.system" row-key="menu_key" size="large"
</template> v-loading="menusTableData.loading">
<el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')" min-width="150" /> <template #empty>
<el-table-column :label="t('icon')" width="100" align="center"> <span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
<template #default="{ row }"> </template>
<icon v-if="row.icon" :name="row.icon" size="18px" /> <el-table-column prop="menu_name" :show-overflow-tooltip="true" :label="t('menuName')"
</template> min-width="150" />
</el-table-column> <el-table-column :label="t('icon')" width="100" align="center">
<el-table-column :label="t('menuType')" width="80"> <template #default="{ row }">
<template #default="{ row }"> <icon v-if="row.icon" :name="row.icon" size="18px" />
<div v-if="row.menu_type == 0">{{ t('menuTypeDir') }}</div> </template>
<div v-else-if="row.menu_type == 1">{{ t('menuTypeMenu') }}</div> </el-table-column>
<div v-else-if="row.menu_type == 2">{{ t('menuTypeButton') }}</div> <el-table-column :label="t('menuType')" width="80">
</template> <template #default="{ row }">
</el-table-column> <div v-if="row.menu_type == 0">{{ t('menuTypeDir') }}</div>
<el-table-column prop="api_url" :label="t('authId')" min-width="150" align="center" /> <div v-else-if="row.menu_type == 1">{{ t('menuTypeMenu') }}</div>
<el-table-column :label="t('status')" min-width="120" align="center"> <div v-else-if="row.menu_type == 2">{{ t('menuTypeButton') }}</div>
<template #default="{ row }"> </template>
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag> </el-table-column>
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{t('statusDeactivate') }}</el-tag> <el-table-column prop="api_url" :label="t('authId')" min-width="150" align="center" />
</template> <el-table-column :label="t('status')" min-width="120" align="center">
</el-table-column> <template #default="{ row }">
<el-table-column prop="sort" :label="t('sort')" min-width="100" /> <el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
<el-table-column :label="t('operation')" align="right" fixed="right" width="130"> <el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate')
<template #default="{ row }"> }}</el-tag>
<!-- <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button> </template>
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete') }}</el-button> --> </el-table-column>
</template> <el-table-column prop="sort" :label="t('sort')" min-width="100" />
</el-table-column> <el-table-column :label="t('operation')" align="right" fixed="right" width="130">
</el-table> <template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane :label="t('application')" name="application">
<el-table :data="menusTableData.application" 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 }">
<icon v-if="row.icon" :name="row.icon" size="18px" />
</template>
</el-table-column>
<el-table-column :label="t('menuType')" width="80">
<template #default="{ row }">
<div v-if="row.menu_type == 0">{{ t('menuTypeDir') }}</div>
<div v-else-if="row.menu_type == 1">{{ t('menuTypeMenu') }}</div>
<div v-else-if="row.menu_type == 2">{{ t('menuTypeButton') }}</div>
</template>
</el-table-column>
<el-table-column prop="api_url" :label="t('authId')" min-width="150" align="center" />
<el-table-column :label="t('status')" min-width="120" align="center">
<template #default="{ row }">
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{ t('statusDeactivate')
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.menu_key)">{{ t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<edit-menu ref="editMenuDialog" :menu-tree="menusTableData.data" @complete="getMenuList" /> <edit-menu ref="editMenuDialog" :menu-tree="menusTableData.data" @complete="getMenuList" />
</el-card> </el-card>
@ -49,11 +101,12 @@ import EditMenu from '@/app/views/auth/components/edit-menu.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const active = ref('system')
const menusTableData = reactive({ const menusTableData = reactive<Record<string, any>>({
loading: true, loading: true,
data: [] system: [],
application: []
}) })
/** /**
@ -61,9 +114,15 @@ const menusTableData = reactive({
*/ */
const getMenuList = () => { const getMenuList = () => {
menusTableData.loading = true menusTableData.loading = true
getMenus('site').then(res => { getMenus('site').then(({ data }) => {
menusTableData.loading = false menusTableData.loading = false
menusTableData.data = res.data const system: Record<string, any>[] = []
const application: Record<string, any> = []
data.forEach((item: any) => {
item.addon == '' ? system.push(item) : application.push(item)
})
menusTableData.system = system
menusTableData.application = application
}).catch(() => { }).catch(() => {
}) })
@ -92,7 +151,7 @@ const editEvent = (data: any) => {
/** /**
* 删除菜单 * 删除菜单
*/ */
const deleteEvent = (menu_key: string) => { const deleteEvent = (key: string) => {
ElMessageBox.confirm(t('menuDeleteTips'), t('warning'), ElMessageBox.confirm(t('menuDeleteTips'), t('warning'),
{ {
confirmButtonText: t('confirm'), confirmButtonText: t('confirm'),
@ -100,7 +159,7 @@ const deleteEvent = (menu_key: string) => {
type: 'warning' type: 'warning'
} }
).then(() => { ).then(() => {
deleteMenu(menu_key).then(res => { deleteMenu('site', key).then(res => {
getMenuList() getMenuList()
}).catch(() => { }).catch(() => {
}) })

View File

@ -97,7 +97,8 @@ const userTableData = reactive({
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam: {
seach: '' seach: '',
user_type: ''
} }
}) })

View File

@ -77,7 +77,6 @@
<p class="text-[#999] text-[12px]">{{ t('aliappSet') }}</p> <p class="text-[#999] text-[12px]">{{ t('aliappSet') }}</p>
</div> </div>
</div> </div>
</div> </div>
</div> --> </div> -->
<div class="w-full p-5 bg-white"> <div class="w-full p-5 bg-white">
@ -219,10 +218,10 @@
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<div class="flex justify-center"> <div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qr_code ? img(qr_code) : ''"> <el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error> <template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]"> <div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qr_code ? t('fileErr') : t('emptyQrCode') }}</span> <span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div> </div>
</template> </template>
</el-image> </el-image>
@ -236,26 +235,26 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { t } from '@/lang' import { t } from '@/lang'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { getAliappConfig } from '@/app/api/aliapp' import { getAliappConfig } from '@/app/api/aliapp'
const router = useRouter() const router = useRouter()
let activeName = ref("/channel/aliapp"); const activeName = ref('/channel/aliapp')
let active = ref(2); const active = ref(2)
let qr_code = ref('') const qrCode = ref<string>('')
onMounted(async () => { onMounted(async () => {
let res = await getAliappConfig() const res = await getAliappConfig()
qr_code.value = res.data.qr_code qrCode.value = res.data.qr_code
}) })
const linkEvent = (url: string) => { const linkEvent = (url: string) => {
window.open(url, "_blank") window.open(url, '_blank')
} }
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }); router.push({ path: activeName.value })
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -310,4 +309,5 @@ const handleClick = (val: any) => {
:deep(.el-step__title) { :deep(.el-step__title) {
height: 40px; height: 40px;
line-height: 40px !important; line-height: 40px !important;
}</style> }
</style>

View File

@ -100,10 +100,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getWechatConfig } from '@/app/api/wechat' import { getWechatConfig } from '@/app/api/wechat'
import { img } from '@/utils/common' // import { img } from '@/utils/common'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
const route = useRoute() const route = useRoute()
@ -111,26 +111,26 @@ const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
const loading = ref(true) const loading = ref(true)
const formData = reactive<Record<string, string>>({ const formData = reactive<Record<string, string>>({
wechat_name: '', wechat_name: '',
wechat_original: '', wechat_original: '',
app_id: '', app_id: '',
app_secret: '', app_secret: '',
qr_code: '', qr_code: '',
token: '', token: '',
encoding_aes_key: '', encoding_aes_key: '',
encryption_type: 'not_encrypt' encryption_type: 'not_encrypt'
}) })
/** /**
* 获取微信配置 * 获取微信配置
*/ */
getWechatConfig().then(res => { getWechatConfig().then(res => {
Object.assign(formData, res.data) Object.assign(formData, res.data)
loading.value = false loading.value = false
}) })
const linkEvent = () => { const linkEvent = () => {
window.open("https://open.alipay.com/develop/manage", "_blank") window.open('https://open.alipay.com/develop/manage', '_blank')
} }
</script> </script>

View File

@ -42,7 +42,7 @@ const pageName = route.meta.title
const loading = ref(true) const loading = ref(true)
const formData = reactive<Record<string, string | boolean>>({ const formData = reactive<Record<string, string | boolean | any>>({
is_open: false, is_open: false,
request_url: '' request_url: ''
}) })
@ -54,13 +54,13 @@ const formRef = ref<FormInstance>()
*/ */
getH5Config().then(res => { getH5Config().then(res => {
Object.assign(formData, res.data) Object.assign(formData, res.data)
formData.is_open = Boolean(Number(formData.is_open)); formData.is_open = Boolean(Number(formData.is_open))
loading.value = false loading.value = false
}) })
/** /**
* 获取h5域名 * 获取h5域名
*/ */
getUrl().then(res => { getUrl().then(res => {
formData.request_url = res.data.wap_url + '/' formData.request_url = res.data.wap_url + '/'
}) })
@ -89,8 +89,8 @@ watch(copied, () => {
}) })
// 访 // 访
const visitFn = ()=>{ const visitFn = () => {
window.open(formData.request_url); window.open(formData.request_url)
} }
/** /**
@ -102,8 +102,8 @@ const save = async (formEl: FormInstance | undefined) => {
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = {...formData}; const data = { ...formData }
data.is_open = Number(data.is_open); data.is_open = Number(data.is_open)
setH5Config(data).then(() => { setH5Config(data).then(() => {
loading.value = false loading.value = false
}).catch(() => { }).catch(() => {

View File

@ -4,7 +4,6 @@
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{pageName}}</span>
</div> </div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form"> <el-form :model="formData" label-width="150px" ref="formRef" class="page-form">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<el-form-item :label="t('preview')" prop="weapp_name"> <el-form-item :label="t('preview')" prop="weapp_name">
<img class="w-[500px]" src="@/app/assets/images/channel/preview.png" alt=""> <img class="w-[500px]" src="@/app/assets/images/channel/preview.png" alt="">
@ -30,26 +29,25 @@ import { t } from '@/lang'
import { getUrl } from '@/app/api/sys' import { getUrl } from '@/app/api/sys'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance } from 'element-plus' import { ElMessage, FormInstance } from 'element-plus'
import { useRouter, useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const loading = ref(true) const loading = ref(true)
const formData = reactive<Record<string, string | boolean>>({ const formData = reactive<Record<string, string | boolean | any>>({
is_open: false, is_open: false,
request_url: '' request_url: ''
}) })
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const router = useRouter()
/** /**
* 获取pc域名 * 获取pc域名
*/ */
getUrl().then(res => { getUrl().then(res => {
formData.request_url = res.data.web_url + '/'; formData.request_url = res.data.web_url + '/'
loading.value = false; loading.value = false
}) })
/** /**
@ -77,8 +75,8 @@ watch(copied, () => {
}) })
// 访 // 访
const visitFn = ()=>{ const visitFn = () => {
window.open(formData.request_url); window.open(formData.request_url)
} }
</script> </script>

View File

@ -137,10 +137,10 @@
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<div class="flex justify-center"> <div class="flex justify-center">
<el-image class="w-[180px] h-[180px]" :src="qr_code ? img(qr_code) : ''"> <el-image class="w-[180px] h-[180px]" :src="qrCode ? img(qrCode) : ''">
<template #error> <template #error>
<div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]"> <div class="w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]">
<span>{{ qr_code ? t('fileErr') : t('emptyQrCode') }}</span> <span>{{ qrCode ? t('fileErr') : t('emptyQrCode') }}</span>
</div> </div>
</template> </template>
</el-image> </el-image>
@ -155,26 +155,26 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from 'vue'
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
import { t } from "@/lang"; import { t } from '@/lang'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { getWeappConfig } from '@/app/api/weapp' import { getWeappConfig } from '@/app/api/weapp'
const router = useRouter(); const router = useRouter()
let activeName = ref("/channel/weapp"); const activeName = ref('/channel/weapp')
let active = ref(2); const active = ref(2)
let qr_code = ref('') const qrCode = ref('')
onMounted(async () => { onMounted(async () => {
let res = await getWeappConfig() const res = await getWeappConfig()
qr_code.value = res.data.qr_code qrCode.value = res.data.qr_code
}) })
const linkEvent = (url: string) => { const linkEvent = (url: string) => {
window.open(url, "_blank"); window.open(url, '_blank')
}; }
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }); router.push({ path: activeName.value })
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -45,7 +45,7 @@
</div> </div>
</el-card> </el-card>
<el-dialog v-model="dialogVisible" :title="t('codeDownTwoDesc')" width="30%" :before-close="handleClose"> <el-dialog v-model="dialogVisible" :title="t('codeDownTwoDesc')" width="30%" :before-close="handleClose">
<el-form ref="ruleFormRef" :model="form" :rules="rules" label-width="120px"> <el-form ref="ruleFormRef" :model="form" label-width="120px">
<el-form-item prop="code" :label="t('code')"> <el-form-item prop="code" :label="t('code')">
<el-input v-model="form.code" :placeholder="t('codePlaceholder')" <el-input v-model="form.code" :placeholder="t('codePlaceholder')"
onkeyup="this.value = this.value.replace(/[^\d\.]/g,'');" /> onkeyup="this.value = this.value.replace(/[^\d\.]/g,'');" />
@ -76,13 +76,20 @@ import { t } from '@/lang'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { getAuthinfo } from '@/app/api/module' import { getAuthinfo } from '@/app/api/module'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { AnyObject } from '@/types/global'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
const activeNames = ref('1') // const activeNames = ref('1')
const dialogVisible = ref(false) const dialogVisible = ref(false)
const weappTableData = reactive({ const weappTableData:{
page: number,
limit: number,
total: number,
loading: boolean,
data: AnyObject
} = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
@ -90,7 +97,10 @@ const weappTableData = reactive({
data: [] data: []
}) })
const form = ref({ const form = ref({
desc: '' desc: '',
code: '',
path: '',
content: ''
}) })
const authCode = ref('') const authCode = ref('')
@ -102,7 +112,13 @@ getAuthinfo().then(res => {
}).catch(() => { }).catch(() => {
}) })
const weappConfig = ref({}) const weappConfig = ref<{
app_id:string,
app_secret:string
}>({
app_id: '',
app_secret: ''
})
getWeappConfig().then(res => { getWeappConfig().then(res => {
weappConfig.value = res.data weappConfig.value = res.data
}) })
@ -111,7 +127,7 @@ const activeName = ref('/channel/weapp/code')
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }) router.push({ path: activeName.value })
} }
const ruleFormRef = ref(null) const ruleFormRef = ref<any>(null)
/** /**
* 获取版本列表 * 获取版本列表

View File

@ -68,7 +68,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { t } from '@/lang' import { t } from '@/lang'
import { img } from '@/utils/common' // import { img } from '@/utils/common'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
const route = useRoute() const route = useRoute()
@ -76,7 +76,7 @@ const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
const linkEvent = () => { const linkEvent = () => {
window.open("https://mp.weixin.qq.com/", "_blank") window.open('https://mp.weixin.qq.com/', '_blank')
} }
</script> </script>

View File

@ -68,14 +68,15 @@ import { getTemplateList, getBatchAcquisition } from '@/app/api/weapp'
import { editNoticeStatus } from '@/app/api/notice' import { editNoticeStatus } from '@/app/api/notice'
import { ElLoading } from 'element-plus' import { ElLoading } from 'element-plus'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { AnyObject } from '@/types/global'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
let activeName = ref("/channel/weapp/message"); const activeName = ref('/channel/weapp/message')
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }); router.push({ path: activeName.value })
}; }
const cronTableData = reactive({ const cronTableData = reactive({
loading: true, loading: true,
data: [] data: []
@ -117,7 +118,7 @@ interface Switch {
type: string; type: string;
status: number status: number
} }
const infoSwitch = (res) => { const infoSwitch = (res:any) => {
const data = ref<Switch>({ const data = ref<Switch>({
key: '', key: '',
type: '', type: '',

View File

@ -56,13 +56,13 @@ const prop = defineProps({
} }
}) })
const formRef = ref(null) const formRef = ref()
const buttonData = computed({ const buttonData = computed({
get() { get () {
return prop.data return prop.data
}, },
set(value) { set (value) {
} }
}) })

View File

@ -60,10 +60,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getWechatConfig } from '@/app/api/wechat' import { getWechatConfig } from '@/app/api/wechat'
import { img } from '@/utils/common'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
@ -71,26 +70,26 @@ const pageName = route.meta.title
const router = useRouter() const router = useRouter()
const loading = ref(true) const loading = ref(true)
const formData = reactive<Record<string, string>>({ const formData = reactive<Record<string, string>>({
wechat_name: '', wechat_name: '',
wechat_original: '', wechat_original: '',
app_id: '', app_id: '',
app_secret: '', app_secret: '',
qr_code: '', qr_code: '',
token: '', token: '',
encoding_aes_key: '', encoding_aes_key: '',
encryption_type: 'not_encrypt' encryption_type: 'not_encrypt'
}) })
/** /**
* 获取微信配置 * 获取微信配置
*/ */
getWechatConfig().then(res => { getWechatConfig().then(res => {
Object.assign(formData, res.data) Object.assign(formData, res.data)
loading.value = false loading.value = false
}) })
const linkEvent = () => { const linkEvent = () => {
window.open('https://mp.weixin.qq.com/', '_blank') window.open('https://mp.weixin.qq.com/', '_blank')
} }
</script> </script>

View File

@ -99,16 +99,16 @@ const button = ref<Record<string, any>[]>([])
const buttonIndex = ref<number>(0) const buttonIndex = ref<number>(0)
const subButtonIndex = ref<number>(-1) const subButtonIndex = ref<number>(-1)
const formRef = ref<Record<string, any>[] | null>(null) const formRef = ref<Record<string, any>[] | null>(null)
let activeName = ref("/channel/wechat/menu"); const activeName = ref('/channel/wechat/menu')
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }); router.push({ path: activeName.value })
}; }
/** /**
* 获取公众号菜单配置 * 获取公众号菜单配置
*/ */
getWechatMenu().then((res) => { getWechatMenu().then((res) => {
button.value = res.data button.value = res.data
loading.value = false; loading.value = false
}) })
/** /**

View File

@ -1,6 +1,8 @@
<template></template> <template>
<div></div>
</template>
<script lang="ts" setup> <script lang="ts" setup>
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -84,15 +84,15 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title; const pageName = route.meta.title
const cronTableData = reactive({ const cronTableData = reactive({
loading: true, loading: true,
data: [] data: []
}) })
let activeName = ref("/channel/wechat/message"); const activeName = ref('/channel/wechat/message')
const handleClick = (val: any) => { const handleClick = (val: any) => {
router.push({ path: activeName.value }); router.push({ path: activeName.value })
}; }
/** /**
* 获取消息模板列表 * 获取消息模板列表
*/ */

View File

@ -64,13 +64,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed } from 'vue' import { ref, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { setDictData, getDictInfo } from '@/app/api/dict' import { setDictData, getDictInfo } from '@/app/api/dict'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
let showDialog = ref(false) const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
const dialogVisible = ref(false) const dialogVisible = ref(false)
@ -86,7 +86,7 @@ const initialFormData = {
name: '', name: '',
value: '', value: '',
sort: 0, sort: 0,
memo:'', memo: ''
} }
const formData = ref({ ...initialFormData }) const formData = ref({ ...initialFormData })
// //
@ -99,7 +99,7 @@ const formRules = computed(() => {
value: [ value: [
{ required: true, message: t('dataValuePlaceholder'), trigger: 'blur' } { required: true, message: t('dataValuePlaceholder'), trigger: 'blur' }
], ]
} }
}) })
const addEvent = () => { const addEvent = () => {
@ -112,7 +112,7 @@ const editEvent = (row: any, index: number) => {
type.value = 'edit' type.value = 'edit'
tabelIndex.value = index tabelIndex.value = index
formData.value = cloneDeep(initialFormData) formData.value = cloneDeep(initialFormData)
formData.value = Object.assign(formData.value,cloneDeep( row)) formData.value = Object.assign(formData.value, cloneDeep(row))
dialogVisible.value = true dialogVisible.value = true
} }
/** /**
@ -126,9 +126,8 @@ const submit = async (formEl: FormInstance | undefined) => {
tableDate.value.push(cloneDeep(formData.value)) tableDate.value.push(cloneDeep(formData.value))
} else { } else {
tableDate.value.splice(tabelIndex.value, 1, cloneDeep(formData.value)) tableDate.value.splice(tabelIndex.value, 1, cloneDeep(formData.value))
} }
tableDate.value.sort(function(a,b){return b.sort-a.sort}) tableDate.value.sort(function (a, b) { return b.sort - a.sort })
dialogVisible.value = false dialogVisible.value = false
} }
}) })
@ -162,12 +161,10 @@ const setFormData = async (row: any = null) => {
id.value = row.id id.value = row.id
name.value = row.name name.value = row.name
const data = await (await getDictInfo(row.id)).data const data = await (await getDictInfo(row.id)).data
tableDate.value = data.dictionary tableDate.value = data.dictionary
loading.value = false loading.value = false
} }
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData setFormData

View File

@ -31,7 +31,7 @@ import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { addDict, editDict, getDictInfo } from '@/app/api/dict' import { addDict, editDict, getDictInfo } from '@/app/api/dict'
let showDialog = ref(false) const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
/** /**
@ -41,7 +41,7 @@ const initialFormData = {
id: '', id: '',
name: '', name: '',
key: '', key: '',
memo: '', memo: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -52,13 +52,13 @@ const formRef = ref<FormInstance>()
const formRules = computed(() => { const formRules = computed(() => {
return { return {
name: [ name: [
{required: true, message: t('namePlaceholder'), trigger: 'blur'} { required: true, message: t('namePlaceholder'), trigger: 'blur' }
], ],
key: [ key: [
{required: true, message: t('keyPlaceholder'), trigger: 'blur'} { required: true, message: t('keyPlaceholder'), trigger: 'blur' }
], ],
data: [ data: [
{required: true, message: t('dataPlaceholder'), trigger: 'blur'} { required: true, message: t('dataPlaceholder'), trigger: 'blur' }
] ]
} }
}) })
@ -71,19 +71,19 @@ const emit = defineEmits(['complete'])
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.id ? editDict : addDict const save = formData.id ? editDict : addDict
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData const data = formData
save(data).then(res => { save(data).then(res => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
}) })
} }
@ -93,11 +93,13 @@ const confirm = async (formEl: FormInstance | undefined) => {
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if(row){ if (row) {
const data = await (await getDictInfo(row.id)).data const data = await (await getDictInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => { if (data) {
if (data[key] != undefined) formData[key] = data[key] Object.keys(formData).forEach((key: string) => {
}) if (data[key] != undefined) formData[key] = data[key]
})
}
} }
loading.value = false loading.value = false
} }

View File

@ -57,27 +57,27 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getDictList, deleteDict } from '@/app/api/dict' import { getDictList, deleteDict } from '@/app/api/dict'
import { img } from '@/utils/common'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'
import Edit from '@/app/views/dict/components/edit.vue' import Edit from '@/app/views/dict/components/edit.vue'
import dict from '@/app/views/dict/components/dict.vue' import dict from '@/app/views/dict/components/dict.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
let dictTable = reactive({ const dictTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
"name":"", name: '',
"key":"" key: ''
} }
}) })
@ -93,7 +93,7 @@ const loadDictList = (page: number = 1) => {
getDictList({ getDictList({
page: dictTable.page, page: dictTable.page,
limit: dictTable.limit, limit: dictTable.limit,
...dictTable.searchParam ...dictTable.searchParam
}).then(res => { }).then(res => {
dictTable.loading = false dictTable.loading = false
dictTable.data = res.data.data dictTable.data = res.data.data
@ -137,7 +137,7 @@ const deleteEvent = (id: number) => {
{ {
confirmButtonText: t('confirm'), confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'), cancelButtonText: t('cancel'),
type: 'warning', type: 'warning'
} }
).then(() => { ).then(() => {
deleteDict(id).then(() => { deleteDict(id).then(() => {
@ -147,14 +147,12 @@ const deleteEvent = (id: number) => {
}) })
} }
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadDictList() loadDictList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -60,105 +60,103 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {ref, reactive,onMounted, nextTick} from 'vue' import { ref, reactive, onMounted, nextTick } from 'vue'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import { getWapIndexList } from '@/app/api/sys' import { getWapIndexList } from '@/app/api/sys'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import {range} from 'lodash-es' import { range } from 'lodash-es'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
// //
diyStore.editComponent.verify = (index: number) => { diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''}; const res = { code: true, message: '' }
// if (diyStore.value[index].list.length === 0) { // if (diyStore.value[index].list.length === 0) {
// res.code = false; // res.code = false;
// res.message = t('selectAddonTips'); // res.message = t('selectAddonTips');
// } // }
return res; return res
}; }
const showDialog = ref(false) const showDialog = ref(false)
const addonBoxRef = ref() const addonBoxRef = ref()
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
const sortable = Sortable.create(addonBoxRef.value, { const sortable = Sortable.create(addonBoxRef.value, {
group: 'item-wrap', group: 'item-wrap',
animation: 200, animation: 200,
onEnd: event => { onEnd: event => {
const temp = diyStore.editComponent.list[event.oldIndex!]; const temp = diyStore.editComponent.list[event.oldIndex!]
diyStore.editComponent.list.splice(event.oldIndex!, 1); diyStore.editComponent.list.splice(event.oldIndex!, 1)
diyStore.editComponent.list.splice(event.newIndex!, 0, temp); diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
sortable.sort( sortable.sort(
range(diyStore.editComponent.list.length).map(value => { range(diyStore.editComponent.list.length).map(value => {
return value.toString(); return value.toString()
}) })
); )
} }
})
});
})
const addonTableData = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
title: '',
key: '',
}
})
//
const loadAddonList = (page: number = 1) => {
addonTableData.loading = true
addonTableData.page = page
getWapIndexList({
...addonTableData.searchParam
}).then(res => {
addonTableData.loading = false
addonTableData.data = res.data
addonTableData.total = res.data.length
}).catch(() => {
addonTableData.loading = false
}) })
})
})
const addonTableData = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
title: '',
key: '',
}
})
//
const loadAddonList = (page: number = 1) => {
addonTableData.loading = true
addonTableData.page = page
getWapIndexList({
...addonTableData.searchParam
}).then(res => {
addonTableData.loading = false
addonTableData.data = res.data
addonTableData.total = res.data.length
}).catch(() => {
addonTableData.loading = false
})
}
loadAddonList()
const handleCurrentChange = (val:any) => {
const item:any = {
id: diyStore.generateRandom(),
key: '',
title: '',
url: '',
icon: '',
desc: ''
}
for (let k in val) {
item[k] = val[k]
} }
loadAddonList() diyStore.editComponent.list.push(item)
showDialog.value = false
}
const handleCurrentChange = (val) => { const addAddon = () => {
let item:any = { showDialog.value = true
id: diyStore.generateRandom(), }
key: '',
title: '',
url: '',
icon: '',
desc: ''
};
for (let k in val) {
item[k] = val[k];
}
diyStore.editComponent.list.push(item) defineExpose({})
showDialog.value = false
}
const addAddon = () => {
showDialog.value = true;
}
defineExpose({})
</script> </script>
<style lang="scss">
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

View File

@ -135,96 +135,96 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, watch, onMounted, nextTick} from 'vue' import { ref, watch, onMounted, nextTick } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import {range} from 'lodash-es' import { range } from 'lodash-es'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
// //
diyStore.editComponent.verify = (index: number) => { diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''}; const res = { code: true, message: '' }
diyStore.value[index].list.forEach((item: any) => { diyStore.value[index].list.forEach((item: any) => {
if ((diyStore.value[index].mode === 'graphic' || diyStore.value[index].mode === 'img') && item.imageUrl === '') { if ((diyStore.value[index].mode === 'graphic' || diyStore.value[index].mode === 'img') && item.imageUrl === '') {
res.code = false; res.code = false
res.message = t('imageUrlTip'); res.message = t('imageUrlTip')
return res; return res
} }
if ((diyStore.value[index].mode === 'graphic' || diyStore.value[index].mode === 'text') && item.title === '') { if ((diyStore.value[index].mode === 'graphic' || diyStore.value[index].mode === 'text') && item.title === '') {
res.code = false; res.code = false
res.message = t('graphicNavTitlePlaceholder'); res.message = t('graphicNavTitlePlaceholder')
return res; return res
} }
});
return res;
};
diyStore.editComponent.list.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom();
}) })
return res
}
watch( diyStore.editComponent.list.forEach((item: any) => {
() => diyStore.editComponent.list, if (!item.id) item.id = diyStore.generateRandom()
(newValue, oldValue) => { })
//
diyStore.editComponent.list.forEach((item: any) => {
let image = new Image();
image.src = img(item.imageUrl);
image.onload = async () => {
item.imgWidth = image.width;
item.imgHeight = image.height;
};
});
},
{deep: true}
)
const addGraphicNav = () => { watch(
diyStore.editComponent.list.push({ () => diyStore.editComponent.list,
id: diyStore.generateRandom(), (newValue, oldValue) => {
title: '', //
imageUrl: '', diyStore.editComponent.list.forEach((item: any) => {
imgWidth: 0, const image = new Image()
imgHeight: 0, image.src = img(item.imageUrl)
link: {name: ''}, image.onload = async () => {
label: { item.imgWidth = image.width
control: false, item.imgHeight = image.height
text: '热门',
textColor: '#FFFFFF',
bgColorStart: '#F83287',
bgColorEnd: '#FE3423'
} }
}) })
} },
{ deep: true }
)
const imageBoxRef = ref() const addGraphicNav = () => {
diyStore.editComponent.list.push({
onMounted(() => { id: diyStore.generateRandom(),
nextTick(() => { title: '',
const sortable = Sortable.create(imageBoxRef.value, { imageUrl: '',
group: 'item-wrap', imgWidth: 0,
animation: 200, imgHeight: 0,
onEnd: event => { link: { name: '' },
const temp = diyStore.editComponent.list[event.oldIndex!]; label: {
diyStore.editComponent.list.splice(event.oldIndex!, 1); control: false,
diyStore.editComponent.list.splice(event.newIndex!, 0, temp); text: '热门',
sortable.sort( textColor: '#FFFFFF',
range(diyStore.editComponent.list.length).map(value => { bgColorStart: '#F83287',
return value.toString(); bgColorEnd: '#FE3423'
}) }
);
}
})
});
}) })
}
defineExpose({}) const imageBoxRef = ref()
onMounted(() => {
nextTick(() => {
const sortable = Sortable.create(imageBoxRef.value, {
group: 'item-wrap',
animation: 200,
onEnd: event => {
const temp = diyStore.editComponent.list[event.oldIndex!]
diyStore.editComponent.list.splice(event.oldIndex!, 1)
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
sortable.sort(
range(diyStore.editComponent.list.length).map(value => {
return value.toString()
})
)
}
})
})
})
defineExpose({})
</script> </script>
@ -250,4 +250,4 @@
} }
} }
} }
</style> </style>

View File

@ -21,13 +21,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['pageBgColor','topRounded','bottomRounded','marginTop','marginBottom','marginBoth']; // diyStore.editComponent.ignore = ['pageBgColor', 'topRounded', 'bottomRounded', 'marginTop', 'marginBottom', 'marginBoth'] //
defineExpose({}) defineExpose({})
</script> </script>
@ -38,4 +38,4 @@
} }
} }
</style> </style>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -33,41 +33,41 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {img} from '@/utils/common' import { img } from '@/utils/common'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
// //
diyStore.editComponent.verify = (index: number) => { diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''}; const res = { code: true, message: '' }
if (diyStore.value[index].imageUrl === '') { if (diyStore.value[index].imageUrl === '') {
res.code = false; res.code = false
res.message = t('imageUrlTip'); res.message = t('imageUrlTip')
return res; return res
}
return res;
};
const selectImg = (url: string) => {
handleHeight();
};
//
const handleHeight = () => {
let image = new Image();
image.src = img(diyStore.editComponent.imageUrl);
image.onload = async () => {
diyStore.editComponent.imgWidth = image.width;
diyStore.editComponent.imgHeight = image.height;
};
} }
return res
}
defineExpose({}) const selectImg = (url: string) => {
handleHeight()
}
//
const handleHeight = () => {
const image = new Image()
image.src = img(diyStore.editComponent.imageUrl)
image.onload = async () => {
diyStore.editComponent.imgWidth = image.width
diyStore.editComponent.imgHeight = image.height
}
}
defineExpose({})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

View File

@ -44,112 +44,112 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, watch, onMounted, nextTick} from 'vue' import { ref, watch, onMounted, nextTick } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import {range} from 'lodash-es' import { range } from 'lodash-es'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
// //
diyStore.editComponent.verify = (index: number) => { diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''}; const res = { code: true, message: '' }
if(diyStore.value[index].imageHeight == 0){ if (diyStore.value[index].imageHeight == 0) {
res.code = false; res.code = false
res.message = t('imageHeightPlaceholder'); res.message = t('imageHeightPlaceholder')
return res; return res
}
if (!/^\d+.?\d{0,2}$/.test(diyStore.value[index].imageHeight)) {
res.code = false
res.message = t('imageHeightRegNum')
return res
}
diyStore.value[index].list.forEach((item: any) => {
if (item.imageUrl === '') {
res.code = false
res.message = t('imageUrlTip')
return res
} }
if(!/^\d+.?\d{0,2}$/.test(diyStore.value[index].imageHeight)){ })
res.code = false; return res
res.message = t('imageHeightRegNum'); }
return res;
} diyStore.editComponent.list.forEach((item: any) => {
diyStore.value[index].list.forEach((item: any) => { if (!item.id) item.id = diyStore.generateRandom()
if (item.imageUrl === '') { })
res.code = false;
res.message = t('imageUrlTip'); watch(
return res; () => diyStore.editComponent.list,
(newValue, oldValue) => {
//
handleHeight()
},
{ deep: true }
)
const addImageAd = () => {
diyStore.editComponent.list.push({
id: diyStore.generateRandom(),
imageUrl: '',
imgWidth: 0,
imgHeight: 0,
link: { name: '' }
})
}
const selectImg = (url:string) => {
handleHeight(true)
}
//
const handleHeight = (isCalcHeight:boolean = false)=> {
diyStore.editComponent.list.forEach((item: any, index: number) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
item.imgWidth = image.width
item.imgHeight = image.height
//
if (isCalcHeight && index == 0) {
const ratio = item.imgHeight / item.imgWidth
item.width = 375
item.height = item.width * ratio
diyStore.editComponent.imageHeight = parseInt(item.height)
} }
}); }
return res;
};
diyStore.editComponent.list.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom();
}) })
}
watch( const blurImageHeight = () => {
() => diyStore.editComponent.list, diyStore.editComponent.imageHeight = parseInt(diyStore.editComponent.imageHeight)
(newValue, oldValue) => { }
//
handleHeight();
},
{deep: true}
)
const addImageAd = () => { const imageBoxRef = ref()
diyStore.editComponent.list.push({
id: diyStore.generateRandom(), onMounted(() => {
imageUrl: '', nextTick(() => {
imgWidth: 0, const sortable = Sortable.create(imageBoxRef.value, {
imgHeight: 0, group: 'item-wrap',
link: {name: ''} animation: 200,
onEnd: event => {
const temp = diyStore.editComponent.list[event.oldIndex!]
diyStore.editComponent.list.splice(event.oldIndex!, 1)
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
sortable.sort(
range(diyStore.editComponent.list.length).map(value => {
return value.toString()
})
)
handleHeight(true)
}
}) })
}
const selectImg = (url:string)=> {
handleHeight(true);
};
//
const handleHeight = (isCalcHeight:boolean = false)=> {
diyStore.editComponent.list.forEach((item: any, index: number) => {
let image = new Image();
image.src = img(item.imageUrl);
image.onload = async () => {
item.imgWidth = image.width;
item.imgHeight = image.height;
//
if (isCalcHeight && index == 0) {
var ratio = item.imgHeight / item.imgWidth;
item.width = 375;
item.height = item.width * ratio;
diyStore.editComponent.imageHeight = parseInt(item.height);
}
};
});
}
const blurImageHeight = ()=> {
diyStore.editComponent.imageHeight = parseInt(diyStore.editComponent.imageHeight);
}
const imageBoxRef = ref()
onMounted(() => {
nextTick(() => {
const sortable = Sortable.create(imageBoxRef.value, {
group: 'item-wrap',
animation: 200,
onEnd: event => {
const temp = diyStore.editComponent.list[event.oldIndex!];
diyStore.editComponent.list.splice(event.oldIndex!, 1);
diyStore.editComponent.list.splice(event.newIndex!, 0, temp);
sortable.sort(
range(diyStore.editComponent.list.length).map(value => {
return value.toString();
})
);
handleHeight(true);
}
})
});
}) })
})
defineExpose({}) defineExpose({})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -167,4 +167,4 @@
} }
} }
} }
</style> </style>

View File

@ -28,14 +28,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
defineExpose({}) defineExpose({})
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -55,7 +55,6 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<!-- 组件样式 --> <!-- 组件样式 -->
<slot name="style"></slot> <slot name="style"></slot>
</div> </div>
@ -63,39 +62,39 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {ref, reactive} from 'vue' import { ref } from 'vue'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
const showDialog = ref(false) const showDialog = ref(false)
const showStyle = () => { const showStyle = () => {
showDialog.value = true showDialog.value = true
}
const selectStyle = ref(diyStore.editComponent.style)
const changeStyle = () => {
switch (selectStyle.value) {
case 'style-1':
diyStore.editComponent.subTitle.control = false
diyStore.editComponent.more.control = false
diyStore.editComponent.styleName = '风格1'
break
case 'style-2':
diyStore.editComponent.subTitle.control = true
diyStore.editComponent.more.control = true
diyStore.editComponent.styleName = '风格2'
break
} }
diyStore.editComponent.style = selectStyle.value
showDialog.value = false
}
const selectStyle = ref(diyStore.editComponent.style) defineExpose({})
const changeStyle = () => {
switch (selectStyle.value) {
case 'style-1':
diyStore.editComponent.subTitle.control = false
diyStore.editComponent.more.control = false
diyStore.editComponent.styleName = "风格1"
break;
case 'style-2':
diyStore.editComponent.subTitle.control = true
diyStore.editComponent.more.control = true
diyStore.editComponent.styleName = "风格2"
break;
}
diyStore.editComponent.style = selectStyle.value
showDialog.value = false
}
defineExpose({})
</script> </script>
<style lang="scss"> <style lang="scss">
@ -108,4 +107,4 @@
width: calc(100% - 20px); width: calc(100% - 20px);
} }
</style> </style>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -40,27 +40,27 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import {ref,watch} from 'vue' import { watch } from 'vue'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {img} from '@/utils/common' import { img } from '@/utils/common'
const diyStore = useDiyStore() const diyStore = useDiyStore()
watch( watch(
() => diyStore.global.bgUrl, () => diyStore.global.bgUrl,
(newValue, oldValue) => { (newValue, oldValue) => {
// //
let image = new Image(); const image = new Image()
image.src = img(diyStore.global.bgUrl); image.src = img(diyStore.global.bgUrl)
image.onload = async () => { image.onload = async () => {
diyStore.global.imgWidth = image.width; diyStore.global.imgWidth = image.width
diyStore.global.imgHeight = image.height; diyStore.global.imgHeight = image.height
};
} }
) }
)
defineExpose({}) defineExpose({})
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -9,7 +9,7 @@
<span>{{ selectTemplate.name }}</span> <span>{{ selectTemplate.name }}</span>
</el-form-item> </el-form-item>
<ul class="selected-template-list"> <ul class="selected-template-list">
<li v-for="(item,i) in templateList" :class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]" @click="changeTemplateList(i)"> <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> </li>
</ul> </ul>
@ -20,7 +20,7 @@
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<ul class="layout"> <ul class="layout">
<li v-for="(li,i) in selectTemplate.dimensionScale" :class="[selectTemplate.className]" :style="{ width: rubikCubeList[i].widthStyle, height: rubikCubeList[i].imgHeight + 'px' }"> <li v-for="(li,i) in selectTemplate.dimensionScale" :key="i" :class="[selectTemplate.className]" :style="{ width: rubikCubeList[i].widthStyle, height: rubikCubeList[i].imgHeight + 'px' }">
<div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl"> <div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl">
<img class="!w-full !h-full" :src="img(diyStore.editComponent.list[i].imageUrl)"/> <img class="!w-full !h-full" :src="img(diyStore.editComponent.list[i].imageUrl)"/>
</div> </div>
@ -31,7 +31,7 @@
</li> </li>
</ul> </ul>
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]"> <div v-for="(item) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')"> <el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg"/> <upload-image v-model="item.imageUrl" :limit="1" @change="selectImg"/>
</el-form-item> </el-form-item>
@ -72,423 +72,422 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, watch, onMounted, nextTick, computed} from 'vue' import { ref, computed } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {img} from '@/utils/common' import { img } from '@/utils/common'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
// //
diyStore.editComponent.verify = (index: number) => { diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''}; const res = { code: true, message: '' }
diyStore.value[index].list.forEach((item: any) => { diyStore.value[index].list.forEach((item: any) => {
if (item.imageUrl === '') { if (item.imageUrl === '') {
res.code = false; res.code = false
res.message = t('imageUrlTip'); res.message = t('imageUrlTip')
return res; return res
}
});
return res;
};
const templateList = ref([
{
name: "1行2个",
src: 'iconyihangliangge',
className: "row1-of2",
dimensionScale: [
{
desc: "宽度50%",
size: "200px * 200px",
name: "图一"
},
{
desc: "宽度50%",
size: "200px * 200px",
name: "图二"
}
],
descAux: "选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为200px"
},
{
name: "1行3个",
src: 'iconyihangsange',
className: "row1-of3",
dimensionScale: [
{
desc: "宽度33.33%",
size: "200px * 200px",
name: "图一"
},
{
desc: "宽度33.33%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度33.33%",
size: "200px * 200px",
name: "图三"
}
],
descAux: "选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为130px"
},
{
name: "1行4个",
src: 'iconyihangsige',
className: "row1-of4",
dimensionScale: [
{
desc: "宽度25%",
size: "200px * 200px",
name: "图一"
},
{
desc: "宽度25%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度25%",
size: "200px * 200px",
name: "图三"
},
{
desc: "宽度25%",
size: "200px * 200px",
name: "图四"
}
],
descAux: "选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为100px"
},
{
name: "2左2右",
src: 'iconmofang-liangzuoliangyou',
className: "row2-lt-of2-rt",
dimensionScale: [
{
desc: "宽度50%",
size: "200px * 200px",
name: "图一"
},
{
desc: "宽度50%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度50%",
size: "200px * 200px",
name: "图三"
},
{
desc: "宽度50%",
size: "200px * 200px",
name: "图四"
}
],
descAux: "选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为200px"
},
{
name: "1左2右",
src: 'iconmofang-yizuoliangyou',
className: "row1-lt-of2-rt",
dimensionScale: [
{
desc: "宽度50% * 高度100%",
size: "200px * 400px",
name: "图一"
},
{
desc: "宽度50% * 高度50%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度50% * 高度50%",
size: "200px * 200px",
name: "图三"
}
],
descAux: "选定布局区域在下方添加图片宽度最小建议为200px右侧两张图片高度一致左侧图片高度为右侧两张图片高度之和左侧图片尺寸200px * 300px右侧两张图片尺寸200px * 150px"
},
{
name: "1上2下",
src: 'iconmofang-yishangliangxia',
className: "row1-tp-of2-bm",
dimensionScale: [
{
desc: "宽度100% * 高度50%",
size: "400px * 200px",
name: "图一"
},
{
desc: "宽度50% * 高度50%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度50% * 高度50%",
size: "200px * 200px",
name: "图三"
}
],
descAux: "选定布局区域在下方添加图片上方一张图片的宽度为下方两张图片宽度之和下放两张图片尺寸一致高度可根据实际需求自行确定上方图片尺寸400px * 150px下方两张图片尺寸200px * 150px"
},
{
name: "1左3右",
src: 'iconxuanzemoban-yizuosanyou',
className: "row1-lt-of1-tp-of2-bm",
dimensionScale: [
{
desc: "宽度50% * 高度100%",
size: "200px * 400px",
name: "图一"
},
{
desc: "宽度50% * 高度50%",
size: "200px * 200px",
name: "图二"
},
{
desc: "宽度25% * 高度50%",
size: "100px * 200px",
name: "图三"
},
{
desc: "宽度25% * 高度50%",
size: "100px * 200px",
name: "图四"
}
],
descAux: "选定布局区域在下方添加图片左右两侧内容宽高相同右侧上下区域高度各占50%右侧内容下半部分两张图片的宽度相同各占右侧内容宽度的50%左侧图片尺寸200px * 400px右侧上半部分图片尺寸200px * 200px右侧下半部分两张图片尺寸100px * 200px"
} }
]); })
return res
}
let rubikCubeList = ref([]); const templateList = ref([
const selectTemplate = computed(() => { {
var data; name: '1行2个',
templateList.value.forEach((item) => { src: 'iconyihangliangge',
if (item.className == diyStore.editComponent.mode) { className: 'row1-of2',
data = item; dimensionScale: [
{
rubikCubeList.value = JSON.parse(JSON.stringify(diyStore.editComponent.list)); desc: '宽度50%',
if (item.className == 'row2-lt-of2-rt') { size: '200px * 200px',
calcFourSquare(); name: '图一'
} else if (item.className == 'row1-lt-of2-rt') { },
calcRowOneLeftOfTwoRight(); {
} else if (item.className == 'row1-tp-of2-bm') { desc: '宽度50%',
calcRowOneTopOfTwoBottom(); size: '200px * 200px',
} else if (item.className == 'row1-lt-of1-tp-of2-bm') { name: '图二'
calcRowOneLeftOfOneTopOfTwoBottom();
} else {
calcSingleRow(item.className);
}
} }
}) ],
return data; descAux: '选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为200px'
}); },
{
name: '1行3个',
src: 'iconyihangsange',
className: 'row1-of3',
dimensionScale: [
{
desc: '宽度33.33%',
size: '200px * 200px',
name: '图一'
},
{
desc: '宽度33.33%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度33.33%',
size: '200px * 200px',
name: '图三'
}
],
descAux: '选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为130px'
},
{
name: '1行4个',
src: 'iconyihangsige',
className: 'row1-of4',
dimensionScale: [
{
desc: '宽度25%',
size: '200px * 200px',
name: '图一'
},
{
desc: '宽度25%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度25%',
size: '200px * 200px',
name: '图三'
},
{
desc: '宽度25%',
size: '200px * 200px',
name: '图四'
}
],
descAux: '选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为100px'
},
{
name: '2左2右',
src: 'iconmofang-liangzuoliangyou',
className: 'row2-lt-of2-rt',
dimensionScale: [
{
desc: '宽度50%',
size: '200px * 200px',
name: '图一'
},
{
desc: '宽度50%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度50%',
size: '200px * 200px',
name: '图三'
},
{
desc: '宽度50%',
size: '200px * 200px',
name: '图四'
}
],
descAux: '选定布局区域在下方添加图片建议添加尺寸一致的图片宽度最小建议为200px'
},
{
name: '1左2右',
src: 'iconmofang-yizuoliangyou',
className: 'row1-lt-of2-rt',
dimensionScale: [
{
desc: '宽度50% * 高度100%',
size: '200px * 400px',
name: '图一'
},
{
desc: '宽度50% * 高度50%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度50% * 高度50%',
size: '200px * 200px',
name: '图三'
}
],
descAux: '选定布局区域在下方添加图片宽度最小建议为200px右侧两张图片高度一致左侧图片高度为右侧两张图片高度之和左侧图片尺寸200px * 300px右侧两张图片尺寸200px * 150px'
},
{
name: '1上2下',
src: 'iconmofang-yishangliangxia',
className: 'row1-tp-of2-bm',
dimensionScale: [
{
desc: '宽度100% * 高度50%',
size: '400px * 200px',
name: '图一'
},
{
desc: '宽度50% * 高度50%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度50% * 高度50%',
size: '200px * 200px',
name: '图三'
}
],
descAux: '选定布局区域在下方添加图片上方一张图片的宽度为下方两张图片宽度之和下放两张图片尺寸一致高度可根据实际需求自行确定上方图片尺寸400px * 150px下方两张图片尺寸200px * 150px'
},
{
name: '1左3右',
src: 'iconxuanzemoban-yizuosanyou',
className: 'row1-lt-of1-tp-of2-bm',
dimensionScale: [
{
desc: '宽度50% * 高度100%',
size: '200px * 400px',
name: '图一'
},
{
desc: '宽度50% * 高度50%',
size: '200px * 200px',
name: '图二'
},
{
desc: '宽度25% * 高度50%',
size: '100px * 200px',
name: '图三'
},
{
desc: '宽度25% * 高度50%',
size: '100px * 200px',
name: '图四'
}
],
descAux: '选定布局区域在下方添加图片左右两侧内容宽高相同右侧上下区域高度各占50%右侧内容下半部分两张图片的宽度相同各占右侧内容宽度的50%左侧图片尺寸200px * 400px右侧上半部分图片尺寸200px * 200px右侧下半部分两张图片尺寸100px * 200px'
}
])
const changeTemplateList = (v: number) => { const rubikCubeList = ref([])
for (var i = 0; i < templateList.value.length; i++) { const selectTemplate = computed(() => {
if (i == v) { let data
diyStore.editComponent.mode = templateList.value[i].className; templateList.value.forEach((item) => {
var count = templateList.value[i].dimensionScale.length; if (item.className == diyStore.editComponent.mode) {
data = item
// rubikCubeList.value = JSON.parse(JSON.stringify(diyStore.editComponent.list))
if (item.className == 'row2-lt-of2-rt') {
calcFourSquare()
} else if (item.className == 'row1-lt-of2-rt') {
calcRowOneLeftOfTwoRight()
} else if (item.className == 'row1-tp-of2-bm') {
calcRowOneTopOfTwoBottom()
} else if (item.className == 'row1-lt-of1-tp-of2-bm') {
calcRowOneLeftOfOneTopOfTwoBottom()
} else {
calcSingleRow(item.className)
}
}
})
return data
})
// const changeTemplateList = (v: number) => {
if (count > diyStore.editComponent.list.length) { for (let i = 0; i < templateList.value.length; i++) {
for (var j = 0; j < count; j++) { if (i == v) {
if ((j + 1) > diyStore.editComponent.list.length) diyStore.editComponent.list.push({ diyStore.editComponent.mode = templateList.value[i].className
imageUrl: "", const count = templateList.value[i].dimensionScale.length
//
//
if (count > diyStore.editComponent.list.length) {
for (let j = 0; j < count; j++) {
if ((j + 1) > diyStore.editComponent.list.length) {
diyStore.editComponent.list.push({
imageUrl: '',
imgWidth: 0, imgWidth: 0,
imgHeight: 0, imgHeight: 0,
link: {name: ""} link: { name: '' }
}); })
} }
} else { }
// } else {
if (count != diyStore.editComponent.list.length) { //
for (var j = 0; j < diyStore.editComponent.list.length; j++) { if (count != diyStore.editComponent.list.length) {
if ((j + 1) > count) { for (let j = 0; j < diyStore.editComponent.list.length; j++) {
diyStore.editComponent.list.splice(j, 1); if ((j + 1) > count) {
j = 0; diyStore.editComponent.list.splice(j, 1)
} j = 0
} }
} }
} }
} }
} }
};
const selectImg = (url:string)=> {
handleHeight(true);
};
//
const handleHeight = (isCalcHeight:boolean = false)=> {
diyStore.editComponent.list.forEach((item: any, index: number) => {
let image = new Image();
image.src = img(item.imageUrl);
image.onload = async () => {
item.imgWidth = image.width;
item.imgHeight = image.height;
};
});
} }
}
defineExpose({}) const selectImg = (url:string) => {
handleHeight(true)
}
/** //
const handleHeight = (isCalcHeight:boolean = false) => {
diyStore.editComponent.list.forEach((item: any, index: number) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
item.imgWidth = image.width
item.imgHeight = image.height
}
})
}
defineExpose({})
/**
* 魔方单行多个平分宽度 * 魔方单行多个平分宽度
* 公式 * 公式
* 宽度屏幕宽度/2示例375/2=187.5 * 宽度屏幕宽度/2示例375/2=187.5
* 比例原图高/原图宽示例322/690=0.46 * 比例原图高/原图宽示例322/690=0.46
* 高度宽度*比例示例187.5*0.46=86.25 * 高度宽度*比例示例187.5*0.46=86.25
*/ */
const calcSingleRow = (type) => { const calcSingleRow = (type:any) => {
let maxHeight = 0; let maxHeight = 0
var paramsRatio = 2; let paramsRatio = 2
var paramsWidth = 'calc(100% / 2)'; let paramsWidth = 'calc(100% / 2)'
if(type == 'row1-of3'){ if (type == 'row1-of3') {
paramsRatio = 3; paramsRatio = 3
paramsWidth = 'calc(100% / 3)'; paramsWidth = 'calc(100% / 3)'
} }
if(type == 'row1-of4'){ if (type == 'row1-of4') {
paramsRatio = 4 paramsRatio = 4
paramsWidth = 'calc(100% / 4)'; paramsWidth = 'calc(100% / 4)'
} }
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
var ratio = item.imgHeight / item.imgWidth; const ratio = item.imgHeight / item.imgWidth
let width = 330; const width = 330
item.imgWidth = width / paramsRatio; item.imgWidth = width / paramsRatio
item.imgHeight = item.imgWidth * ratio; item.imgHeight = item.imgWidth * ratio
if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight; if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight
}) })
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
item.widthStyle = paramsWidth; item.widthStyle = paramsWidth
item.imgHeight = maxHeight; item.imgHeight = maxHeight
}); })
}; };
/** /**
* 魔方四方型各占50% * 魔方四方型各占50%
*/ */
const calcFourSquare = () => { const calcFourSquare = () => {
let maxHeightFirst = 0; let maxHeightFirst = 0
let maxHeightTwo = 0; let maxHeightTwo = 0
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
var ratio = item.imgHeight / item.imgWidth; const ratio = item.imgHeight / item.imgWidth
item.imgWidth = 330; item.imgWidth = 330
item.imgWidth = item.imgWidth / 2; item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio; item.imgHeight = item.imgWidth * ratio
//
if (index <= 1) {
if (maxHeightFirst == 0 || maxHeightFirst < item.imgHeight) {
maxHeightFirst = item.imgHeight
}
} else if (index > 1) {
if (maxHeightTwo == 0 || maxHeightTwo < item.imgHeight) {
maxHeightTwo = item.imgHeight
}
}
})
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth = 'calc(100% / 2)'
item.widthStyle = item.imgWidth
if (index <= 1) {
item.imgHeight = maxHeightFirst
} else if (index > 1) {
item.imgHeight = maxHeightTwo
}
})
}
// /**
if (index <= 1) {
if (maxHeightFirst == 0 || maxHeightFirst < item.imgHeight) {
maxHeightFirst = item.imgHeight;
}
} else if (index > 1) {
if (maxHeightTwo == 0 || maxHeightTwo < item.imgHeight) {
maxHeightTwo = item.imgHeight;
}
}
});
rubikCubeList.value.forEach((item, index) => {
item.imgWidth = 'calc(100% / 2)';
item.widthStyle = item.imgWidth;
if (index <= 1) {
item.imgHeight = maxHeightFirst;
} else if (index > 1) {
item.imgHeight = maxHeightTwo;
}
});
}
/**
* 魔方1左2右 * 魔方1左2右
*/ */
const calcRowOneLeftOfTwoRight = () => { const calcRowOneLeftOfTwoRight = () => {
let rightHeight = 0; // let rightHeight = 0 //
let divide = 'left'; // leftright let divide = 'left' // leftright
if (rubikCubeList.value[1].imgWidth === rubikCubeList.value[2].imgWidth) divide = 'right'; if (rubikCubeList.value[1].imgWidth === rubikCubeList.value[2].imgWidth) divide = 'right'
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
if (index == 0) { if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; // const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330; item.imgWidth = 330
item.imgWidth = item.imgWidth / 2; item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio; item.imgHeight = item.imgWidth * ratio
rightHeight = item.imgHeight / 2; rightHeight = item.imgHeight / 2
item.imgWidth += 'px'; item.imgWidth += 'px'
} else { } else {
item.imgWidth = rubikCubeList.value[0].imgWidth; item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rightHeight; item.imgHeight = rightHeight
} }
}); })
} }
/** /**
* 魔方1上2下 * 魔方1上2下
*/ */
const calcRowOneTopOfTwoBottom = () => { const calcRowOneTopOfTwoBottom = () => {
var maxHeight = 0; let maxHeight = 0
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth //
if (index == 0) {
item.imgWidth = 330
} else if (index > 0) {
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
}
var ratio = item.imgHeight / item.imgWidth; // item.imgHeight = item.imgWidth * ratio
if (index == 0) {
item.imgWidth = 330;
} else if (index > 0) {
item.imgWidth = 330;
item.imgWidth = item.imgWidth / 2;
}
item.imgHeight = item.imgWidth * ratio; //
if (index > 0 && (maxHeight == 0 || maxHeight < item.imgHeight)) {
maxHeight = item.imgHeight
}
})
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth += 'px'
item.widthStyle = item.imgWidth
if (index > 0) item.imgHeight = maxHeight
})
}
// /**
if (index > 0 && (maxHeight == 0 || maxHeight < item.imgHeight))
maxHeight = item.imgHeight;
});
rubikCubeList.value.forEach((item, index) => {
item.imgWidth += 'px';
item.widthStyle = item.imgWidth;
if (index > 0) item.imgHeight = maxHeight;
});
}
/**
* 魔方1左3右 * 魔方1左3右
*/ */
const calcRowOneLeftOfOneTopOfTwoBottom = () => { const calcRowOneLeftOfOneTopOfTwoBottom = () => {
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
// //
if (index == 0) { if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; // const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330; item.imgWidth = 330
item.imgWidth = item.imgWidth / 2; item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio; item.imgHeight = item.imgWidth * ratio
} else if (index == 1) { } else if (index == 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth; item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rubikCubeList.value[0].imgHeight / 2; item.imgHeight = rubikCubeList.value[0].imgHeight / 2
} else if (index > 1) { } else if (index > 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth / 2; item.imgWidth = rubikCubeList.value[0].imgWidth / 2
item.imgHeight = rubikCubeList.value[1].imgHeight; item.imgHeight = rubikCubeList.value[1].imgHeight
} }
}); })
rubikCubeList.value.forEach((item, index) => { rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth += 'px'; item.imgWidth += 'px'
}); })
} }
</script> </script>

View File

@ -5,9 +5,10 @@
<h3 class="mb-[10px]">{{ t('styleSet') }}</h3> <h3 class="mb-[10px]">{{ t('styleSet') }}</h3>
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex"> <el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span> <span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName
}}</span>
<el-icon> <el-icon>
<ArrowRight/> <ArrowRight />
</el-icon> </el-icon>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -16,15 +17,16 @@
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3> <h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('title')"> <el-form-item :label="t('title')">
<el-input v-model="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="15" show-word-limit/> <el-input v-model="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable
maxlength="15" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item :label="t('link')"> <el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.link"/> <diy-link v-model="diyStore.editComponent.link" />
</el-form-item> </el-form-item>
<el-form-item :label="t('textAlign')" v-show="diyStore.editComponent.style == 'style-1'"> <el-form-item :label="t('textAlign')" v-show="diyStore.editComponent.style == 'style-1'">
<el-radio-group v-model="diyStore.editComponent.textAlign"> <el-radio-group v-model="diyStore.editComponent.textAlign">
<el-radio :label="'left'">{{t('textAlignLeft')}}</el-radio> <el-radio :label="'left'">{{ t('textAlignLeft') }}</el-radio>
<el-radio :label="'center'">{{t('textAlignCenter')}}</el-radio> <el-radio :label="'center'">{{ t('textAlignCenter') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -34,13 +36,15 @@
<h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3> <h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('subTitle')"> <el-form-item :label="t('subTitle')">
<el-input v-model="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="30" show-word-limit/> <el-input v-model="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')"
clearable maxlength="30" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item :label="t('textFontSize')"> <el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="16"/> <el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small"
class="ml-[10px] article-slider" :min="12" :max="16" />
</el-form-item> </el-form-item>
<el-form-item :label="t('textColor')"> <el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.color"/> <el-color-picker v-model="diyStore.editComponent.subTitle.color" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -49,16 +53,17 @@
<h3 class="mb-[10px]">{{ t('moreContent') }}</h3> <h3 class="mb-[10px]">{{ t('moreContent') }}</h3>
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('more')"> <el-form-item :label="t('more')">
<el-input v-model="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable maxlength="8" show-word-limit/> <el-input v-model="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable
maxlength="8" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item :label="t('link')"> <el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.more.link"/> <diy-link v-model="diyStore.editComponent.more.link" />
</el-form-item> </el-form-item>
<el-form-item :label="t('moreIsShow')"> <el-form-item :label="t('moreIsShow')">
<el-switch v-model="diyStore.editComponent.more.isShow"/> <el-switch v-model="diyStore.editComponent.more.isShow" />
</el-form-item> </el-form-item>
<el-form-item :label="t('textColor')"> <el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.more.color"/> <el-color-picker v-model="diyStore.editComponent.more.color" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -66,19 +71,21 @@
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="40%"> <el-dialog v-model="showDialog" :title="t('selectStyle')" width="40%">
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50" :class="{ 'border-primary' : selectStyle == 'style-1'}" @click="selectStyle = 'style-1'"> <div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50"
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png"/> :class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
</div> </div>
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50" :class="{ 'border-primary' : selectStyle == 'style-2'}" @click="selectStyle = 'style-2'"> <div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50"
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png"/> :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png" />
</div> </div>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel')}}</el-button> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button> <el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -91,16 +98,17 @@
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3> <h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]"> <el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')"> <el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="20"/> <el-slider v-model="diyStore.editComponent.fontSize" show-input size="small"
class="ml-[10px] article-slider" :min="12" :max="20" />
</el-form-item> </el-form-item>
<el-form-item :label="t('textFontWeight')"> <el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight"> <el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio> <el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio> <el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="t('textColor')"> <el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor"/> <el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -109,51 +117,49 @@
<slot name="style"></slot> <slot name="style"></slot>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {t} from '@/lang' import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy' import useDiyStore from '@/stores/modules/diy'
import {ref, reactive} from 'vue' import { ref } from 'vue'
const diyStore = useDiyStore() const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; // diyStore.editComponent.ignore = [] //
const showDialog = ref(false) const showDialog = ref(false)
const showStyle = () => { const showStyle = () => {
showDialog.value = true showDialog.value = true
}
const selectStyle = ref(diyStore.editComponent.style)
const changeStyle = () => {
switch (selectStyle.value) {
case 'style-1':
diyStore.editComponent.subTitle.control = false
diyStore.editComponent.more.control = false
diyStore.editComponent.styleName = '风格1'
break
case 'style-2':
diyStore.editComponent.subTitle.control = true
diyStore.editComponent.more.control = true
diyStore.editComponent.styleName = '风格2'
break
} }
diyStore.editComponent.style = selectStyle.value
showDialog.value = false
}
const selectStyle = ref(diyStore.editComponent.style) defineExpose({})
const changeStyle = () => {
switch (selectStyle.value) {
case 'style-1':
diyStore.editComponent.subTitle.control = false
diyStore.editComponent.more.control = false
diyStore.editComponent.styleName = "风格1"
break;
case 'style-2':
diyStore.editComponent.subTitle.control = true
diyStore.editComponent.more.control = true
diyStore.editComponent.styleName = "风格2"
break;
}
diyStore.editComponent.style = selectStyle.value
showDialog.value = false
}
defineExpose({})
</script> </script>
<style lang="scss"> <style lang="scss">
.horz-blank-slider { .horz-blank-slider {
.el-slider__input { .el-slider__input {
width: 100px; width: 100px;
}
} }
</style> }</style>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

File diff suppressed because it is too large Load Diff

View File

@ -1,460 +1,457 @@
<template> <template>
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] mt-[20px] bg-[#f7f7f7] w-[300px] pt-[80px] pb-[20px]" <div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] mt-[20px] bg-[#f7f7f7] w-[300px] pt-[80px] pb-[20px]"
:class="{ 'cursor-pointer' : !item.isDisabledPop }" v-for="(item,key) in page" :key="key"> :class="{ 'cursor-pointer': !item.isDisabledPop }" v-for="(item, key) in page" :key="key">
<p class="absolute top-[46px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center"> <p class="absolute top-[46px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">
{{item.use_template.title}}</p> {{ item.use_template.title }}</p>
<div v-show="item.use_template.url" class="w-[282px] h-[493px] mx-auto"> <div v-show="item.use_template.url" class="w-[282px] h-[493px] mx-auto">
<iframe :id="'previewIframe_' + key" v-show="item.loadingIframe" class="w-[282px] h-[493px] mx-auto" <iframe :id="'previewIframe_' + key" v-show="item.loadingIframe" class="w-[282px] h-[493px] mx-auto"
:src="item.use_template.wapPreview" frameborder="0"></iframe> :src="item.use_template.wapPreview" frameborder="0"></iframe>
<div v-show="item.loadingDev" class="w-[282px] h-[493px] mx-auto bg-body pt-[20px] px-[20px]"> <div v-show="item.loadingDev" class="w-[282px] h-[493px] mx-auto bg-body pt-[20px] px-[20px]">
<div class="font-bold text-xl mb-[40px]">{{t('developTitle')}}</div> <div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col"> <div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text> <text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable/> <el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
</div> </div>
<div class="flex"> <div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button> <el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button> <el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
</div> </div>
</div> </div>
</div> </div>
<div v-show="!item.use_template.wapPreview" class="overflow-hidden w-[282px] h-[493px] mx-auto"> <div v-show="!item.use_template.wapPreview" class="overflow-hidden w-[282px] h-[493px] mx-auto">
<img class="max-w-full" v-if="item.use_template.cover" :src="img(item.use_template.cover)"/> <img class="max-w-full" v-if="item.use_template.cover" :src="img(item.use_template.cover)" />
</div> </div>
<p class="text-[12px] text-[#999] mt-[10px] mx-auto truncate text-center w-[250px]"> <p class="text-[12px] text-[#999] mt-[10px] mx-auto truncate text-center w-[250px]">
{{item.use_template.desc}}</p> {{ item.use_template.desc }}</p>
<div class="item-hide absolute inset-x-0 inset-y-0 bg-black bg-opacity-50 text-center" <div class="item-hide absolute inset-x-0 inset-y-0 bg-black bg-opacity-50 text-center"
:class="{ 'disabled' : item.isDisabledPop }"> :class="{ 'disabled': item.isDisabledPop }">
<div class="item-btn-box absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-col flex-wrap"> <div
<el-button @click="show(key,item)">{{ t('changePage') }}</el-button> class="item-btn-box absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-col flex-wrap">
<el-button @click="toDecorate(item.use_template)" <el-button @click="show(key, item)">{{ t('changePage') }}</el-button>
v-show="item.use_template.mode != 'other' || item.use_template.action == 'decorate'">{{ <el-button @click="toDecorate(item.use_template)"
t('decorate') }} v-show="item.use_template.mode != 'other' || item.use_template.action == 'decorate'">{{
</el-button> t('decorate') }}
<el-button @click="toPreview(item.use_template)">{{ t('preview') }}</el-button> </el-button>
</div> <el-button @click="toPreview(item.use_template)">{{ t('preview') }}</el-button>
</div> </div>
</div>
</div> </div>
</div> </div>
<el-dialog v-model="showDialog" :title="t('changeTemplate')" width="400px" :close-on-press-escape="false" <el-dialog v-model="showDialog" :title="t('changeTemplate')" width="400px" :close-on-press-escape="false"
:destroy-on-close="true" :close-on-click-modal="false"> :destroy-on-close="true" :close-on-click-modal="false">
<el-form :model="form" label-width="0px" v-if="formData.type"> <el-form :model="form" label-width="0px" v-if="formData.type">
<el-form-item label=""> <el-form-item label="">
<div>{{t('hopeBeforeTip')}}<span class="text-primary px-[5px]">{{ page[formData.type].title }}</span>{{t('hopeAfterTip')}} <div>{{ t('hopeBeforeTip') }}<span class="text-primary px-[5px]">{{ page[formData.type].title
</div> }}</span>{{ t('hopeAfterTip') }}
</el-form-item> </div>
</el-form-item>
<el-form-item label=""> <el-form-item label="">
<el-select v-model="hope" class="w-full"> <el-select v-model="hope" class="w-full">
<el-option :label="t('changeTemplateTip') + ' ' + page[formData.type].title + ' ' + t('template')" <el-option :label="t('changeTemplateTip') + ' ' + page[formData.type].title + ' ' + t('template')"
value="template"/> value="template" />
<el-option :label="t('changeMyPageTip') + ' ' + page[formData.type].title" value="diy"/> <el-option :label="t('changeMyPageTip') + ' ' + page[formData.type].title" value="diy" />
<el-option :label="t('changeOtherPageTip') + ' ' + page[formData.type].title" value="other"/> <el-option :label="t('changeOtherPageTip') + ' ' + page[formData.type].title" value="other" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="" v-show="hope == 'template'"> <el-form-item label="" v-show="hope == 'template'">
<el-select v-model="formData.template" class="w-full"> <el-select v-model="formData.template" class="w-full">
<el-option v-for="(item, key) in page[formData.type].template" :label="item.title" :value="key"/> <el-option v-for="(item, key) in page[formData.type].template" :label="item.title" :value="key" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="" v-show="hope == 'diy'"> <el-form-item label="" v-show="hope == 'diy'">
<el-select v-model="formData.id" class="w-full"> <el-select v-model="formData.id" class="w-full">
<el-option v-for="(item, index) in page[formData.type].my_page" :label="item.title" <el-option v-for="(item, index) in page[formData.type].my_page" :label="item.title" :value="item.id" :key="index" />
:value="item.id"/> </el-select>
</el-select> <div class="mt-[10px]">
<div class="mt-[10px]"> <span class="cursor-pointer text-primary mr-[10px]" @click="toDiyList">{{ t('createPage') }}</span>
<span class="cursor-pointer text-primary mr-[10px]" @click="toDiyList">{{ t('createPage') }}</span> <span class="cursor-pointer text-primary" @click="refreshMyPage">{{ t('refreshPage') }}</span>
<span class="cursor-pointer text-primary" @click="refreshMyPage">{{ t('refreshPage') }}</span> </div>
</div> </el-form-item>
</el-form-item>
<el-form-item label="" v-show="hope == 'other'"> <el-form-item label="" v-show="hope == 'other'">
<el-select v-model="formData.page" class="w-full"> <el-select v-model="formData.page" class="w-full">
<el-option v-for="(item, index) in page[formData.type].other_page" :label="item.title" <el-option v-for="(item, index) in page[formData.type].other_page" :label="item.title"
:value="item.page"/> :value="item.page" :key="index" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel')}}</el-button>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {reactive, ref, watch} from 'vue' import { reactive, ref, watch } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import {useRouter} from 'vue-router' import { useRouter } from 'vue-router'
import {ElMessage} from 'element-plus' import { ElMessage } from 'element-plus'
import {getDecoratePage, getDiyList, changeTemplate} from '@/app/api/diy' import { getDecoratePage, getDiyList, changeTemplate } from '@/app/api/diy'
import storage from '@/utils/storage' import storage from '@/utils/storage'
const page: any = reactive({}) const page: any = reactive({})
const showDialog = ref(false) const showDialog = ref(false)
const router = useRouter() const router = useRouter()
const hope = ref('template') const hope = ref('template')
const wapDomain = ref('') const wapDomain = ref('')
// //
const formData = reactive({ const formData = reactive({
type: '', type: '',
name: '', name: '',
mode: '', mode: '',
template: '', template: '',
id: '', id: '',
page: '', page: '',
title: '', title: '',
action: '' action: ''
}) })
// //
const refreshData = () => { const refreshData = () => {
formData.type = ''; formData.type = ''
formData.name = ''; formData.name = ''
formData.mode = ''; formData.mode = ''
formData.template = ''; formData.template = ''
formData.id = ''; formData.id = ''
formData.page = ''; formData.page = ''
formData.title = ''; formData.title = ''
formData.action = ''; formData.action = ''
getDecoratePage({}).then((res => { getDecoratePage({}).then(res => {
for (let key in res.data) { for (const key in res.data) {
page[key] = res.data[key] page[key] = res.data[key]
}
for (let key in page) {
if (page[key].use_template.url) {
page[key].loadingIframe = false; // iframe
page[key].loadingDev = false; //
page[key].isDisabledPop = false; //
page[key].difference = 0; // 1000wap
wapDomain.value = page[key].domain_url.wap_domain;
page[key].wapUrl = page[key].domain_url.wap_url;
if (import.meta.env.MODE == 'development') {
// wap
if (wapDomain.value) {
page[key].wapUrl = wapDomain.value + '/wap';
setDomain(key);
}
if (storage.get('wap_domain')) {
page[key].wapUrl = storage.get('wap_domain')
setDomain(key);
}
}
setDomain(key);
}
}
}));
}
refreshData();
// uni-app
window.addEventListener('message', (event) => {
try {
let data = JSON.parse(event.data);
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
for (let key in page) {
page[key].loadingDev = false; //
page[key].loadingIframe = true; // iframe
var loadTime = new Date().getTime();
page[key].difference = loadTime - page[key].timeIframe;
page[key].isDisabledPop = false; //
}
}
} catch (e) {
for (let key in page) {
initLoad(key);
}
console.log('后台接受数据错误', e)
} }
}, false);
// uniapp for (const key in page) {
const postMessage = (key: string) => { if (page[key].use_template.url) {
var diyData = JSON.stringify({ page[key].loadingIframe = false // iframe
type: 'appOnReady', page[key].loadingDev = false //
message: '加载完成' page[key].isDisabledPop = false //
}); page[key].difference = 0 // 1000wap
if (window['previewIframe_' + key]) window['previewIframe_' + key].contentWindow.postMessage(diyData, '*');
};
// wapDomain.value = page[key].domain_url.wap_domain
const initLoad = (key: string) => { page[key].wapUrl = page[key].domain_url.wap_url
page[key].loadingDev = true;
page[key].isDisabledPop = true; if (import.meta.env.MODE == 'development') {
page[key].loadingIframe = false; // wap
if (wapDomain.value) {
page[key].wapUrl = wapDomain.value + '/wap'
setDomain(key)
}
if (storage.get('wap_domain')) {
page[key].wapUrl = storage.get('wap_domain')
setDomain(key)
}
}
setDomain(key)
}
}
})
}
refreshData()
// uni-app
window.addEventListener('message', (event) => {
try {
const data = JSON.parse(event.data)
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
for (const key in page) {
page[key].loadingDev = false //
page[key].loadingIframe = true // iframe
const loadTime = new Date().getTime()
page[key].difference = loadTime - page[key].timeIframe
page[key].isDisabledPop = false //
}
}
} catch (e) {
for (const key in page) {
initLoad(key)
}
console.log('后台接受数据错误', e)
} }
}, false)
const saveDomain = () => { // uniapp
if (wapDomain.value.trim().length == 0) { const postMessage = (key: string) => {
const diyData = JSON.stringify({
type: 'appOnReady',
message: '加载完成'
})
if (window['previewIframe_' + key]) window['previewIframe_' + key].contentWindow.postMessage(diyData, '*')
}
//
const initLoad = (key: string) => {
page[key].loadingDev = true
page[key].isDisabledPop = true
page[key].loadingIframe = false
}
const saveDomain = () => {
if (wapDomain.value.trim().length == 0) {
ElMessage({
type: 'warning',
message: `${t('wapDomainPlaceholder')}`,
})
return
}
const wapUrl = wapDomain.value + '/wap'
storage.set({ key: 'wap_domain', data: wapUrl })
for (const key in page) {
if (page[key].use_template.url) {
page[key].wapUrl = wapUrl
setDomain(key)
}
}
setTimeout(() => {
for (const key in page) {
if (page[key].use_template.url) {
page[key].loadingIframe = true // iframe
page[key].loadingDev = false //
page[key].isDisabledPop = false //
}
}
}, 100 * 3)
}
const settingTips = () => {
window.open('https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213393')
}
const setDomain = (key: string) => {
page[key].use_template.wapPreview = page[key].wapUrl + page[key].use_template.url
page[key].timeIframe = new Date().getTime()
postMessage(key)
setTimeout(() => {
if (page[key].difference == 0) initLoad(key)
}, 1000 * 2)
}
const show = (key: string, data: any) => {
//
showDialog.value = true
hope.value = data.use_template.hope
formData.type = key
formData.name = data.use_template.name
formData.mode = data.use_template.mode
formData.action = data.use_template.action
if (hope.value == 'template') {
formData.template = data.use_template.template
} else if (hope.value == 'diy') {
formData.id = data.use_template.id
} else if (hope.value == 'other') {
formData.page = data.use_template.page
formData.title = data.use_template.title
}
}
//
const toDecorate = (data: any) => {
const query: any = {
back: '/site/diy/index'
}
if (data.id) {
query.id = data.id
} else if (data.name) {
query.name = data.name
} else if (data.url) {
query.url = data.url
}
const url = router.resolve({
path: '/decorate/edit',
query
})
window.open(url.href)
}
//
const toPreview = (data: any) => {
let page = data.page
if (data.url) {
page = data.url
} else if (data.id) {
page += '?id=' + data.id
}
const url = router.resolve({
path: '/preview/wap',
query: {
page
}
})
window.open(url.href)
}
//
const toDiyList = (data: any) => {
const url = router.resolve({
path: '/diy/list'
})
window.open(url.href)
}
//
const refreshMyPage = () => {
getDiyList({ type: formData.type }).then((res) => {
let isExist = true //
for (let i = 0; i < res.data.length; i++) {
if (formData.id == res.data[i].id) {
isExist = false
break
}
}
if (isExist) {
formData.id = ''
}
page[formData.type].my_page = {}
Object.assign(page[formData.type].my_page, res.data)
})
}
watch(
() => hope.value,
(newValue, oldValue) => {
//
if (newValue == 'template') {
//
formData.id = ''
formData.page = ''
formData.action = 'decorate'
formData.name = formData.type
} else if (newValue == 'diy') {
//
formData.mode = 'diy'
formData.template = ''
formData.page = ''
formData.action = 'decorate'
formData.name = formData.type
} else if (newValue == 'other') {
//
formData.mode = 'other'
formData.template = ''
formData.id = ''
}
}
)
//
watch(
() => formData.template,
(newValue, oldValue) => {
if (newValue) {
formData.mode = page[formData.type].template[newValue].mode
}
}
)
//
watch(
() => formData.page,
(newValue, oldValue) => {
if (newValue) {
for (let i = 0; i < page[formData.type].other_page.length; i++) {
if (page[formData.type].other_page[i].page == newValue) {
formData.name = page[formData.type].other_page[i].name
formData.title = page[formData.type].other_page[i].title
formData.action = page[formData.type].other_page[i].action
break
}
}
}
}
)
const isRepeat = ref(false)
const save = () => {
if (hope.value == 'template') {
if (formData.template == '') {
ElMessage({ ElMessage({
type: 'warning', type: 'warning',
message: `${t('wapDomainPlaceholder')}`, message: `${t('placeholderTemplate')}`
}); })
return; return
} }
let wapUrl = wapDomain.value + '/wap'; } else if (hope.value == 'diy') {
storage.set({key: 'wap_domain', data: wapUrl}); if (formData.id == '') {
ElMessage({
for (let key in page) { type: 'warning',
if (page[key].use_template.url) { message: `${t('placeholderMyPage')}`
page[key].wapUrl = wapUrl; })
setDomain(key); return
}
} }
setTimeout(() => { } else if (hope.value == 'other') {
for (let key in page) { if (formData.page == '') {
if (page[key].use_template.url) { ElMessage({
page[key].loadingIframe = true; // iframe type: 'warning',
page[key].loadingDev = false; // message: `${t('placeholderOtherPage')}`
page[key].isDisabledPop = false; // })
} return
}
}, 100 * 3);
}
const settingTips = () => {
window.open('https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213393')
}
const setDomain = (key: string) => {
page[key].use_template.wapPreview = page[key].wapUrl + page[key].use_template.url;
page[key].timeIframe = new Date().getTime();
postMessage(key);
setTimeout(() => {
if (page[key].difference == 0) initLoad(key);
}, 1000 * 2);
}
const show = (key: string, data: any) => {
//
showDialog.value = true;
hope.value = data.use_template.hope;
formData.type = key;
formData.name = data.use_template.name;
formData.mode = data.use_template.mode;
formData.action = data.use_template.action;
if (hope.value == 'template') {
formData.template = data.use_template.template;
} else if (hope.value == 'diy') {
formData.id = data.use_template.id;
} else if (hope.value == 'other') {
formData.page = data.use_template.page;
formData.title = data.use_template.title;
} }
} }
// if (isRepeat.value) return
const toDecorate = (data: any) => { isRepeat.value = true
let query: any = {
back: '/site/diy/index'
};
if (data.id) {
query.id = data.id;
} else if (data.name) {
query.name = data.name;
} else if (data.url) {
query.url = data.url;
}
let url = router.resolve({
path: '/decorate/edit',
query
});
window.open(url.href);
}
// changeTemplate({
const toPreview = (data: any) => { ...formData
let page = data.page; }).then((res) => {
if (data.url) { isRepeat.value = false
page = data.url; showDialog.value = false
} else if (data.id) { refreshData()
page += '?id=' + data.id; })
} }
let url = router.resolve({
path: '/preview/wap',
query: {
page
}
});
window.open(url.href);
}
//
const toDiyList = (data: any) => {
let url = router.resolve({
path: '/diy/list'
});
window.open(url.href);
}
//
const refreshMyPage = () => {
getDiyList({type: formData.type}).then((res) => {
let isExist = true; //
for (let i = 0; i < res.data.length; i++) {
if (formData.id == res.data[i].id) {
isExist = false;
break;
}
}
if (isExist) {
formData.id = '';
}
page[formData.type].my_page = {};
Object.assign(page[formData.type].my_page, res.data);
})
}
watch(
() => hope.value,
(newValue, oldValue) => {
//
if (newValue == 'template') {
//
formData.id = '';
formData.page = '';
formData.action = 'decorate';
formData.name = formData.type;
} else if (newValue == 'diy') {
//
formData.mode = 'diy';
formData.template = '';
formData.page = '';
formData.action = 'decorate';
formData.name = formData.type;
} else if (newValue == 'other') {
//
formData.mode = 'other';
formData.template = '';
formData.id = '';
}
}
)
//
watch(
() => formData.template,
(newValue, oldValue) => {
if (newValue) {
formData.mode = page[formData.type].template[newValue].mode;
}
}
)
//
watch(
() => formData.page,
(newValue, oldValue) => {
if (newValue) {
for (let i = 0; i < page[formData.type].other_page.length; i++) {
if (page[formData.type].other_page[i].page == newValue) {
formData.name = page[formData.type].other_page[i].name;
formData.title = page[formData.type].other_page[i].title;
formData.action = page[formData.type].other_page[i].action;
break;
}
}
}
}
)
const isRepeat = ref(false)
const save = () => {
if (hope.value == 'template') {
if (formData.template == '') {
ElMessage({
type: 'warning',
message: `${t('placeholderTemplate')}`,
});
return;
}
} else if (hope.value == 'diy') {
if (formData.id == '') {
ElMessage({
type: 'warning',
message: `${t('placeholderMyPage')}`,
});
return;
}
} else if (hope.value == 'other') {
if (formData.page == '') {
ElMessage({
type: 'warning',
message: `${t('placeholderOtherPage')}`,
});
return;
}
}
if (isRepeat.value) return
isRepeat.value = true
changeTemplate({
...formData
}).then((res) => {
isRepeat.value = false;
showDialog.value = false;
refreshData();
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.page-item { .page-item {
background-image: url(@/app/assets/images/iphone_bg.png); background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color); background-color: var(--el-bg-color);
background-size: 100%; background-size: 100%;
.item-hide { .item-hide {
display: none; display: none;
.item-btn-box { .item-btn-box {
button { button {
height: 35px; height: 35px;
width: 100px; width: 100px;
& ~ button { &~button {
margin-top: 15px; margin-top: 15px;
margin-left: 0; margin-left: 0;
} }
} }
} }
} }
&:hover { &:hover {
.item-hide:not(.disabled) { .item-hide:not(.disabled) {
display: block !important; display: block !important;
} }
} }
} }
</style> </style>

View File

@ -1,338 +1,337 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true"> <el-button type="primary" class="w-[100px]" @click="dialogVisible = true">
{{ t('addDiyPage') }} {{ t('addDiyPage') }}
</el-button> </el-button>
</div> </div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="diyPageTableData.searchParam" ref="searchFormDiyPageRef"> <el-form :inline="true" :model="diyPageTableData.searchParam" ref="searchFormDiyPageRef">
<el-form-item :label="t('title')" prop="title"> <el-form-item :label="t('title')" prop="title">
<el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')"/> <el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('typeName')" prop="type"> <el-form-item :label="t('typeName')" prop="type">
<el-select v-model="diyPageTableData.searchParam.type" :placeholder="t('pageTypePlaceholder')"> <el-select v-model="diyPageTableData.searchParam.type" :placeholder="t('pageTypePlaceholder')">
<el-option :label="t('all')" value=""/> <el-option :label="t('all')" value="" />
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key"/> <el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadDiyPageList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadDiyPageList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormDiyPageRef)">{{ t('reset') }}</el-button> <el-button @click="resetForm(searchFormDiyPageRef)">{{ t('reset') }}</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<el-table :data="diyPageTableData.data" size="large" v-loading="diyPageTableData.loading"> <el-table :data="diyPageTableData.data" size="large" v-loading="diyPageTableData.loading">
<template #empty> <template #empty>
<span>{{ !diyPageTableData.loading ? t('emptyData') : '' }}</span> <span>{{ !diyPageTableData.loading ? t('emptyData') : '' }}</span>
</template> </template>
<el-table-column prop="title" :label="t('title')" min-width="120"/> <el-table-column prop="title" :label="t('title')" min-width="120" />
<el-table-column prop="type_name" :label="t('typeName')" min-width="80"/> <el-table-column prop="type_name" :label="t('typeName')" min-width="80" />
<!-- <el-table-column :label="t('status')" min-width="80">--> <!-- <el-table-column :label="t('status')" min-width="80">-->
<!-- <template #default="{ row }">--> <!-- <template #default="{ row }">-->
<!-- <span v-if="row.type == 'DIY_PAGE'">-</span>--> <!-- <span v-if="row.type == 'DIY_PAGE'">-</span>-->
<!-- <template v-else>--> <!-- <template v-else>-->
<!-- <span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>--> <!-- <span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>-->
<!-- <span v-else>{{ t('unused') }}</span>--> <!-- <span v-else>{{ t('unused') }}</span>-->
<!-- </template>--> <!-- </template>-->
<!-- </template>--> <!-- </template>-->
<!-- </el-table-column>--> <!-- </el-table-column>-->
<el-table-column prop="update_time" :label="t('updateTime')" min-width="120"/> <el-table-column prop="update_time" :label="t('updateTime')" min-width="120" />
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160"> <el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="toPreview(row)">{{ t('promote') }}</el-button> <el-button type="primary" link @click="toPreview(row)">{{ t('promote') }}</el-button>
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{ <el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{
t('shareSet') }} t('shareSet') }}
</el-button> </el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<!-- <el-button v-if="row.type == 'DIY_PAGE' || row.is_default == 0" type="danger" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>--> <!-- <el-button v-if="row.type == 'DIY_PAGE' || row.is_default == 0" type="danger" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>-->
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="diyPageTableData.page" v-model:page-size="diyPageTableData.limit" <el-pagination v-model:current-page="diyPageTableData.page" v-model:page-size="diyPageTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="diyPageTableData.total" layout="total, sizes, prev, pager, next, jumper" :total="diyPageTableData.total"
@size-change="loadDiyPageList()" @current-change="loadDiyPageList"/> @size-change="loadDiyPageList()" @current-change="loadDiyPageList" />
</div> </div>
</el-card> </el-card>
<!--添加页面--> <!--添加页面-->
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="25%"> <el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="25%">
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules"> <el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
<el-form-item :label="t('title')" prop="title"> <el-form-item :label="t('title')" prop="title">
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" <el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12"
show-word-limit class="w-full"/> show-word-limit class="w-full" />
</el-form-item> </el-form-item>
<el-form-item :label="t('addType')" prop="type"> <el-form-item :label="t('addType')" prop="type">
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="w-full"> <el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="w-full">
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key"/> <el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('templateName')" prop="template" v-show="pageTypeData"> <el-form-item :label="t('templateName')" prop="template" v-show="pageTypeData">
<el-select v-model="formData.template" class="w-full"> <el-select v-model="formData.template" class="w-full">
<el-option :label="t('emptyTemplate')" value=""/> <el-option :label="t('emptyTemplate')" value="" />
<el-option v-for="(item, key) in pageTypeData" :label="item.title" :value="key"/> <el-option v-for="(item, key) in pageTypeData" :label="item.title" :value="key" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button> <el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="addEvent(formRef)">{{ t('confirm') }}</el-button> <el-button type="primary" @click="addEvent(formRef)">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 分享设置--> <!-- 分享设置-->
<el-dialog v-model="shareDialogVisible" :title="t('shareSet')" width="30%"> <el-dialog v-model="shareDialogVisible" :title="t('shareSet')" width="30%">
<el-tabs v-model="tabShareType"> <el-tabs v-model="tabShareType">
<el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane> <el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane>
<el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane> <el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane>
</el-tabs> </el-tabs>
<el-form :model="shareFormData[tabShareType]" label-width="90px" ref="shareFormRef" :rules="shareFormRules"> <el-form :model="shareFormData[tabShareType]" label-width="90px" ref="shareFormRef" :rules="shareFormRules">
<el-form-item :label="t('sharePage')"> <el-form-item :label="t('sharePage')">
<span>{{ sharePage }}</span> <span>{{ sharePage }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="t('shareTitle')" prop="title"> <el-form-item :label="t('shareTitle')" prop="title">
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" <el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')"
clearable maxlength="30" show-word-limit/> clearable maxlength="30" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'"> <el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" <el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')"
type="textarea" rows="4" clearable maxlength="100" show-word-limit/> type="textarea" rows="4" clearable maxlength="100" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item :label="t('shareImageUrl')" prop="url"> <el-form-item :label="t('shareImageUrl')" prop="url">
<upload-image v-model="shareFormData[tabShareType].url" :limit="1"/> <upload-image v-model="shareFormData[tabShareType].url" :limit="1" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="shareDialogVisible = false">{{ t('cancel') }}</el-button> <el-button @click="shareDialogVisible = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="shareEvent(shareFormRef)">{{ t('confirm') }}</el-button> <el-button type="primary" @click="shareEvent(shareFormRef)">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {reactive, ref, computed} from 'vue' import { reactive, ref, computed } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import {getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare} from '@/app/api/diy' import { getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare } from '@/app/api/diy'
import {ElMessageBox, FormInstance} from 'element-plus' import { ElMessageBox, FormInstance } from 'element-plus'
import {useRoute, useRouter} from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import {getUrl} from '@/app/api/sys' import { getUrl } from '@/app/api/sys'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
const pageType: any = reactive({}) // const pageType: any = reactive({}) //
// //
const formData = reactive({ const formData = reactive({
title: '',
type: '',
template: ''
})
//
const formRules = computed(() => {
return {
title: [
{ required: true, message: t('titlePlaceholder'), trigger: 'blur' }
],
type: [
{ required: true, message: t('pageTypePlaceholder'), trigger: 'blur' }
]
}
})
const pageTypeData = computed(() => {
let data: any = ''
formData.template = ''
if (formData.type) {
data = pageType[formData.type].template
}
return data
})
const formRef = ref<FormInstance>()
const dialogVisible = ref(false)
const addEvent = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
dialogVisible.value = false
let url = `/decorate/edit?type=${formData.type}&title=${formData.title}`
if (formData.template) url += `&template=${formData.template}`
router.push(url)
}
})
}
const wapDomain = ref('')
const getDomain = async () => {
wapDomain.value = (await getUrl()).data.wap_url
}
getDomain()
//
getDiyTemplate({ mode: '' }).then(res => {
for (const key in res.data) {
pageType[key] = res.data[key]
}
})
const diyPageTableData: any = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
title: '', title: '',
type: '', type: '',
template: '' mode: ''
})
//
const formRules = computed(() => {
return {
title: [
{required: true, message: t('titlePlaceholder'), trigger: 'blur'},
],
type: [
{required: true, message: t('pageTypePlaceholder'), trigger: 'blur'},
]
}
})
const pageTypeData = computed(() => {
let data: any = '';
formData.template = '';
if (formData.type) {
data = pageType[formData.type].template;
}
return data;
})
const formRef = ref<FormInstance>()
const dialogVisible = ref(false)
const addEvent = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
dialogVisible.value = false;
let url = `/decorate/edit?type=${formData.type}&title=${formData.title}`;
if (formData.template) url += `&template=${formData.template}`;
router.push(url);
}
})
} }
})
const wapDomain = ref('') const searchFormDiyPageRef = ref<FormInstance>()
const getDomain = async () => {
wapDomain.value = (await getUrl()).data.wap_url;
};
getDomain();
// //
getDiyTemplate({mode: ''}).then(res => { const loadDiyPageList = (page: number = 1) => {
for (let key in res.data) { diyPageTableData.loading = true
pageType[key] = res.data[key] diyPageTableData.page = page
}
getDiyPageList({
page: diyPageTableData.page,
limit: diyPageTableData.limit,
...diyPageTableData.searchParam
}).then(res => {
diyPageTableData.loading = false
diyPageTableData.data = res.data.data
diyPageTableData.total = res.data.total
}).catch(() => {
diyPageTableData.loading = false
}) })
}
let diyPageTableData: any = reactive({ loadDiyPageList()
page: 1,
limit: 10, //
total: 0, const editEvent = (data: any) => {
loading: true, const url = router.resolve({
data: [], path: '/decorate/edit',
searchParam: { query: { id: data.id }
"title": "",
"type": '',
'mode': ''
}
}) })
window.open(url.href)
}
const searchFormDiyPageRef = ref<FormInstance>() //
const deleteEvent = (id: number) => {
// ElMessageBox.confirm(t('diyPageDeleteTips'), t('warning'),
const loadDiyPageList = (page: number = 1) => { {
diyPageTableData.loading = true confirmButtonText: t('confirm'),
diyPageTableData.page = page cancelButtonText: t('cancel'),
type: 'warning'
getDiyPageList({ }
page: diyPageTableData.page, ).then(() => {
limit: diyPageTableData.limit, deleteDiyPage(id).then(() => {
...diyPageTableData.searchParam loadDiyPageList()
}).then(res => {
diyPageTableData.loading = false
diyPageTableData.data = res.data.data
diyPageTableData.total = res.data.total
}).catch(() => { }).catch(() => {
diyPageTableData.loading = false
}) })
})
}
//
const toPreview = (data: any) => {
const url = router.resolve({
path: '/preview/wap',
query: {
page: data.type_page + '?id=' + data.id
}
})
window.open(url.href)
}
const tabShareType = ref('wechat')
const sharePage = ref('')
const shareFormId = ref(0)
const shareFormData = reactive({
wechat: {
title: '',
desc: '',
url: ''
},
weapp: {
title: '',
url: ''
}
})
const shareDialogVisible = ref(false)
const shareFormRules = computed(() => {
return {}
})
const shareFormRef = ref<FormInstance>()
const openShare = async (row: any) => {
shareFormId.value = row.id
sharePage.value = row.title
const share = row.share ? JSON.parse(row.share) : {
wechat: { title: '', desc: '', url: '' },
weapp: { title: '', url: '' }
}
if (share) {
shareFormData.wechat = share.wechat
shareFormData.weapp = share.weapp
} }
loadDiyPageList() shareDialogVisible.value = true
}
// const shareEvent = async (formEl: FormInstance | undefined) => {
const editEvent = (data: any) => { if (!formEl) return
let url = router.resolve({
path: '/decorate/edit',
query: {id: data.id}
});
window.open(url.href);
}
// await formEl.validate(async (valid) => {
const deleteEvent = (id: number) => { if (valid) {
ElMessageBox.confirm(t('diyPageDeleteTips'), t('warning'), editDiyPageShare({
{ id: shareFormId.value,
confirmButtonText: t('confirm'), share: JSON.stringify(shareFormData)
cancelButtonText: t('cancel'), }).then(() => {
type: 'warning',
}
).then(() => {
deleteDiyPage(id).then(() => {
loadDiyPageList() loadDiyPageList()
shareDialogVisible.value = false
}).catch(() => { }).catch(() => {
}) })
})
}
//
const toPreview = (data: any) => {
let url = router.resolve({
path: '/preview/wap',
query: {
page: data.type_page + '?id=' + data.id
}
});
window.open(url.href);
}
const tabShareType = ref('wechat')
const sharePage = ref('')
const shareFormId = ref(0)
const shareFormData = reactive({
wechat: {
title: '',
desc: '',
url: ''
},
weapp: {
title: '',
url: ''
} }
}) })
const shareDialogVisible = ref(false) }
const shareFormRules = computed(() => {
return {}
})
const shareFormRef = ref<FormInstance>() const resetForm = (formEl: FormInstance | undefined) => {
const openShare = async (row: any) => { if (!formEl) return
shareFormId.value = row.id; formEl.resetFields()
sharePage.value = row.title; loadDiyPageList()
let share = row.share ? JSON.parse(row.share) : { }
wechat: {title: '', desc: '', url: ''},
weapp: {title: '', url: ''}
};
if (share) {
shareFormData.wechat = share.wechat;
shareFormData.weapp = share.weapp;
}
shareDialogVisible.value = true;
}
const shareEvent = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
editDiyPageShare({
id: shareFormId.value,
share: JSON.stringify(shareFormData),
}).then(() => {
loadDiyPageList()
shareDialogVisible.value = false;
}).catch(() => {
})
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields();
loadDiyPageList();
}
</script> </script>
<style lang="scss"> <style lang="scss">
.copy { .copy {
background: var(--el-color-primary) !important; background: var(--el-color-primary) !important;
color: var(--el-color-white) !important; color: var(--el-color-white) !important;
} }
</style> </style>
<style lang="scss" scoped></style>

View File

@ -53,140 +53,140 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, reactive, watch} from 'vue' import { ref, reactive, watch } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import {useRoute} from 'vue-router' import { useRoute } from 'vue-router'
import {getWeappConfig} from '@/app/api/weapp' import { getWeappConfig } from '@/app/api/weapp'
import {getUrl} from '@/app/api/sys' import { getUrl } from '@/app/api/sys'
import {useClipboard} from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import {ElMessage} from 'element-plus' import { ElMessage } from 'element-plus'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import QRCode from "qrcode"; import QRCode from 'qrcode'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import {getPreviewData} from '@/app/api/diy' import { getPreviewData } from '@/app/api/diy'
const wapUrl = ref('') const wapUrl = ref('')
const wapDomain = ref('') const wapDomain = ref('')
const wapImage = ref('') const wapImage = ref('')
const wapPreview = ref('') const wapPreview = ref('')
const loading = ref(false) const loading = ref(false)
const loadingIframe = ref(false) // iframe const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) // const loadingDev = ref(false) //
const timeFrame = ref(0) const timeFrame = ref(0)
var time = new Date().getTime(); let time = new Date().getTime()
const route = useRoute(); const route = useRoute()
route.query.id = route.query.id || 0; route.query.id = route.query.id || 0
route.query.name = route.query.name || ''; route.query.name = route.query.name || ''
getUrl().then((res: any) => { getUrl().then((res: any) => {
wapDomain.value = res.data.wap_domain; wapDomain.value = res.data.wap_domain
wapUrl.value = res.data.wap_url; wapUrl.value = res.data.wap_url
setDomain(); setDomain()
// //
if (import.meta.env.MODE == 'production') return; if (import.meta.env.MODE == 'production') return
// envwap // envwap
if (wapDomain.value) return; if (wapDomain.value) return
let wap_domain_storage = storage.get('wap_domain'); let wap_domain_storage = storage.get('wap_domain')
if (wap_domain_storage) { if (wap_domain_storage) {
wapUrl.value = wap_domain_storage wapUrl.value = wap_domain_storage
setDomain(); setDomain()
return; return
}
timeFrame.value = new Date().getTime();
});
const save = () => {
if (wapDomain.value.trim().length == 0) {
ElMessage({
type: 'warning',
message: `${t('wapDomainPlaceholder')}`,
});
return;
}
wapUrl.value = wapDomain.value + '/wap';
setDomain();
storage.set({key: 'wap_domain', data: wapUrl.value});
loadingIframe.value = true;
loadingDev.value = false;
} }
const setDomain = () => { timeFrame.value = new Date().getTime()
getPreviewData({ })
id: route.query.id,
name: route.query.name,
}).then((res: any) => {
let data = res.data;
wapPreview.value = `${wapUrl.value}/${data.page}`;
// id const save = () => {
if (import.meta.env.MODE == 'development') { if (wapDomain.value.trim().length == 0) {
let siteId = storage.get('siteId') || 0; ElMessage({
wapPreview.value += `&site_id=${siteId}`; type: 'warning',
} message: `${t('wapDomainPlaceholder')}`
QRCode.toDataURL(wapPreview.value, {errorCorrectionLevel: 'L', margin: 0, width: 100}).then(url => { })
wapImage.value = url return
}) }
wapUrl.value = wapDomain.value + '/wap'
setDomain()
storage.set({ key: 'wap_domain', data: wapUrl.value })
loadingIframe.value = true
loadingDev.value = false
}
const setDomain = () => {
getPreviewData({
id: route.query.id,
name: route.query.name
}).then((res: any) => {
const data = res.data
wapPreview.value = `${wapUrl.value}/${data.page}`
// id
if (import.meta.env.MODE == 'development') {
const siteId = storage.get('siteId') || 0
wapPreview.value += `&site_id=${siteId}`
}
QRCode.toDataURL(wapPreview.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
wapImage.value = url
})
})
}
// iframe
const loadIframe = () => {
if (!wapPreview.value) return
const loadTime = new Date().getTime()
const difference = loadTime - timeFrame.value
// 1000wap
if (difference < 1000) {
loadingDev.value = true
loadingIframe.value = false
wapPreview.value = ''
wapImage.value = ''
} else {
loadingDev.value = false
loadingIframe.value = true
}
loading.value = true
}
const weappConfig = reactive({
qr_code: ''
})
const previewMode = ref('weapp')
//
getWeappConfig().then((res: any) => {
if (res.code == 1) {
const data = res.data
weappConfig.qr_code = data.qr_code
}
})
//
const { copy, isSupported, copied } = useClipboard()
const copyEvent = (text: string) => {
if (!isSupported.value) {
ElMessage({
message: t('notSupportCopy'),
type: 'warning'
}) })
} }
copy(text)
}
// iframe watch(copied, () => {
const loadIframe = () => { if (copied.value) {
if (!wapPreview.value) return; ElMessage({
var loadTime = new Date().getTime(); message: t('copySuccess'),
var difference = loadTime - timeFrame.value; type: 'success'
// 1000wap })
if (difference < 1000) {
loadingDev.value = true;
loadingIframe.value = false;
wapPreview.value = '';
wapImage.value = '';
} else {
loadingDev.value = false;
loadingIframe.value = true;
}
loading.value = true
} }
})
const weappConfig = reactive({
qr_code: ''
})
const previewMode = ref('weapp')
//
getWeappConfig().then((res: any) => {
if (res.code == 1) {
let data = res.data;
weappConfig.qr_code = data.qr_code;
}
})
//
const {copy, isSupported, copied} = useClipboard()
const copyEvent = (text: string) => {
if (!isSupported.value) {
ElMessage({
message: t('notSupportCopy'),
type: 'warning'
})
}
copy(text)
}
watch(copied, () => {
if (copied.value) {
ElMessage({
message: t('copySuccess'),
type: 'success'
})
}
})
</script> </script>

View File

@ -16,7 +16,7 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<el-table :data="diyRouteTableData.data" size="large" v-loading="diyRouteTableData.loading"> <el-table :data="diyRouteTableData.data" size="large" v-loading="diyRouteTableData.loading">
<template #empty> <template #empty>
<span>{{ !diyRouteTableData.loading ? t('emptyData') : '' }}</span> <span>{{ !diyRouteTableData.loading ? t('emptyData') : '' }}</span>
@ -83,7 +83,7 @@
import { reactive, ref, watch, computed } from 'vue' import { reactive, ref, watch, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getDiyTemplate, getDiyRouteList, getDiyRouteInfo, editDiyRouteShare } from '@/app/api/diy' import { getDiyTemplate, getDiyRouteList, getDiyRouteInfo, editDiyRouteShare } from '@/app/api/diy'
import { ElMessage, FormInstance, ElMessageBox } from 'element-plus' import { ElMessage, FormInstance } from 'element-plus'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import { getUrl } from '@/app/api/sys' import { getUrl } from '@/app/api/sys'
@ -91,28 +91,28 @@ import { getUrl } from '@/app/api/sys'
const pageTemplate: any = reactive({}) const pageTemplate: any = reactive({})
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const dialogVisible = ref(false) const dialogVisible = ref(false)
let diyRouteTableData = reactive({ const diyRouteTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam: {
"title": "", title: ''
} }
}) })
const wapDomain = ref('') const wapDomain = ref('')
const getDomain = async () => { const getDomain = async () => {
wapDomain.value = (await getUrl()).data.wap_url; wapDomain.value = (await getUrl()).data.wap_url
}; }
getDomain(); getDomain()
/** /**
* 获取自定义路由列表 * 获取自定义路由列表
@ -126,15 +126,15 @@ const loadDiyRouteList = (page: number = 1) => {
limit: diyRouteTableData.limit, limit: diyRouteTableData.limit,
...diyRouteTableData.searchParam ...diyRouteTableData.searchParam
}).then(res => { }).then(res => {
diyRouteTableData.loading = false; diyRouteTableData.loading = false
let len = Math.ceil(res.data.length / diyRouteTableData.limit); const len = Math.ceil(res.data.length / diyRouteTableData.limit)
let data = JSON.parse(JSON.stringify(res.data)); const data = JSON.parse(JSON.stringify(res.data))
let dataGather = []; const dataGather = []
for(var i = 0; i < len; i++){ for (let i = 0; i < len; i++) {
dataGather[i] = data.splice(0, diyRouteTableData.limit); dataGather[i] = data.splice(0, diyRouteTableData.limit)
} }
diyRouteTableData.data = dataGather[diyRouteTableData.page-1]; diyRouteTableData.data = dataGather[diyRouteTableData.page - 1]
diyRouteTableData.total = res.data.length diyRouteTableData.total = res.data.length
}).catch(() => { }).catch(() => {
@ -145,7 +145,7 @@ loadDiyRouteList()
// //
getDiyTemplate({}).then(res => { getDiyTemplate({}).then(res => {
for (let key in res.data) { for (const key in res.data) {
pageTemplate[key] = res.data[key] pageTemplate[key] = res.data[key]
} }
}) })
@ -204,12 +204,12 @@ const shareFormRules = computed(() => {
const shareFormRef = ref<FormInstance>() const shareFormRef = ref<FormInstance>()
const openShare = async (row: any) => { const openShare = async (row: any) => {
// //
let info = (await getDiyRouteInfo({ const info = (await getDiyRouteInfo({
name: row.name name: row.name
})).data; })).data
if (info.title) { if (info.title) {
row.id = info.id; row.id = info.id
row.title = info.title row.title = info.title
row.name = info.name row.name = info.name
row.page = info.page row.page = info.page
@ -224,18 +224,18 @@ const openShare = async (row: any) => {
diyRouteData.is_share = row.is_share diyRouteData.is_share = row.is_share
diyRouteData.sort = row.sort diyRouteData.sort = row.sort
shareFormId.value = row.id; shareFormId.value = row.id
sharePage.value = row.title; sharePage.value = row.title
let share = row.share ? JSON.parse(row.share) : { const share = row.share ? JSON.parse(row.share) : {
wechat: {title: '', desc: '', url: ''}, wechat: { title: '', desc: '', url: '' },
weapp: {title: '', url: ''} weapp: { title: '', url: '' }
}; }
if (share) { if (share) {
shareFormData.wechat = share.wechat; shareFormData.wechat = share.wechat
shareFormData.weapp = share.weapp; shareFormData.weapp = share.weapp
} }
shareDialogVisible.value = true; shareDialogVisible.value = true
} }
const shareEvent = async (formEl: FormInstance | undefined) => { const shareEvent = async (formEl: FormInstance | undefined) => {
@ -243,24 +243,24 @@ const shareEvent = async (formEl: FormInstance | undefined) => {
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
let save = editDiyRouteShare const save = editDiyRouteShare
save({ save({
id: shareFormId.value, id: shareFormId.value,
share: JSON.stringify(shareFormData), share: JSON.stringify(shareFormData),
...diyRouteData ...diyRouteData
}).then(() => { }).then(() => {
loadDiyRouteList() loadDiyRouteList()
shareDialogVisible.value = false; shareDialogVisible.value = false
}).catch(() => { }).catch(() => {
}) })
} }
}) })
} }
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadDiyRouteList(); loadDiyRouteList()
} }
</script> </script>
@ -270,4 +270,4 @@ const resetForm = (formEl: FormInstance | undefined)=>{
color: var(--el-color-white) !important; color: var(--el-color-white) !important;
} }
</style> </style>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -2,18 +2,18 @@
<div class="error"> <div class="error">
<div class="flex items-center"> <div class="flex items-center">
<slot name="content"> <slot name="content">
<div> <div>
<img class="w-[300px]" src="@/app/assets/images/error.png"/> <img class="w-[300px]" src="@/app/assets/images/error.png" />
</div> </div>
</slot> </slot>
<div class="text-left ml-[100px]"> <div class="text-left ml-[100px]">
<div class="error-text text-[28px] font-bold">404错误</div> <div class="error-text text-[28px] font-bold">404错误</div>
<div class="text-[#222] text-[20px] mt-[15px]">哎呀出错了您访问的页面不存在...</div> <div class="text-[#222] text-[20px] mt-[15px]">哎呀出错了您访问的页面不存在...</div>
<div class="text-[#c4c2c2] text-[12px] mt-[5px]">尝试检查URL的错误然后点击浏览器刷新按钮</div> <div class="text-[#c4c2c2] text-[12px] mt-[5px]">尝试检查URL的错误然后点击浏览器刷新按钮</div>
<div class="mt-[40px]"> <div class="mt-[40px]">
<el-button class="bottom" @click="router.go(-1)">{{ second }} 秒后返回上一页</el-button> <el-button class="bottom" @click="router.go(-1)">{{ second }} 秒后返回上一页</el-button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -53,13 +53,15 @@ onUnmounted(() => {
@apply text-primary; @apply text-primary;
font-size: 150px; font-size: 150px;
} }
.error-text {
color:#0e77fd; .error-text {
} color: #0e77fd;
}
.el-button { .el-button {
width: 176px; width: 176px;
background-color: #0e77fd; background-color: #0e77fd;
color:#fff color: #fff
} }
} }
</style> </style>

View File

@ -1,230 +1,196 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card">
<el-statistic :value="accountStat.pay ? Number.parseFloat(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]"> <el-col :span="8" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="accountStat.refund ? Number.parseFloat(accountStat.refund).toFixed(2) : '0.00'"></el-statistic> <el-statistic
<div class="statistic-footer"> :value="accountStat.pay ? accountStat.pay.toFixed(2) : '0.00'"></el-statistic>
<div class="footer-item text-[14px] text-[#666]"> <div class="statistic-footer">
<span>{{ t('totalRefund') }}</span> <div class="footer-item text-[14px] text-[#666]">
</div> <span>{{ t('totalPay') }}</span>
</div> </div>
</div> </div>
</el-col> </div>
<el-col :span="8" class="min-w-[100px]"> </el-col>
<el-col :span="8" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="accountStat.transfer ? Number.parseFloat(accountStat.transfer).toFixed(2) : '0.00'"></el-statistic> <el-statistic
<div class="statistic-footer"> :value="accountStat.refund ? accountStat.refund.toFixed(2) : '0.00'"></el-statistic>
<div class="footer-item text-[14px] text-[#666]"> <div class="statistic-footer">
<span>{{ t('totalTransfer') }}</span> <div class="footer-item text-[14px] text-[#666]">
</div> <span>{{ t('totalRefund') }}</span>
</div> </div>
</div> </div>
</el-col> </div>
</el-row> </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>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never"> <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 :inline="true" :model="siteAccountLogTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('type')" class="items-center"> <el-form-item :label="t('type')" class="items-center">
<el-select v-model="siteAccountLogTable.searchParam.type" class="m-2" :placeholder="t('accountType')" > <el-select v-model="siteAccountLogTable.searchParam.type" class="m-2"
<el-option :placeholder="t('accountType')">
v-for="(item, index) in accountType" <el-option v-for="(item, index) in accountType" :key="index" :label="item" :value="index" />
:key="index"
:label="item"
:value="index"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('tradeNo')" prop="trade_no"> <el-form-item :label="t('tradeNo')" prop="trade_no">
<el-input v-model="siteAccountLogTable.searchParam.trade_no" :placeholder="t('tradeNoPlaceholder')" /> <el-input v-model="siteAccountLogTable.searchParam.trade_no"
</el-form-item> :placeholder="t('tradeNoPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="siteAccountLogTable.searchParam.create_time" type="datetimerange" <el-date-picker v-model="siteAccountLogTable.searchParam.create_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" /> :end-placeholder="t('endDate')" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadSiteAccountLogList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadSiteAccountLogList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button> <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<div class="mt-[10px]"> <div class="mt-[10px]">
<el-table :data="siteAccountLogTable.data" size="large" v-loading="siteAccountLogTable.loading"> <el-table :data="siteAccountLogTable.data" size="large" v-loading="siteAccountLogTable.loading">
<template #empty> <template #empty>
<span>{{ !siteAccountLogTable.loading ? t('emptyData') : '' }}</span> <span>{{ !siteAccountLogTable.loading ? t('emptyData') : '' }}</span>
</template> </template>
<el-table-column prop="trade_no" :label="t('tradeNo')" min-width="120" /> <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="type_name" :label="t('type')" min-width="120" />
<el-table-column prop="money" :label="t('money')" min-width="120" align="right" /> <el-table-column prop="money" :label="t('money')" min-width="120" align="right" />
<el-table-column :label="t('createTime')" min-width="150" align="center"> <el-table-column :label="t('createTime')" min-width="150" align="center">
<template #default="{ row }"> <template #default="{ row }">
{{ row.create_time || '' }} {{ row.create_time || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right" min-width="120"> <el-table-column :label="t('operation')" align="right" fixed="right" min-width="120">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button> <el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="siteAccountLogTable.page" v-model:page-size="siteAccountLogTable.limit" <el-pagination v-model:current-page="siteAccountLogTable.page"
layout="total, sizes, prev, pager, next, jumper" :total="siteAccountLogTable.total" v-model:page-size="siteAccountLogTable.limit" layout="total, sizes, prev, pager, next, jumper"
@size-change="loadSiteAccountLogList()" @current-change="loadSiteAccountLogList" /> :total="siteAccountLogTable.total" @size-change="loadSiteAccountLogList()"
</div> @current-change="loadSiteAccountLogList" />
</div> </div>
</el-card> </div>
</el-card>
<el-dialog v-model="showDialog" :title="t('accountDetail')" width="550px" :destroy-on-close="true"> <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 :model="formData" label-width="110px" ref="formRef" class="page-form">
<el-form-item :label="t('tradeNo')" > <el-form-item :label="t('tradeNo')">
<div class="input-width"> {{ formData.trade_no }} </div> <div class="input-width"> {{ formData.trade_no }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('type')" > <el-form-item :label="t('type')">
<div class="input-width"> {{ formData.type_name }} </div> <div class="input-width"> {{ formData.type_name }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('money')" > <el-form-item :label="t('money')">
<div class="input-width"> {{ formData.money }} </div> <div class="input-width"> {{ formData.money }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" > <el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.create_time }} </div> <div class="input-width"> {{ formData.create_time }} </div>
</el-form-item> </el-form-item>
<div v-if="formData.type == 'transfer'"> <div v-if="formData.type == 'transfer'">
<el-form-item :label="t('transferNo')" > <el-form-item :label="t('transferNo')">
<div class="input-width"> {{ formData.pay_info.transfer_no }} </div> <div class="input-width"> {{ formData.pay_info.transfer_no }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('transferTime')" > <el-form-item :label="t('transferTime')">
<div class="input-width"> {{ formData.pay_info.transfer_time }} </div> <div class="input-width"> {{ formData.pay_info.transfer_time }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('transferType')" > <el-form-item :label="t('transferType')">
<div class="input-width"> {{ formData.pay_info.transfer_type }} </div> <div class="input-width"> {{ formData.pay_info.transfer_type }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('transferMoney')" > <el-form-item :label="t('transferMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div> <div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('transferRemark')" > <el-form-item :label="t('transferRemark')">
<div class="input-width"> {{ formData.pay_info.remark }} </div> <div class="input-width"> {{ formData.pay_info.remark }} </div>
</el-form-item> </el-form-item>
</div> </div>
<div v-if="formData.type == 'refund'"> <div v-if="formData.type == 'refund'">
<el-form-item :label="t('outTradeNo')" > <el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div> <div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" > <el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div> <div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('refundMoney')" > <el-form-item :label="t('refundMoney')">
<div class="input-width"> {{ formData.pay_info.money }} </div> <div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('failReason')" > <el-form-item :label="t('failReason')">
<div class="input-width"> {{ formData.pay_info.fail_reason }} </div> <div class="input-width"> {{ formData.pay_info.fail_reason }} </div>
</el-form-item> </el-form-item>
</div> </div>
<div v-if="formData.type == 'pay'"> <div v-if="formData.type == 'pay'">
<el-form-item :label="t('outTradeNo')" > <el-form-item :label="t('outTradeNo')">
<div class="input-width"> {{ formData.pay_info.out_trade_no }} </div> <div class="input-width"> {{ formData.pay_info.out_trade_no }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" > <el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.pay_info.create_time }} </div> <div class="input-width"> {{ formData.pay_info.create_time }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('money')" > <el-form-item :label="t('money')">
<div class="input-width"> {{ formData.pay_info.money }} </div> <div class="input-width"> {{ formData.pay_info.money }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('body')" > <el-form-item :label="t('body')">
<div class="input-width"> {{ formData.pay_info.body }} </div> <div class="input-width"> {{ formData.pay_info.body }} </div>
</el-form-item> </el-form-item>
</div> </div>
<!-- <el-form-item :label="t('headimg')" >
<div class="flex items-center">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="formData.member.headimg" :src="img(formData.member.headimg)" alt="" >
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" >
</div>
</el-form-item>
<el-form-item :label="t('memberId')" > </el-form>
<div class="input-width"> {{ formData.member.member_no }} </div>
</el-form-item>
<el-form-item :label="t('nickName')" > <template #footer>
<div class="input-width"> {{ formData.member.nickname }} </div> <span class="dialog-footer">
</el-form-item> <el-button type="primary" @click="showDialog = false">{{ t('confirm') }}</el-button>
</span>
</template>
<el-form-item :label="t('mobile')" >
<div class="input-width"> {{ formData.member.mobile }} </div>
</el-form-item>
<el-form-item :label="t('accountData')" >
<div class="input-width"> {{ formData.account_data }} </div>
</el-form-item>
<el-form-item :label="t('fromType')" >
<div class="input-width"> {{ formData.from_type_name }} </div>
</el-form-item>
<el-form-item :label="t('memo')" >
<div class="input-width"> {{ formData.memo }} </div>
</el-form-item>
<el-form-item :label="t('createTime')" >
<div class="input-width"> {{ formData.create_time }} </div>
</el-form-item> -->
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="showDialog = false">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getAccountList, getAccountStat, getAccountType } from '@/app/api/site' import { getAccountList, getAccountStat, getAccountType } from '@/app/api/site'
import { img } from '@/utils/common' // import { img } from '@/utils/common'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
let siteAccountLogTable = reactive({ const siteAccountLogTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
site_id: "", site_id: '',
type: "", type: '',
money: "", money: '',
trade_no: "", trade_no: '',
create_time: "" create_time: ''
} }
}) })
@ -240,7 +206,7 @@ const loadSiteAccountLogList = (page: number = 1) => {
getAccountList({ getAccountList({
page: siteAccountLogTable.page, page: siteAccountLogTable.page,
limit: siteAccountLogTable.limit, limit: siteAccountLogTable.limit,
...siteAccountLogTable.searchParam ...siteAccountLogTable.searchParam
}).then(res => { }).then(res => {
siteAccountLogTable.loading = false siteAccountLogTable.loading = false
siteAccountLogTable.data = res.data.data siteAccountLogTable.data = res.data.data
@ -251,8 +217,6 @@ const loadSiteAccountLogList = (page: number = 1) => {
} }
loadSiteAccountLogList() loadSiteAccountLogList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
@ -261,19 +225,46 @@ const resetForm = (formEl: FormInstance | undefined) => {
const accountType = ref([]) const accountType = ref([])
const checkAccountType = () => { const checkAccountType = () => {
getAccountType().then(res=>{ getAccountType().then(res => {
accountType.value = res.data accountType.value = res.data
}) })
} }
checkAccountType() checkAccountType()
const showDialog = ref(false) const showDialog = ref(false)
const formData = ref([]); const formData = ref({
const detailEvent = (info) => { trade_no: '',
showDialog.value = true type_name: '',
formData.value = info money: 0,
create_time: '',
type: '',
pay_info: {
transfer_no: '',
transfer_time: '',
transfer_type: '',
money: 0,
remark: '',
out_trade_no: '',
create_time: '',
fail_reason: '',
body: ''
}
})
const detailEvent = (info:any) => {
showDialog.value = true
formData.value = info
} }
const accountStat = ref([]) interface AccountStat{
pay: number,
refund: number,
transfer: number
}
const accountStat = ref<AccountStat>({
pay: 0,
refund: 0,
transfer: 0
})
const checkAccountStat = async () => { const checkAccountStat = async () => {
accountStat.value = await (await getAccountStat()).data accountStat.value = await (await getAccountStat()).data
} }

View File

@ -2,32 +2,34 @@
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]"> <div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="12"> <el-col :span="12">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="statistics.transfered ? Number.parseFloat(statistics.transfered).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="statistics.transfered ? statistics.transfered.toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalTransfered') }}</span> <span>{{ t('totalTransfered') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="statistics.cash_outing ? Number.parseFloat(statistics.cash_outing).toFixed(2) : '0'"></el-statistic> <el-statistic
:value="statistics.cash_outing ? statistics.cash_outing.toFixed(2) : '0'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalCashOuting') }}</span> <span>{{ t('totalCashOuting') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</el-card> </el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
@ -36,39 +38,39 @@
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" /> :end-placeholder="t('endDate')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('cashOutNumber')" prop="cash_out_no"> <el-form-item :label="t('cashOutNumber')" prop="cash_out_no">
<el-input v-model="orderTableData.searchParam.cash_out_no" class="w-[240px]" <el-input v-model="orderTableData.searchParam.cash_out_no" class="w-[240px]"
:placeholder="t('cashOutNumberPlaceholder')" /> :placeholder="t('cashOutNumberPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('memberInfo')" prop="keyword"> <el-form-item :label="t('memberInfo')" prop="keyword">
<el-input v-model="orderTableData.searchParam.keyword" class="w-[240px]" <el-input v-model="orderTableData.searchParam.keyword" class="w-[240px]"
:placeholder="t('memberInfoPlaceholder')" /> :placeholder="t('memberInfoPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('cashOutMethod')" prop="transfer_type"> <el-form-item :label="t('cashOutMethod')" prop="transfer_type">
<el-select v-model="orderTableData.searchParam.transfer_type" clearable class="input-width"> <el-select v-model="orderTableData.searchParam.transfer_type" clearable class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item.name" :value="key" v-for="(item, key) in Transfertype" /> <el-option :label="item.name" :value="key" v-for="(item, key) in Transfertype" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('cashOutStatus')" prop="order_from"> <el-form-item :label="t('cashOutStatus')" prop="order_from">
<el-select v-model="orderTableData.searchParam.status" clearable class="input-width"> <el-select v-model="orderTableData.searchParam.status" clearable class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item" :value="key" v-for="(item, key) in cashOutStatusList" /> <el-option :label="item" :value="key" v-for="(item, key) in cashOutStatusList" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('auditTime')" prop="audit_time"> <el-form-item :label="t('auditTime')" prop="audit_time">
<el-date-picker v-model="orderTableData.searchParam.audit_time" type="datetimerange" <el-date-picker v-model="orderTableData.searchParam.audit_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" /> :end-placeholder="t('endDate')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('transferTime')" prop="transfer_time"> <el-form-item :label="t('transferTime')" prop="transfer_time">
<el-date-picker v-model="orderTableData.searchParam.transfer_time" type="datetimerange" <el-date-picker v-model="orderTableData.searchParam.transfer_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" /> :end-placeholder="t('endDate')" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadOrderList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadOrderList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button> <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
@ -82,11 +84,14 @@
<span>{{ !orderTableData.loading ? t('emptyData') : '' }}</span> <span>{{ !orderTableData.loading ? t('emptyData') : '' }}</span>
</template> </template>
<el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('memberInfo')" align="center" min-width="140"> <el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('memberInfo')" align="center"
min-width="140">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)"> <div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="" > <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" > :src="img(row.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span> <span class="">{{ row.member.nickname || '' }}</span>
<span class="">{{ row.member.mobile || '' }}</span> <span class="">{{ row.member.mobile || '' }}</span>
@ -94,15 +99,16 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('cashOutMethod')" align="center" min-width="140" > <el-table-column :label="t('cashOutMethod')" align="center" min-width="140">
<template #default="{ row }"> <template #default="{ row }">
{{ Transfertype[row.transfer_type].name }} {{ Transfertype[row.transfer_type].name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="apply_money" :label="t('applicationForWithdrawalAmount')" min-width="140" align="center" /> <el-table-column prop="apply_money" :label="t('applicationForWithdrawalAmount')" min-width="140"
align="center" />
<el-table-column prop="money" :label="t('actualTransferAmount')" min-width="200" align="center"/> <el-table-column prop="money" :label="t('actualTransferAmount')" min-width="200" align="center" />
<el-table-column prop="service_money" :label="t('cashOutCommission')" align="center" min-width="140" /> <el-table-column prop="service_money" :label="t('cashOutCommission')" align="center" min-width="140" />
@ -114,21 +120,23 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('auditTime')" min-width="180" align="center"> <el-table-column :label="t('auditTime')" min-width="180" align="center">
<template #default="{ row }"> <template #default="{ row }">
{{ row.audit_time || '' }} {{ row.audit_time || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('transferTime')" min-width="180" align="center"> <el-table-column :label="t('transferTime')" min-width="180" align="center">
<template #default="{ row }"> <template #default="{ row }">
{{ row.transfer_time || '' }} {{ row.transfer_time || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right" width="230"> <el-table-column :label="t('operation')" align="right" fixed="right" width="230">
<template #default="{ row }"> <template #default="{ row }">
<el-button v-for="(item,index) in operationBtn[row.status.toString()].value" :key="index+'a'" @click="fnProcessing(operationBtn[row.status.toString()].clickArr[index],row)" type="primary" link>{{ item }}</el-button> <el-button v-for="(item, index) in operationBtn[row.status.toString()].value" :key="index + 'a'"
@click="fnProcessing(operationBtn[row.status.toString()].clickArr[index], row)"
type="primary" link>{{ item }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
@ -144,7 +152,8 @@
<!-- 详情 --> <!-- 详情 -->
<el-dialog v-model="cashOutShowDialog" :title="t('cashOutDetail')" width="500px" :destroy-on-close="true"> <el-dialog v-model="cashOutShowDialog" :title="t('cashOutDetail')" width="500px" :destroy-on-close="true">
<el-form :model="cashOutInfo" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="cashOutLoading"> <el-form :model="cashOutInfo" label-width="120px" ref="formRef" :rules="formRules" class="page-form"
v-loading="cashOutLoading">
<el-form-item :label="t('nickname')"> <el-form-item :label="t('nickname')">
<div class="input-width"> {{ cashOutInfo.nickname }} </div> <div class="input-width"> {{ cashOutInfo.nickname }} </div>
</el-form-item> </el-form-item>
@ -169,33 +178,35 @@
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button type="primary" @click="cashOutShowDialog = false">{{t('confirm')}}</el-button> <el-button type="primary" @click="cashOutShowDialog = false">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 是否审核 --> <!-- 是否审核 -->
<el-dialog v-model="auditShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true"> <el-dialog v-model="auditShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true">
<el-form :model="auditFailure" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading"> <el-form :model="auditFailure" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form-item :label="t('reasonsRefusal')" prop="label_name"> <el-form-item :label="t('reasonsRefusal')" prop="label_name">
<el-input v-model="auditFailure.refuse_reason" clearable :placeholder="t('reasonsRefusalPlaceholder')" class="input-width" type="textarea" /> <el-input v-model="auditFailure.refuse_reason" clearable :placeholder="t('reasonsRefusalPlaceholder')"
class="input-width" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="auditShowDialog = false">{{ t('cancel') }}</el-button> <el-button @click="auditShowDialog = 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()">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 是否转账 --> <!-- 是否转账 -->
<el-dialog v-model="transferShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true"> <el-dialog v-model="transferShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true">
<p>{{t('isTransfer')}}</p> <p>{{ t('isTransfer') }}</p>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="transferShowDialog = false">{{ t('cancel') }}</el-button> <el-button @click="transferShowDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirm(formRef)">{{t('confirm')}}</el-button> <el-button type="primary" @click="confirm()">{{ t('confirm') }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -205,44 +216,46 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getCashOutList, getTransfertype, memberTransfer, memberAudit, getCashOutDetail, getCashOutStatusList,getCashOutStat } from '@/app/api/member' import { getCashOutList, getTransfertype, memberTransfer, memberAudit, getCashOutDetail, getCashOutStatusList, getCashOutStat } from '@/app/api/member'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox, FormInstance, FormRules } from 'element-plus'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { AnyObject } from '@/types/global'
const cashOutStatusList = ref([]) const cashOutStatusList = ref([])
const checkStatusList = async () => { const checkStatusList = async () => {
cashOutStatusList.value = await (await getCashOutStatusList({})).data cashOutStatusList.value = await (await getCashOutStatusList()).data
} }
checkStatusList() checkStatusList()
const transferShowDialog = ref(false)
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title; const pageName = route.meta.title
const member_id: number = parseInt(route.query.id || 0) const operationBtn = ref<AnyObject>({
const operationBtn = ref({ 1: {
"1": { value: [t('successfulAudit'), t('auditFailure'), t('detail')],
value: [t('successfulAudit'),t('auditFailure'),t('detail')], clickArr: ['successfulAuditFn', 'auditFailureFn', 'detailFn']
clickArr: ['successfulAuditFn','auditFailureFn','detailFn']
}, },
"2": { 2: {
value: [t('transfer'),t('detail')], value: [t('transfer'), t('detail')],
clickArr: ['transferFn','detailFn'] clickArr: ['transferFn', 'detailFn']
}, },
"3": { 3: {
value: [t('detail')], value: [t('detail')],
clickArr: ['detailFn'] clickArr: ['detailFn']
}, },
"-1": { '-1': {
value: [t('detail')], value: [t('detail')],
clickArr: ['detailFn'] clickArr: ['detailFn']
}, },
"-2": { '-2': {
value: [t('detail')], value: [t('detail')],
clickArr: ['detailFn'] clickArr: ['detailFn']
} }
}); })
//
const formRules = reactive<FormRules>({})
const orderTableData = reactive({ const orderTableData = reactive({
page: 1, page: 1,
@ -252,40 +265,41 @@ const orderTableData = reactive({
data: [], data: [],
searchParam: { searchParam: {
order_no: '', order_no: '',
member_id, member_id: 0,
create_time: [], create_time: [],
status: '', status: '',
cash_out_no: '', cash_out_no: '',
keyword: '', keyword: '',
audit_time: '', audit_time: '',
transfer_time: '', transfer_time: '',
transfer_type: '' transfer_type: ''
} }
}) })
const statistics = ref([]) const statistics = ref({
transfered: 0,
cash_outing: 0
})
const checkStatInfo = () => { const checkStatInfo = () => {
getCashOutStat().then(res => { getCashOutStat().then(res => {
statistics.value = res.data; statistics.value = res.data
}) })
} }
checkStatInfo() checkStatInfo()
// //
const Transfertype = ref<Array<Object>>([]) const Transfertype = ref<Array<Object|any>>([])
const getTransfertypeFn = async()=>{ const getTransfertypeFn = async () => {
Transfertype.value = await (await getTransfertype()).data Transfertype.value = await (await getTransfertype()).data
} }
getTransfertypeFn() getTransfertypeFn()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadOrderList(); loadOrderList()
} }
/** /**
@ -310,38 +324,37 @@ const loadOrderList = (page: number = 1) => {
loadOrderList() loadOrderList()
// //
let auditFailure = ref({refuse_reason:'',id:0,action: 0}) const auditFailure = ref({ refuse_reason: '', id: 0, action: 0 })
let auditShowDialog = ref(false); const auditShowDialog = ref(false)
const fnProcessing = (type:string, data: any)=>{ const fnProcessing = (type: string, data: any) => {
let obj = {} const obj = {}
if(['successfulAuditFn','auditFailureFn'].includes(type)){ if (['successfulAuditFn', 'auditFailureFn'].includes(type)) {
obj.id = data.id; obj.id = data.id
if(type == 'successfulAuditFn'){ if (type == 'successfulAuditFn') {
obj.action = 'agree'; obj.action = 'agree'
cashOutAuditFn(obj) cashOutAuditFn(obj)
}else{ } else {
obj.action = 'refuse'; obj.action = 'refuse'
auditFailure.value = Object.assign(auditFailure.value,obj); auditFailure.value = Object.assign(auditFailure.value, obj)
auditShowDialog.value = true; auditShowDialog.value = true
} }
}else if(type == 'transferFn'){ } else if (type == 'transferFn') {
obj.id = data.id; obj.id = data.id
ElMessageBox.confirm(`${t('isTransfer')}`,`${t('transfer')}`) ElMessageBox.confirm(`${t('isTransfer')}`, `${t('transfer')}`)
.then(() => { .then(() => {
transferFn(obj); transferFn(obj)
}) })
}else{ } else {
detailFn(data.id); detailFn(data.id)
} }
} }
/** /**
* 转账 * 转账
* @param data * @param data
*/ */
const transferFn = (data)=>{ const transferFn = (data:any) => {
memberTransfer({...data}).then(res => { memberTransfer({ ...data }).then(res => {
loadOrderList() loadOrderList()
}).catch(() => { }).catch(() => {
loadOrderList() loadOrderList()
@ -353,14 +366,22 @@ const transferFn = (data)=>{
* @param data * @param data
*/ */
let cashOutShowDialog = ref(false); const cashOutShowDialog = ref(false)
let cashOutInfo = ref({}); const cashOutInfo = ref({
let cashOutLoading = ref(true); nickname: '',
const detailFn = (id)=>{ account_type_name: '',
transfer_type: '',
apply_money: 0,
service_money: 0,
money: 0,
status_name: ''
})
const cashOutLoading = ref(true)
const detailFn = (id:any) => {
getCashOutDetail(id).then(res => { getCashOutDetail(id).then(res => {
cashOutInfo.value = res.data; cashOutInfo.value = res.data
cashOutShowDialog.value = true; cashOutShowDialog.value = true
cashOutLoading.value = false; cashOutLoading.value = false
}).catch(() => { }).catch(() => {
loadOrderList() loadOrderList()
}) })
@ -370,7 +391,7 @@ const detailFn = (id)=>{
* 提现审核 * 提现审核
* @param data * @param data
*/ */
const cashOutAuditFn = (data)=>{ const cashOutAuditFn = (data:any) => {
memberAudit({ memberAudit({
...data ...data
}).then(res => { }).then(res => {
@ -384,25 +405,16 @@ const cashOutAuditFn = (data)=>{
* 拒绝审核 * 拒绝审核
* @param data * @param data
*/ */
const confirm = ()=>{ const confirm = () => {
auditShowDialog.value = false; auditShowDialog.value = false
cashOutAuditFn(auditFailure.value); cashOutAuditFn(auditFailure.value)
} }
/**
* 订单详情
* @param data
*/
const infoEvent = (data: any) => {
router.push(`/finance/recharge/detail?order_id=${data.order_id}`)
}
/** /**
* 会员详情 * 会员详情
*/ */
const toMember = (member_id: number) => { const toMember = (memberId: number) => {
router.push(`/member/detail?id=${member_id}`) router.push(`/member/detail?id=${memberId}`)
} }
</script> </script>

View File

@ -52,11 +52,11 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getPayRefundPages } from '@/app/api/pay' import { getPayRefundPages } from '@/app/api/pay'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import type { FormInstance } from 'element-plus'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
@ -76,7 +76,7 @@ const payRefundTable = reactive({
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
// //
const selectData = ref<any[]>([]) // const selectData = ref<any[]>([])
/** /**
* 获取商品标签列表 * 获取商品标签列表
@ -99,7 +99,7 @@ const loadPayRefundList = (page: number = 1) => {
} }
loadPayRefundList() loadPayRefundList()
const infoEvent = (data) => { const infoEvent = (data:any) => {
router.push('/finance/refund/detail?refund_no=' + data.refund_no) router.push('/finance/refund/detail?refund_no=' + data.refund_no)
} }

View File

@ -8,54 +8,56 @@
<span class="adorn">|</span> <span class="adorn">|</span>
<span class="right">{{ pageName }}</span> <span class="right">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none relative" shadow="never" v-if="formData"> <el-card class="box-card !border-none relative" shadow="never" v-if="formData">
<div class="flex px-[20px] py-[20px] justify-between"> <div class="flex px-[20px] py-[20px] justify-between">
<span>{{ t('refundMoney') }}<span>{{ formData.money }}</span></span> <span>{{ t('refundMoney') }}<span>{{ formData.money }}</span></span>
<span>{{ t('refundNo') }}<span>{{ formData.refund_no }}</span></span> <span>{{ t('refundNo') }}<span>{{ formData.refund_no }}</span></span>
</div> </div>
<el-table :data="refundList" size="large"> <el-table :data="refundList" size="large">
<el-table-column prop="out_trade_no" :label="t('outTradeNo')" min-width="200" /> <el-table-column prop="out_trade_no" :label="t('outTradeNo')" min-width="200" />
<el-table-column prop="create_time" :label="t('createTime')" min-width="160" /> <el-table-column prop="create_time" :label="t('createTime')" min-width="160" />
<el-table-column prop="refund_type_name" :label="t('refundTypeName')" min-width="120" /> <el-table-column prop="refund_type_name" :label="t('refundTypeName')" min-width="120" />
<el-table-column :label="t('refundMoney')" min-width="120"> <el-table-column :label="t('refundMoney')" min-width="120">
<template #default="{ row }"> <template #default="{ row }">
<span>{{ row.money }}</span> <span>{{ row.money }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status_name" :label="t('statusName')" min-width="120" /> <el-table-column prop="status_name" :label="t('statusName')" min-width="120" />
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="120"> <el-table-column :label="t('operation')" fixed="right" align="right" min-width="120">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="transferEvent(row)" v-if="row.status == 'wait'">{{ t('transfer') }}</el-button> <el-button type="primary" link @click="transferEvent(row)" v-if="row.status == 'wait'">{{
</template> t('transfer') }}</el-button>
</el-table-column> </template>
</el-table> </el-table-column>
</el-card> </el-table>
</el-card>
<el-dialog v-model="transferDialog" :title="title" width="500px" class="diy-dialog-wrap" <el-dialog v-model="transferDialog" :title="title" width="500px" class="diy-dialog-wrap" :destroy-on-close="true">
:destroy-on-close="true"> <el-form :model="transfeFormData" label-width="120px" ref="formRef" :rules="formRules" class="page-form"
<el-form :model="transfeFormData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading"> v-loading="loading">
<el-form-item :label="t('transferType')"> <el-form-item :label="t('transferType')">
<el-radio-group v-model="transfeFormData.refund_type"> <el-radio-group v-model="transfeFormData.refund_type">
<el-radio :label="item.value" v-for="(item, index) in refundTypeData" :key="index">{{ item.name }}</el-radio> <el-radio :label="item.value" v-for="(item, index) in refundTypeData" :key="index">{{ item.name
</el-radio-group> }}</el-radio>
</el-form-item> </el-radio-group>
<el-form-item :label="t('refundMoney')" > </el-form-item>
<span>{{ transfeFormData.refund_money }}</span> <el-form-item :label="t('refundMoney')">
</el-form-item> <span>{{ transfeFormData.refund_money }}</span>
<el-form-item :label="t('voucher')" v-if="transfeFormData.refund_type == 'offline'"> </el-form-item>
<upload-image v-model="transfeFormData.voucher" /> <el-form-item :label="t('voucher')" v-if="transfeFormData.refund_type == 'offline'">
</el-form-item> <upload-image v-model="transfeFormData.voucher" />
</el-form> </el-form-item>
</el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="transferDialog = false">{{ t('cancel') }}</el-button> <el-button @click="transferDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm') t('confirm')
}}</el-button> }}</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -64,15 +66,13 @@ import { ref, reactive, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getPayRefundInfo, getRefundType, getRefundTransfer } from '@/app/api/pay' import { getPayRefundInfo, getRefundType, getRefundTransfer } from '@/app/api/pay'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { img, getAppType } from '@/utils/common' import { FormInstance } from 'element-plus'
import { ElMessageBox, FormInstance } from 'element-plus'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
const refundNo: string = route.query.refund_no const refundNo: string = route.query.refund_no
const loading = ref(true) const loading = ref(true)
const appType = getAppType()
const refundList = ref([]) const refundList = ref([])
const formData: Record<string, any> | null = ref(null) const formData: Record<string, any> | null = ref(null)
@ -102,7 +102,7 @@ getRefundType().then((data) => {
}) })
const transferDialog = ref(false) const transferDialog = ref(false)
const transferEvent = (data) => { const transferEvent = (data:any) => {
transferDialog.value = true transferDialog.value = true
transfeFormData.refund_no = data.refund_no transfeFormData.refund_no = data.refund_no
transfeFormData.refund_money = data.money transfeFormData.refund_money = data.money
@ -140,7 +140,7 @@ const confirm = async (formEl: FormInstance | undefined) => {
transferDialog.value = false transferDialog.value = false
refundList.value = [] refundList.value = []
setFormData(refundNo) setFormData(refundNo)
}).catch(err => { }).catch(() => {
transferDialog.value = false transferDialog.value = false
loading.value = false loading.value = false
}) })

View File

@ -1,23 +1,24 @@
<template> <template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading"> <div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4"> <div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('editPersonal') }}</span> <span class="text-[20px]">{{ t('editPersonal') }}</span>
</div> </div>
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form"> <el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
<el-form-item :label="t('headImg')"> <el-form-item :label="t('headImg')">
<upload-image v-model="saveInfo.head_img" :limit="1" /> <upload-image v-model="saveInfo.head_img" :limit="1" />
</el-form-item> </el-form-item>
<el-form-item :label="t('userName')"> <el-form-item :label="t('userName')">
<span>{{saveInfo.username}}</span> <span>{{ saveInfo.username }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="t('realName')"> <el-form-item :label="t('realName')">
<el-input v-model="saveInfo.real_name" :placeholder="t('realNamePlaceholder')" clearable class="input-width" /> <el-input v-model="saveInfo.real_name" :placeholder="t('realNamePlaceholder')" clearable
class="input-width" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="flex justify-center mt-[50px]"> <div class="flex justify-center mt-[50px]">
<el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button> <el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button>
<el-button type="primary" @click="returnFn(formRef)">{{ t('cancel') }}</el-button> <el-button type="primary" @click="returnFn()">{{ t('cancel') }}</el-button>
</div> </div>
</el-card> </el-card>
</div> </div>
@ -26,77 +27,83 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance, FormRules, ElNotification } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common' import { getUserInfo, setUserInfo } from '@/app/api/personal'
import { getUserInfo,setUserInfo } from '@/app/api/personal' import { useRouter } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
// //
let saveInfo = reactive({ const saveInfo: {
head_img: '', head_img: string;
real_name: '', real_name: string;
username: '' username: string;
}); } = reactive({
head_img: '',
real_name: '',
username: ''
})
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>()
const loading = ref(true); const loading = ref(true)
/** /**
* 获取用户信息 * 获取用户信息
*/ */
const getUserInfoFn = () => { const getUserInfoFn = () => {
loading.value = true; loading.value = true
getUserInfo().then(res => { getUserInfo().then(res => {
loading.value = false; loading.value = false
let data = res.data; const data = res.data
saveInfo.head_img = data.head_img; saveInfo.head_img = data.head_img
saveInfo.real_name = data.real_name; saveInfo.real_name = data.real_name
saveInfo.username = data.username; saveInfo.username = data.username
}).catch(() => { }).catch(() => {
loading.value = false; loading.value = false
}) })
} }
getUserInfoFn(); getUserInfoFn()
const submitForm = (formEl: FormInstance | undefined) => { const submitForm = (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
formEl.validate((valid) => { formEl.validate((valid) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true
setUserInfo(saveInfo).then((res: any) => { setUserInfo(saveInfo).then((res: any) => {
loading.value = false; loading.value = false
}).catch((err: any) => { }).catch(() => {
loading.value = false loading.value = false
}) })
} else { } else {
return false return false
} }
}); })
} }
const returnFn = ()=>{ const returnFn = () => {
router.push('/user/center') router.push('/user/center')
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.personal-body){ :deep(.personal-body) {
background-color: #fff; background-color: #fff;
.el-form-item__content{
.el-input{ .el-form-item__content {
.el-input {
width: 250px; width: 250px;
} }
.el-form-item__content{
.el-form-item__content {
justify-content: space-between; justify-content: space-between;
} }
.el-button{
.el-button {
margin-left: auto; margin-left: auto;
} }
.personal-option{
.personal-option {
margin-right: auto; margin-right: auto;
} }
} }
} }</style>
</style>

View File

@ -1,3 +1,4 @@
<!-- eslint-disable vue/no-deprecated-v-on-native-modifier -->
<template> <template>
<div> <div>
<div class="flex justify-between items-center py-[24px] pl-[62px] pr-[64px] home-head"> <div class="flex justify-between items-center py-[24px] pl-[62px] pr-[64px] home-head">
@ -63,18 +64,38 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, toRefs } from 'vue' import { reactive, ref, toRefs } from 'vue'
import { CollectionTag, Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import { getHomeSite } from '@/app/api/home' import { getHomeSite } from '@/app/api/home'
import { getWebConfig } from '@/app/api/sys' import { getWebConfig } from '@/app/api/sys'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import useUserStore from '@/stores/modules/user' import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import { getInstalledAddonList } from '@/app/api/addon' import { getInstalledAddonList } from '@/app/api/addon'
import { useRouter } from 'vue-router' import { ElMessage } from 'element-plus'
import { AnyObject } from '@/types/global'
const userStore:AnyObject = useUserStore()
const userStore = useUserStore() interface State{
const router = useRouter() params: {
const state = reactive({ keywords: string,
page: number,
limit: number,
app: string,
sort: boolean
},
loading: boolean,
tableData: {
logo: string,
app_name: string,
site_name: string,
create_time: string,
expire_time: string,
site_id: number,
group_name: string
}[]
}
const state:State = reactive({
params: { params: {
keywords: '', keywords: '',
page: 1, page: 1,
@ -99,17 +120,19 @@ const getHomeSiteFn = () => {
getHomeSiteFn() getHomeSiteFn()
// //
const cutAppFn = (app)=>{ const cutAppFn = (app:any) => {
state.params.app = app; state.params.app = app
getHomeSiteFn(); getHomeSiteFn()
} }
// //
let webConfig = ref({}) const webConfig = ref({
const getWebConfigFn = () =>{ icon: '',
getWebConfig().then(res =>{ site_name: ''
webConfig.value = res.data; })
const getWebConfigFn = () => {
getWebConfig().then(res => {
webConfig.value = res.data
}) })
} }
getWebConfigFn() getWebConfigFn()
@ -128,19 +151,19 @@ const selectSite = (site: any) => {
}) })
location.href = `${location.origin}/site/` location.href = `${location.origin}/site/`
} }
const logoutFn = ()=>{ const logoutFn = () => {
userStore.logout(); userStore.logout()
}
const toLinkFn = (link)=>{
router.push(link)
} }
/** /**
* 获取应用列表 * 获取应用列表
*/ */
const addonList = ref([]) const addonList = ref<{
key: string,
title: string
}[]>([])
getInstalledAddonList().then(({ data }) => { getInstalledAddonList().then(({ data }) => {
const apps = [] const apps:any = []
Object.keys(data).forEach(key => { Object.keys(data).forEach(key => {
const addon = data[key] const addon = data[key]
addon.type == 'app' && apps.push(addon) addon.type == 'app' && apps.push(addon)
@ -149,7 +172,7 @@ getInstalledAddonList().then(({ data }) => {
}).catch() }).catch()
const handleChick = () => { const handleChick = () => {
ElMessage('加班加点研发中...') ElMessage('加班加点研发中...')
} }
</script> </script>

View File

@ -1,25 +1,28 @@
<template> <template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading"> <div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4"> <div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('personal') }}</span> <span class="text-[20px]">{{ t("personal") }}</span>
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span> <span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t("editPersonal") }}</span>
</div> </div>
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form"> <el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
<el-form-item :label="t('headImg')"> <el-form-item :label="t('headImg')">
<el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain"> <el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain">
<template #error> <template #error>
<div class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full"> <div
<el-icon class="!text-[#fff] !text-[45px]"><UserFilled /></el-icon> class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full">
<el-icon class="!text-[#fff] !text-[45px]">
<UserFilled />
</el-icon>
</div> </div>
</template> </template>
</el-image> </el-image>
</el-form-item> </el-form-item>
<el-form-item :label="t('userName')"> <el-form-item :label="t('userName')">
<div>{{saveInfo.username}}</div> <div>{{ saveInfo.username }}</div>
</el-form-item> </el-form-item>
<el-form-item :label="t('realName')"> <el-form-item :label="t('realName')">
<div>{{saveInfo.real_name}}</div> <div>{{ saveInfo.real_name }}</div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@ -29,45 +32,46 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance, FormRules, ElNotification } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { getUserInfo,setUserInfo } from '@/app/api/personal' import { getUserInfo } from '@/app/api/personal'
import { useRoute, useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
// //
let saveInfo = reactive({ const saveInfo = reactive({
head_img: '', head_img: '',
real_name: '', real_name: '',
original_password: '', original_password: '',
password: '', password: '',
password_copy: '', password_copy: '',
username: '' username: ''
}); })
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>()
const loading = ref(true); const loading = ref(true)
/** /**
* 获取用户信息 * 获取用户信息
*/ */
const getUserInfoFn = () => { const getUserInfoFn = () => {
loading.value = true; loading.value = true
getUserInfo().then(res => { getUserInfo().then((res) => {
loading.value = false; loading.value = false
let data = res.data; const data = res.data
saveInfo.head_img = data.head_img; saveInfo.head_img = data.head_img
saveInfo.real_name = data.real_name; saveInfo.real_name = data.real_name
saveInfo.original_password = data.original_password; saveInfo.original_password = data.original_password
saveInfo.password = data.password; saveInfo.password = data.password
saveInfo.password_copy = data.password; saveInfo.password_copy = data.password
saveInfo.username = data.username; saveInfo.username = data.username
}).catch(() => {
loading.value = false;
}) })
.catch(() => {
loading.value = false
})
} }
getUserInfoFn(); getUserInfoFn()
// //
const toEditPersonal = () => { const toEditPersonal = () => {
@ -76,19 +80,23 @@ const toEditPersonal = () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.personal-body){ :deep(.personal-body) {
background-color: #fff; background-color: #fff;
.el-form-item__content{
.el-input{ .el-form-item__content {
.el-input {
width: 250px; width: 250px;
} }
.el-form-item__content{
.el-form-item__content {
justify-content: space-between; justify-content: space-between;
} }
.el-button{
.el-button {
margin-left: auto; margin-left: auto;
} }
.personal-option{
.personal-option {
margin-right: auto; margin-right: auto;
} }
} }

View File

@ -56,20 +56,26 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, onMounted, computed } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getInstalledAddonList } from '@/app/api/addon' import { getInstalledAddonList } from '@/app/api/addon'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import { findFirstValidRoute } from '@/router/routers' import { findFirstValidRoute } from '@/router/routers'
import { UserFilled } from '@element-plus/icons-vue'
import useUserStore from '@/stores/modules/user' import useUserStore from '@/stores/modules/user'
import { AnyObject } from '@/types/global'
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore:AnyObject = useUserStore()
const loading = ref(true) const loading = ref(true)
const detail = reactive({ const detail:{
appList: {
title: string,
desc: string,
icon: string
}[]
} = reactive({
appList: [] appList: []
}) })
const appLink: any = ref({}) const appLink: any = ref({})
@ -82,7 +88,7 @@ const getAuthaddonFn = () => {
detail.appList.push(item) detail.appList.push(item)
} }
}) })
userStore.routers.forEach((item, index) => { userStore.routers.forEach((item:any, index:number) => {
if (item.children && item.children.length) { if (item.children && item.children.length) {
item.name = findFirstValidRoute(item.children) item.name = findFirstValidRoute(item.children)
appLink.value[item.meta.app] = findFirstValidRoute(item.children) appLink.value[item.meta.app] = findFirstValidRoute(item.children)
@ -93,7 +99,6 @@ const getAuthaddonFn = () => {
loading.value = false loading.value = false
}).catch(() => { }).catch(() => {
loading.value = false loading.value = false
}) })
} }
@ -105,30 +110,14 @@ const itemPath = (data: any) => {
const appMenuList = userStore.appMenuList const appMenuList = userStore.appMenuList
appMenuList.push(data.key) appMenuList.push(data.key)
userStore.setAppMenuList(appMenuList) userStore.setAppMenuList(appMenuList)
let name: any = appLink.value[data.key] const name: any = appLink.value[data.key]
router.push({ name: name }) router.push({ name })
}
const goAppManage = () => {
router.push('/app_manage')
}
const goRouter = () => {
window.open('https://www.niucloud.com/app')
} }
// //
const toAppStore = () => { const toAppStore = () => {
router.push('/app_manage/app_store') router.push('/app_manage/app_store')
} }
const goNiucloud = () => {
window.open('https://www.niucloud.com')
}
const logout = () => {
userStore.logout();
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -4,7 +4,7 @@
<span class="text-[20px]">{{ t('editPersonal') }}</span> <span class="text-[20px]">{{ t('editPersonal') }}</span>
</div> </div>
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form"> <el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
<el-form-item :label="t('headImg')"> <el-form-item :label="t('headImg')">
<upload-image v-model="saveInfo.head_img" :limit="1" /> <upload-image v-model="saveInfo.head_img" :limit="1" />
</el-form-item> </el-form-item>
@ -17,7 +17,7 @@
</el-form> </el-form>
<div class="flex justify-center mt-[50px]"> <div class="flex justify-center mt-[50px]">
<el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button> <el-button type="primary" @click="submitForm(formRef)">{{ t('save') }}</el-button>
<el-button type="primary" @click="returnFn(formRef)">{{ t('cancel') }}</el-button> <el-button type="primary" @click="returnFn()">{{ t('cancel') }}</el-button>
</div> </div>
</el-card> </el-card>
</div> </div>
@ -26,57 +26,56 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance, FormRules, ElNotification } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common'
import { getUserInfo,setUserInfo } from '@/app/api/personal' import { getUserInfo, setUserInfo } from '@/app/api/personal'
import { useRoute, useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
// //
let saveInfo = reactive({ const saveInfo = reactive({
head_img: '', head_img: '',
real_name: '', real_name: '',
username: '' username: ''
}); })
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>()
const loading = ref(true); const loading = ref(true)
/** /**
* 获取用户信息 * 获取用户信息
*/ */
const getUserInfoFn = () => { const getUserInfoFn = () => {
loading.value = true; loading.value = true
getUserInfo().then(res => { getUserInfo().then(res => {
loading.value = false; loading.value = false
const data = res.data
let data = res.data; saveInfo.head_img = data.head_img
saveInfo.head_img = data.head_img; saveInfo.real_name = data.real_name
saveInfo.real_name = data.real_name; saveInfo.username = data.username
saveInfo.username = data.username;
}).catch(() => { }).catch(() => {
loading.value = false; loading.value = false
}) })
} }
getUserInfoFn(); getUserInfoFn()
const submitForm = (formEl: FormInstance | undefined) => { const submitForm = (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
formEl.validate((valid) => { formEl.validate((valid) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true
setUserInfo(saveInfo).then((res: any) => { setUserInfo(saveInfo).then((res: any) => {
loading.value = false; loading.value = false
}).catch((err: any) => { }).catch(() => {
loading.value = false loading.value = false
}) })
} else { } else {
return false return false
} }
}); })
} }
const returnFn = ()=>{ const returnFn = () => {
router.push('/user/center') router.push('/user/center')
} }
</script> </script>

View File

@ -1,3 +1,4 @@
<!-- eslint-disable no-undef -->
<template> <template>
<div class="bg-[#FAFAFA] box-border pb-[77px]"> <div class="bg-[#FAFAFA] box-border pb-[77px]">
<div class="main-container" v-loading="loading"> <div class="main-container" v-loading="loading">
@ -164,33 +165,43 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from "vue"; import { ref, watch } from 'vue'
import useSystemStore from "@/stores/modules/system"; import { t } from '@/lang'
import { t } from "@/lang"; import { getStatInfo } from '@/app/api/stat'
import { getStatInfo } from "@/app/api/stat"; import * as echarts from 'echarts'
import * as echarts from "echarts";
import { img } from "@/utils/common";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import useStyleStore from '@/stores/modules/style' import useStyleStore from '@/stores/modules/style'
import { getFrameworkNewVersion } from '@/app/api/module' import { getFrameworkNewVersion } from '@/app/api/module'
import { useRoute, useRouter } from 'vue-router'
import { AnyObject } from '@/types/global'
const loading = ref(true)
const loading = ref(true); const newSiteStat = ref<any>(null)
const visitStat = ref<any>(null); const siteStat = ref<any>(null)
const memberStat = ref<any>(null);
const newSiteStat = ref<any>(null);
const siteStat = ref<any>(null);
const systemStore = useSystemStore();
const styleStore = useStyleStore() const styleStore = useStyleStore()
const newVersion = ref(null)
interface NewVersion{
last_version: string
}
interface StatInfo {
today_data: AnyObject,
system: AnyObject,
version: AnyObject,
about: any,
site_stat: AnyObject,
site_group_stat: AnyObject,
app: AnyObject
}
const newVersion = ref<NewVersion>({
last_version: ''
})
getFrameworkNewVersion().then(({ data }) => { getFrameworkNewVersion().then(({ data }) => {
newVersion.value = data newVersion.value = data
}).catch() }).catch()
let statInfo = ref({ const statInfo = ref<StatInfo>({
today_data: {}, today_data: {},
system: {}, system: {},
version: {}, version: {},
@ -198,44 +209,44 @@ let statInfo = ref({
site_stat: {}, site_stat: {},
site_group_stat: {}, site_group_stat: {},
app: {} app: {}
}); })
const getStatInfoFn = async (id: number = 0) => { const getStatInfoFn = async (id: number = 0) => {
statInfo.value = await (await getStatInfo()).data; statInfo.value = await (await getStatInfo()).data
loading.value = false; loading.value = false
setTimeout(() => { setTimeout(() => {
drawChart(); drawChart()
}, 20); }, 20)
}; }
getStatInfoFn(); getStatInfoFn()
// 线 // 线
const drawChart = () => { const drawChart = () => {
// //
const newSiteStatChart = echarts.init(newSiteStat.value); const newSiteStatChart = echarts.init(newSiteStat.value)
const newSiteStatOption = ref({ const newSiteStatOption = ref({
legend: {}, legend: {},
xAxis: { xAxis: {
data: [], data: []
}, },
yAxis: {}, yAxis: {},
tooltip: { tooltip: {
trigger: "axis", trigger: 'axis'
}, },
series: [ series: [
{ {
name: t("newSite"), name: t('newSite'),
type: "line", type: 'line',
data: [], data: []
}, }
], ]
}); })
newSiteStatOption.value.xAxis.data = statInfo.value.site_stat.date; newSiteStatOption.value.xAxis.data = statInfo.value.site_stat.date
newSiteStatOption.value.series[0].data = statInfo.value.site_stat.value; newSiteStatOption.value.series[0].data = statInfo.value.site_stat.value
newSiteStatChart.setOption(newSiteStatOption.value); newSiteStatChart.setOption(newSiteStatOption.value)
// //
const siteStatChart = echarts.init(siteStat.value); const siteStatChart = echarts.init(siteStat.value)
const siteStatOption = ref({ const siteStatOption:AnyObject = ref({
legend: { legend: {
orient: 'vertical', orient: 'vertical',
right: 20, right: 20,
@ -244,34 +255,40 @@ const drawChart = () => {
tooltip: {}, tooltip: {},
series: [ series: [
{ {
type: "pie", type: 'pie',
data: [], data: []
}, }
], ]
}); })
const len = statInfo.value.site_group_stat.type.length; const len = statInfo.value.site_group_stat.type.length
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let obj = {}; const obj:{
obj.name = statInfo.value.site_group_stat.type[i]; name: string,
obj.value = statInfo.value.site_group_stat.value[i]; value: number
siteStatOption.value.series[0].data.push(obj); } = {
name: '',
value: 0
}
obj.name = statInfo.value.site_group_stat.type[i]
obj.value = statInfo.value.site_group_stat.value[i]
siteStatOption.value.series[0].data.push(obj)
} }
siteStatChart.setOption(siteStatOption.value); siteStatChart.setOption(siteStatOption.value)
window.addEventListener("resize", () => { window.addEventListener('resize', () => {
//Echarts // Echarts
newSiteStatChart.resize(); newSiteStatChart.resize()
siteStatChart.resize(); siteStatChart.resize()
}); })
}; }
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
if(route.path == '/admin/index'){ if (route.path == '/admin/index') {
styleStore.changeStyle() styleStore.changeStyle()
} }
watch(() => route.path, (newval, oldval) => { watch(() => route.path, (newval, oldval) => {
if(newval !== '/admin/index'){ if (newval !== '/admin/index') {
styleStore.changeBlack() styleStore.changeBlack()
} }
}) })
@ -279,19 +296,19 @@ watch(() => route.path, (newval, oldval) => {
/** /**
* 链接跳转 * 链接跳转
*/ */
const toLink = (link) => { const toLink = (link:any) => {
router.push(link); router.push(link)
};
const toHref = (url:any,id:any) =>{
router.push({
path:url,
query:{id}
})
} }
const toApplication = ()=>{ const toHref = (url:any, id:any) => {
router.push({
path: url,
query: { id }
})
}
const toApplication = () => {
window.open('https://www.niucloud.com/app') window.open('https://www.niucloud.com/app')
} }
// //
const time = ref('') const time = ref('')
const nowTime = () => { const nowTime = () => {
const date = new Date() const date = new Date()
@ -301,7 +318,7 @@ const nowTime = () => {
const hh = checkTime(date.getHours()) const hh = checkTime(date.getHours())
const mm = checkTime(date.getMinutes()) const mm = checkTime(date.getMinutes())
const ss = checkTime(date.getSeconds()) const ss = checkTime(date.getSeconds())
function checkTime (i) { function checkTime (i:any) {
if (i < 10) { if (i < 10) {
return '0' + i return '0' + i
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading"> <div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4"> <div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('personal') }}</span> <span class="text-[20px]">{{ t('personal') }}</span>
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span> <span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span>
@ -9,17 +9,20 @@
<el-form-item :label="t('headImg')"> <el-form-item :label="t('headImg')">
<el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain"> <el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain">
<template #error> <template #error>
<div class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full"> <div
<el-icon class="!text-[#fff] !text-[45px]"><UserFilled /></el-icon> class="image-slot bg-[#c0c4cc] flex items-center justify-center w-[70px] h-[70px] rounded-full">
<el-icon class="!text-[#fff] !text-[45px]">
<UserFilled />
</el-icon>
</div> </div>
</template> </template>
</el-image> </el-image>
</el-form-item> </el-form-item>
<el-form-item :label="t('userName')"> <el-form-item :label="t('userName')">
<div>{{saveInfo.username}}</div> <div>{{ saveInfo.username }}</div>
</el-form-item> </el-form-item>
<el-form-item :label="t('realName')"> <el-form-item :label="t('realName')">
<div>{{saveInfo.real_name}}</div> <div>{{ saveInfo.real_name }}</div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@ -29,45 +32,45 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance, FormRules, ElNotification } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { getUserInfo,setUserInfo } from '@/app/api/personal' import { getUserInfo } from '@/app/api/personal'
import { useRoute, useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter() const router = useRouter()
// //
let saveInfo = reactive({ const saveInfo = reactive({
head_img: '', head_img: '',
real_name: '', real_name: '',
original_password: '', original_password: '',
password: '', password: '',
password_copy: '', password_copy: '',
username: '' username: ''
}); })
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>()
const loading = ref(true); const loading = ref(true)
/** /**
* 获取用户信息 * 获取用户信息
*/ */
const getUserInfoFn = () => { const getUserInfoFn = () => {
loading.value = true; loading.value = true
getUserInfo().then(res => { getUserInfo().then(res => {
loading.value = false; loading.value = false
let data = res.data; const data = res.data
saveInfo.head_img = data.head_img; saveInfo.head_img = data.head_img
saveInfo.real_name = data.real_name; saveInfo.real_name = data.real_name
saveInfo.original_password = data.original_password; saveInfo.original_password = data.original_password
saveInfo.password = data.password; saveInfo.password = data.password
saveInfo.password_copy = data.password; saveInfo.password_copy = data.password
saveInfo.username = data.username; saveInfo.username = data.username
}).catch(() => { }).catch(() => {
loading.value = false; loading.value = false
}) })
} }
getUserInfoFn(); getUserInfoFn()
// //
const toEditPersonal = () => { const toEditPersonal = () => {
@ -76,21 +79,24 @@ const toEditPersonal = () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.personal-body){ :deep(.personal-body) {
background-color: #fff; background-color: #fff;
.el-form-item__content{
.el-input{ .el-form-item__content {
.el-input {
width: 250px; width: 250px;
} }
.el-form-item__content{
.el-form-item__content {
justify-content: space-between; justify-content: space-between;
} }
.el-button{
.el-button {
margin-left: auto; margin-left: auto;
} }
.personal-option{
.personal-option {
margin-right: auto; margin-right: auto;
} }
} }
} }</style>
</style>

View File

@ -1,215 +1,211 @@
<template> <template>
<div class="main-container w-[375px] mx-auto mt-[20px] mb-[40px] relative"> <div class="main-container w-[375px] mx-auto mt-[20px] mb-[40px] relative">
<div class="flex full-container"> <div class="flex full-container">
<iframe v-show="loadingIframe" class="w-[375px]" :src="wapPreview" frameborder="0" <iframe v-show="loadingIframe" class="w-[375px]" :src="wapPreview" frameborder="0" id="previewIframe"></iframe>
id="previewIframe"></iframe> <div v-show="loadingDev" class="w-[375px] border border-slate-100 bg-body pt-[20px] px-[20px]">
<div v-show="loadingDev" class="w-[375px] border border-slate-100 bg-body pt-[20px] px-[20px]"> <div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="font-bold text-xl mb-[40px]">{{t('developTitle')}}</div> <div class="mb-[20px] flex flex-col">
<div class="mb-[20px] flex flex-col"> <text class="mb-[10px]">{{ t('wapDomain') }}</text>
<text class="mb-[10px]">{{ t('wapDomain') }}</text> <el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable/> </div>
</div> <el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button> </div>
</div>
<div class="w-[400px] absolute bg-body top-[10%] -right-[450px]" v-if="loadingIframe"> <div class="w-[400px] absolute bg-body top-[10%] -right-[450px]" v-if="loadingIframe">
<div class="info-wrap mt-[20px]"> <div class="info-wrap mt-[20px]">
<div class="px-[20px] pb-[10px] font-bold">{{t('h5')}}</div> <div class="px-[20px] pb-[10px] font-bold">{{ t('h5') }}</div>
<el-form label-width="40px" class="px-[20px]"> <el-form label-width="40px" class="px-[20px]">
<el-form-item :label="t('link')" v-show="wapPreview"> <el-form-item :label="t('link')" v-show="wapPreview">
<el-input readonly :value="wapPreview"> <el-input readonly :value="wapPreview">
<template #append> <template #append>
<el-button @click="copyEvent(wapPreview)" class="bg-primary copy">{{ t('copy') }} <el-button @click="copyEvent(wapPreview)" class="bg-primary copy">{{ t('copy') }}
</el-button> </el-button>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label=" " v-show="wapImage"> <el-form-item label=" " v-show="wapImage">
<el-image :src="wapImage"/> <el-image :src="wapImage" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="px-[20px] pb-[10px] font-bold mt-[40px]">{{t('weapp')}}</div> <div class="px-[20px] pb-[10px] font-bold mt-[40px]">{{ t('weapp') }}</div>
<el-form label-width="40px" class="px-[20px]"> <el-form label-width="40px" class="px-[20px]">
<el-form-item label=" " v-if="weappConfig.qr_code"> <el-form-item label=" " v-if="weappConfig.qr_code">
<el-image class="w-[100px] h-[100px]" :src="img(weappConfig.qr_code)"/> <el-image class="w-[100px] h-[100px]" :src="img(weappConfig.qr_code)" />
</el-form-item> </el-form-item>
<el-form-item label=" " v-else> <el-form-item label=" " v-else>
<span class="text-gray-400">{{t('weappNotSet')}}</span> <span class="text-gray-400">{{ t('weappNotSet') }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref, reactive, watch} from 'vue' import { ref, reactive, watch } from 'vue'
import {t} from '@/lang' import { t } from '@/lang'
import {useRoute} from 'vue-router' import { useRoute } from 'vue-router'
import {getWeappConfig} from '@/app/api/weapp' import { getWeappConfig } from '@/app/api/weapp'
import {getUrl} from '@/app/api/sys' import { getUrl } from '@/app/api/sys'
import {useClipboard} from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import {ElMessage} from 'element-plus' import { ElMessage } from 'element-plus'
import {img} from '@/utils/common' import { img } from '@/utils/common'
import QRCode from "qrcode"; import QRCode from 'qrcode'
import storage from '@/utils/storage' import storage from '@/utils/storage'
const wapUrl = ref('') const wapUrl = ref('')
const wapDomain = ref('') const wapDomain = ref('')
const wapImage = ref('') const wapImage = ref('')
const wapPreview = ref('') const wapPreview = ref('')
const loadingIframe = ref(false) // iframe const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) // const loadingDev = ref(false) //
const timeIframe = ref(0) // iframe const timeIframe = ref(0) // iframe
const difference = ref(0) // 1000wap const difference = ref(0) // 1000wap
var time = new Date().getTime(); const route = useRoute()
const route = useRoute(); route.query.page = route.query.page || '' //
route.query.page = route.query.page || ''; //
getUrl().then((res: any) => { getUrl().then((res: any) => {
wapUrl.value = res.data.wap_url; wapUrl.value = res.data.wap_url
setDomain(); setDomain()
// //
if (import.meta.env.MODE == 'production') return; if (import.meta.env.MODE == 'production') return
wapDomain.value = res.data.wap_domain; wapDomain.value = res.data.wap_domain
// envwap // envwap
if (wapDomain.value) { if (wapDomain.value) {
wapUrl.value = wapDomain.value + '/wap'; wapUrl.value = wapDomain.value + '/wap'
setDomain(); setDomain()
}
let wap_domain_storage = storage.get('wap_domain');
if (wap_domain_storage) {
wapUrl.value = wap_domain_storage;
setDomain();
}
});
const save = () => {
if (wapDomain.value.trim().length == 0) {
ElMessage({
type: 'warning',
message: `${t('wapDomainPlaceholder')}`,
});
return;
}
wapUrl.value = wapDomain.value + '/wap';
setDomain();
storage.set({key: 'wap_domain', data: wapUrl.value});
loadingIframe.value = true;
loadingDev.value = false;
} }
const setDomain = () => { const wap_domain_storage = storage.get('wap_domain')
if (route.query.page) { if (wap_domain_storage) {
wapPreview.value = `${wapUrl.value}${route.query.page}`; wapUrl.value = wap_domain_storage
console.log(wapPreview.value) setDomain()
// errorCorrectionLevelLH()
QRCode.toDataURL(wapPreview.value, {errorCorrectionLevel: 'L', margin: 0, width: 100}).then(url => {
wapImage.value = url
})
timeIframe.value = new Date().getTime();
setTimeout(() => {
if (difference.value == 0) initLoad();
}, 1000 * 2);
}
} }
})
// uni-app const save = () => {
window.addEventListener('message', (event) => { if (wapDomain.value.trim().length == 0) {
try { ElMessage({
let data = JSON.parse(event.data); type: 'warning',
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) { message: `${t('wapDomainPlaceholder')}`
loadingDev.value = false; })
loadingIframe.value = true; return
var loadTime = new Date().getTime();
difference.value = loadTime - timeIframe.value;
}
} catch (e) {
initLoad();
console.log('后台接受数据错误', e)
}
}, false);
// uniapp
const postMessage = () => {
let data = JSON.stringify({
type: 'appOnReady',
message: '加载完成'
});
if (window.previewIframe) window.previewIframe.contentWindow.postMessage(data, '*');
};
//
const initLoad = () => {
loadingDev.value = true;
loadingIframe.value = false;
wapPreview.value = '';
wapImage.value = '';
} }
wapUrl.value = wapDomain.value + '/wap'
setDomain()
storage.set({ key: 'wap_domain', data: wapUrl.value })
loadingIframe.value = true
loadingDev.value = false
}
const weappConfig = reactive({ const setDomain = () => {
qr_code: '' if (route.query.page) {
wapPreview.value = `${wapUrl.value}${route.query.page}`
console.log(wapPreview.value)
// errorCorrectionLevelLH()
QRCode.toDataURL(wapPreview.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
wapImage.value = url
})
timeIframe.value = new Date().getTime()
setTimeout(() => {
if (difference.value == 0) initLoad()
}, 1000 * 2)
}
}
// uni-app
window.addEventListener('message', (event) => {
try {
const data = JSON.parse(event.data)
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
loadingDev.value = false
loadingIframe.value = true
const loadTime = new Date().getTime()
difference.value = loadTime - timeIframe.value
}
} catch (e) {
initLoad()
console.log('后台接受数据错误', e)
}
}, false)
// uniapp
const postMessage = () => {
const data = JSON.stringify({
type: 'appOnReady',
message: '加载完成'
}) })
if (window.previewIframe) window.previewIframe.contentWindow.postMessage(data, '*')
}
// //
getWeappConfig().then((res: any) => { const initLoad = () => {
if (res.code == 1) { loadingDev.value = true
let data = res.data; loadingIframe.value = false
weappConfig.qr_code = data.qr_code; wapPreview.value = ''
} wapImage.value = ''
}) }
// const weappConfig = reactive({
const {copy, isSupported, copied} = useClipboard() qr_code: ''
const copyEvent = (text: string) => { })
if (!isSupported.value) {
ElMessage({ //
message: t('notSupportCopy'), getWeappConfig().then((res: any) => {
type: 'warning' if (res.code == 1) {
}) const data = res.data
} weappConfig.qr_code = data.qr_code
copy(text)
} }
})
watch(copied, () => { //
if (copied.value) { const { copy, isSupported, copied } = useClipboard()
ElMessage({ const copyEvent = (text: string) => {
message: t('copySuccess'), if (!isSupported.value) {
type: 'success' ElMessage({
}) message: t('notSupportCopy'),
} type: 'warning'
}) })
}
copy(text)
}
watch(copied, () => {
if (copied.value) {
ElMessage({
message: t('copySuccess'),
type: 'success'
})
}
})
</script> </script>
<style lang="scss"> <style lang="scss">
body { body {
background: #edf0f3; background: #edf0f3;
} }
.copy { .copy {
background: var(--el-color-primary) !important; background: var(--el-color-primary) !important;
color: var(--el-color-white) !important; color: var(--el-color-white) !important;
} }
</style>
<style lang="scss" scoped>
</style> </style>
<style lang="scss" scoped></style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -249,7 +249,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in installCheckResult.dir.is_readable"> v-for="(item,index) in installCheckResult.dir.is_readable" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -266,7 +266,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in installCheckResult.dir.is_write"> v-for="(item,index) in installCheckResult.dir.is_write" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -308,7 +308,7 @@
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col"> <div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result> <el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
<!-- 提示信息 --> <!-- 提示信息 -->
<div v-for="item in installAfterTips" class="mb-[10px]"> <div v-for="(item,index) in installAfterTips" class="mb-[10px]" :key="index">
<el-alert :title="item" type="error" :closable="false" /> <el-alert :title="item" type="error" :closable="false" />
</div> </div>
</div> </div>
@ -333,7 +333,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" <el-row class="pb-[10px] items pl-[15px]"
v-for="item in uninstallCheckResult.dir.is_readable"> v-for="(item,index) in uninstallCheckResult.dir.is_readable" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -349,7 +349,7 @@
</span> </span>
</el-col> </el-col>
</el-row> </el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in uninstallCheckResult.dir.is_write"> <el-row class="pb-[10px] items pl-[15px]" v-for="(item,index) in uninstallCheckResult.dir.is_write" :key="index">
<el-col :span="12"> <el-col :span="12">
<span>{{ item.dir }}</span> <span>{{ item.dir }}</span>
</el-col> </el-col>
@ -394,7 +394,6 @@ import { t } from '@/lang'
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon' import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon'
import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module' import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus' import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
import { img } from '@/utils/common'
import 'vue-web-terminal/lib/theme/dark.css' import 'vue-web-terminal/lib/theme/dark.css'
import { Terminal, TerminalFlash } from 'vue-web-terminal' import { Terminal, TerminalFlash } from 'vue-web-terminal'
import { findFirstValidRoute } from '@/router/routers' import { findFirstValidRoute } from '@/router/routers'
@ -421,7 +420,7 @@ const downEventHintFn = () => {
downEvent(currDownData.value, true) downEvent(currDownData.value, true)
} }
const activeNameTabFn = (data) => { const activeNameTabFn = (data:any) => {
activeName.value = data activeName.value = data
storage.set({ key: 'storeActiveName', data }) storage.set({ key: 'storeActiveName', data })
} }
@ -563,7 +562,7 @@ const onExecCmd = (key, command, success, failed, name)=> {
} }
function makeIterator(array: string[]) { function makeIterator(array: string[]) {
var nextIndex = 0 let nextIndex = 0
return { return {
next() { next() {
if ((nextIndex + 1) == array.length) { if ((nextIndex + 1) == array.length) {
@ -614,6 +613,7 @@ const getInstallTask = (first: boolean = true) => {
} }
} }
if (res.data.error) { if (res.data.error) {
ElMessage({ message: '插件安装失败', type: 'error', duration: 5000 })
return return
} }
if (res.data.mode == 'cloud') { if (res.data.mode == 'cloud') {
@ -982,6 +982,9 @@ html.dark .table-head-bg {
height: calc(100vh - 120px); height: calc(100vh - 120px);
box-sizing: border-box; box-sizing: border-box;
} }
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style> </style>
<style> <style>

View File

@ -123,28 +123,22 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {reactive, ref, onMounted, computed} from 'vue' import { ref } from 'vue'
import {t} from '@/lang' import { useRouter } from 'vue-router'
import {getAuthaddon} from '@/app/api/auth' import useSystemStore from '@/stores/modules/system'
import {img} from '@/utils/common'
import {useRouter} from 'vue-router'
import storage from '@/utils/storage'
import {findFirstValidRoute} from '@/router/routers'
import {UserFilled} from '@element-plus/icons-vue'
import useSystemStore from '@/stores/modules/system'
const systemStore = useSystemStore()
systemStore.setHeadMenu('');
const router = useRouter() const systemStore = useSystemStore()
let developerDialogVisible = ref(false) systemStore.setHeadMenu('')
const toLink = (link)=>{ const router = useRouter()
router.push(link) const developerDialogVisible = ref(false)
}
const goRouter = () => { const toLink = (link:any) => {
window.open('https://www.niucloud.com/app') router.push(link)
} }
const goRouter = () => {
window.open('https://www.niucloud.com/app')
}
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -129,7 +129,7 @@ if (loginType.value == 'site') {
// - start // - start
const verifyRef = ref(null) const verifyRef = ref(null)
const success = (params) => { const success = (params:any) => {
loginFn({ captcha_code: params.captchaVerification }) loginFn({ captcha_code: params.captchaVerification })
} }
// - end // - end
@ -178,7 +178,7 @@ const loginFn = (data = {}) => {
const { query: { redirect } } = route const { query: { redirect } } = route
const path = typeof redirect === 'string' ? redirect : '/' const path = typeof redirect === 'string' ? redirect : '/'
router.push(path) router.push(path)
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
}) })
} }

View File

@ -1,23 +1,24 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]"> <div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="8" class="min-w-[100px]"> <el-col :span="8" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="balanceStatistics.money && balanceStatistics.balance ? (Number.parseFloat(balanceStatistics.money)+Number.parseFloat(balanceStatistics.balance)).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="balanceStatistics.money && balanceStatistics.balance ? (Number.parseFloat(balanceStatistics.money) + Number.parseFloat(balanceStatistics.balance)).toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalAllBalance') }}</span> <span>{{ t('totalAllBalance') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="8" class="min-w-[100px]"> <el-col :span="8" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="balanceStatistics.money"></el-statistic> <el-statistic :value="balanceStatistics.money"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
@ -25,9 +26,9 @@
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="8" class="min-w-[100px]"> <el-col :span="8" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="balanceStatistics.balance"></el-statistic> <el-statistic :value="balanceStatistics.balance"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
@ -35,37 +36,36 @@
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</el-card> </el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('memberInfo')" prop="keywords"> <el-form-item :label="t('memberInfo')" prop="keywords">
<el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" /> <el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]"
:placeholder="t('memberInfoPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('balanceType')" prop="from_type"> <el-form-item :label="t('balanceType')" prop="from_type">
<el-select v-model="memberAccountLogTableData.balance_type" clearable :placeholder="t('fromTypePlaceholder')" class="input-width" @change="checkAccountType"> <el-select v-model="memberAccountLogTableData.balance_type" clearable
<el-option :label="t('selectPlaceholder')" value="" /> :placeholder="t('fromTypePlaceholder')" class="input-width" @change="checkAccountType">
<el-option :label="item.name" :value="item.type" v-for="(item,key) in balanceStatus" /> <el-option :label="t('selectPlaceholder')" value="" />
</el-select> <el-option :label="item.name" :value="item.type" v-for="(item, key) in balanceStatus" :key="key"/>
</el-form-item> </el-select>
</el-form-item>
<el-form-item :label="t('fromType')" prop="from_type"> <el-form-item :label="t('fromType')" prop="from_type">
<el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable :placeholder="t('fromTypePlaceholder')" class="input-width"> <el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable
:placeholder="t('fromTypePlaceholder')" class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item.name" :value="key" v-for="(item,key) in fromTypeList" /> <el-option :label="item.name" :value="key" v-for="(item, key) in fromTypeList" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker <el-date-picker v-model="memberAccountLogTableData.searchParam.create_time" type="datetimerange"
v-model="memberAccountLogTableData.searchParam.create_time" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
type="datetimerange" :end-placeholder="t('endDate')" />
value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="t('startDate')"
:end-placeholder="t('endDate')"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button>
@ -81,48 +81,52 @@
<template #empty> <template #empty>
<span>{{ !memberAccountLogTableData.loading ? t('emptyData') : '' }}</span> <span>{{ !memberAccountLogTableData.loading ? t('emptyData') : '' }}</span>
</template> </template>
<el-table-column prop="member_id" :label="t('memberId')" min-width="80" :show-overflow-tooltip="true"> <el-table-column prop="member_id" :label="t('memberId')" min-width="80" :show-overflow-tooltip="true">
<template #default="{ row }"> <template #default="{ row }">
{{ row.member.member_no }} {{ row.member.member_no }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('memberInfo')" min-width="140" :show-overflow-tooltip="true"> <el-table-column :label="t('memberInfo')" min-width="140" :show-overflow-tooltip="true">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center cursor-pointer" @click="toMember(row.member_id)"> <div class="flex items-center cursor-pointer" @click="toMember(row.member_id)">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="" > <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" > :src="img(row.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span> <span class="">{{ row.member.nickname || '' }}</span>
</div> </div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="mobile" :label="t('mobile')" min-width="90"> <el-table-column prop="mobile" :label="t('mobile')" min-width="90">
<template #default="{ row }"> <template #default="{ row }">
{{ row.member.mobile || '' }} {{ row.member.mobile || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_data" :label="t('accountData')" min-width="70" align="right"> <el-table-column prop="account_data" :label="t('accountData')" min-width="70" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.account_data >= 0">+{{ row.account_data }}</span> <span v-if="row.account_data >= 0">+{{ row.account_data }}</span>
<span v-else>{{ row.account_data }}</span> <span v-else>{{ row.account_data }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_sum" :label="t('accountSum')" min-width="110" align="right"/> <el-table-column prop="account_sum" :label="t('accountSum')" min-width="110" align="right" />
<el-table-column prop="account_type_name" :label="t('balanceType')" min-width="150" align="center" /> <el-table-column prop="account_type_name" :label="t('balanceType')" min-width="150" align="center" />
<el-table-column prop="from_type_name" :label="t('fromType')" min-width="120" align=""/> <el-table-column prop="from_type_name" :label="t('fromType')" min-width="120" align="" />
<el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')" min-width="150" /> <el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')"
min-width="150" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="100"> <el-table-column :label="t('operation')" align="right" fixed="right" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button> <el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="memberAccountLogTableData.page" v-model:page-size="memberAccountLogTableData.limit" <el-pagination v-model:current-page="memberAccountLogTableData.page"
layout="total, sizes, prev, pager, next, jumper" :total="memberAccountLogTableData.total" v-model:page-size="memberAccountLogTableData.limit" layout="total, sizes, prev, pager, next, jumper"
@size-change="loadMemberAccountLogList()" @current-change="loadMemberAccountLogList" /> :total="memberAccountLogTableData.total" @size-change="loadMemberAccountLogList()"
@current-change="loadMemberAccountLogList" />
</div> </div>
</div> </div>
</el-card> </el-card>
@ -134,54 +138,53 @@
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { import {
getBalanceList, getBalanceList,
getChangeTypeList, getChangeTypeList,
getBalanceSum, getBalanceSum,
getBalanceStatus, getBalanceStatus,
getMoneyList, getMoneyList,
getAccountType, getAccountType
} from '@/app/api/member' } from '@/app/api/member'
import { FormInstance } from 'element-plus' import { FormInstance } from 'element-plus'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import balanceInfo from '@/app/views/member/components/member-balance-info.vue' import balanceInfo from '@/app/views/member/components/member-balance-info.vue'
import { useRoute,useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
const route = useRoute() const route = useRoute()
const member_id: number = parseInt(route.query.id || 0) const member_id: number = parseInt(route.query.id || 0)
const pageName = route.meta.title; const pageName = route.meta.title
let memberAccountLogTableData = reactive({ const memberAccountLogTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
keywords:"", keywords: '',
from_type:"", from_type: '',
create_time:"", create_time: '',
mobile:"", mobile: '',
member_id, member_id: member_id
}, },
balance_type: "" balance_type: ''
}) })
let fromTypeList = ref([]) const fromTypeList = ref([])
const setFromTypeList = async () => { const setFromTypeList = async () => {
fromTypeList.value = await (await getChangeTypeList('balance')).data fromTypeList.value = await (await getChangeTypeList('balance')).data
} }
setFromTypeList(); setFromTypeList()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined) => {
const resetForm = (formEl: FormInstance | undefined)=>{
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadMemberAccountLogList(); loadMemberAccountLogList()
} }
/** /**
@ -190,32 +193,31 @@ const resetForm = (formEl: FormInstance | undefined)=>{
const loadMemberAccountLogList = (page: number = 1) => { const loadMemberAccountLogList = (page: number = 1) => {
memberAccountLogTableData.loading = true memberAccountLogTableData.loading = true
memberAccountLogTableData.page = page memberAccountLogTableData.page = page
if(memberAccountLogTableData.balance_type == "" || memberAccountLogTableData.balance_type == "balance"){ if (memberAccountLogTableData.balance_type == '' || memberAccountLogTableData.balance_type == 'balance') {
getBalanceList({ getBalanceList({
page: memberAccountLogTableData.page, page: memberAccountLogTableData.page,
limit: memberAccountLogTableData.limit, limit: memberAccountLogTableData.limit,
...memberAccountLogTableData.searchParam ...memberAccountLogTableData.searchParam
}).then(res => { }).then(res => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
memberAccountLogTableData.data = res.data.data memberAccountLogTableData.data = res.data.data
memberAccountLogTableData.total = res.data.total memberAccountLogTableData.total = res.data.total
}).catch(() => { }).catch(() => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
}) })
}else{ } else {
getMoneyList({ getMoneyList({
page: memberAccountLogTableData.page, page: memberAccountLogTableData.page,
limit: memberAccountLogTableData.limit, limit: memberAccountLogTableData.limit,
...memberAccountLogTableData.searchParam ...memberAccountLogTableData.searchParam
}).then(res => { }).then(res => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
memberAccountLogTableData.data = res.data.data memberAccountLogTableData.data = res.data.data
memberAccountLogTableData.total = res.data.total memberAccountLogTableData.total = res.data.total
}).catch(() => { }).catch(() => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
}) })
} }
} }
loadMemberAccountLogList() loadMemberAccountLogList()
@ -224,7 +226,7 @@ const balanceDialog: Record<string, any> | null = ref(null)
* 查看详情 * 查看详情
* @param data * @param data
*/ */
const infoEvent = (data: any) => { const infoEvent = (data: any) => {
balanceDialog.value.setFormData(data) balanceDialog.value.setFormData(data)
balanceDialog.value.showDialog = true balanceDialog.value.showDialog = true
} }
@ -234,7 +236,7 @@ const router = useRouter()
/** /**
* 会员详情 * 会员详情
*/ */
const toMember = (member_id:number) => { const toMember = (member_id: number) => {
router.push(`/member/detail?id=${member_id}`) router.push(`/member/detail?id=${member_id}`)
} }
@ -243,37 +245,37 @@ const toMember = (member_id:number) => {
*/ */
const balanceStatistics = ref([]) const balanceStatistics = ref([])
const checkBalanceInfo = () => { const checkBalanceInfo = () => {
getBalanceSum({ getBalanceSum({
member_id member_id
}).then(res => { }).then(res => {
balanceStatistics.value = res.data; balanceStatistics.value = res.data
}) })
} }
checkBalanceInfo() checkBalanceInfo()
// //
const balanceStatus = ref([]) const balanceStatus = ref([])
const checkBalanceStatus = () => { const checkBalanceStatus = () => {
getBalanceStatus().then(res => { getBalanceStatus().then(res => {
for (var i in res.data) { for (var i in res.data) {
if(i == 'balance' || i == 'money'){ if (i == 'balance' || i == 'money') {
balanceStatus.value.push({"name" : res.data[i], "type" : i}) balanceStatus.value.push({ 'name': res.data[i], 'type': i })
} }
} }
}) })
} }
checkBalanceStatus() checkBalanceStatus()
const checkAccountType = () => { const checkAccountType = () => {
let account_type = memberAccountLogTableData.balance_type; let account_type = memberAccountLogTableData.balance_type
if(memberAccountLogTableData.balance_type == ""){ if (memberAccountLogTableData.balance_type == '') {
account_type = "balance" account_type = 'balance'
} }
getAccountType({ getAccountType({
account_type account_type
}).then(res => { }).then(res => {
fromTypeList.value = res.data; fromTypeList.value = res.data
}) })
} }
checkAccountType() checkAccountType()

View File

@ -2,72 +2,74 @@
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]"> <div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="6" class="min-w-[100px]"> <el-col :span="6" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="commissionStatistics.total_commission ? Number.parseFloat(commissionStatistics.total_commission).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="commissionStatistics.total_commission ? Number.parseFloat(commissionStatistics.total_commission).toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('totalCommission') }}</span> <span>{{ t('totalCommission') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="6" class="min-w-[100px]"> <el-col :span="6" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="commissionStatistics.commission ? Number.parseFloat(commissionStatistics.commission).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="commissionStatistics.commission ? Number.parseFloat(commissionStatistics.commission).toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('commission') }}</span> <span>{{ t('commission') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="6" class="min-w-[100px]"> <el-col :span="6" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="commissionStatistics.withdrawn_commission ? Number.parseFloat(commissionStatistics.withdrawn_commission).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="commissionStatistics.withdrawn_commission ? Number.parseFloat(commissionStatistics.withdrawn_commission).toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('withdrawnCommission') }}</span> <span>{{ t('withdrawnCommission') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="6" class="min-w-[100px]"> <el-col :span="6" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="commissionStatistics.commission_cash_outing ? Number.parseFloat(commissionStatistics.commission_cash_outing).toFixed(2) : '0.00'"></el-statistic> <el-statistic
:value="commissionStatistics.commission_cash_outing ? Number.parseFloat(commissionStatistics.commission_cash_outing).toFixed(2) : '0.00'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('cashOutingCommission') }}</span> <span>{{ t('cashOutingCommission') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</el-card> </el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('memberInfo')" prop="keywords"> <el-form-item :label="t('memberInfo')" prop="keywords">
<el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" /> <el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]"
:placeholder="t('memberInfoPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('fromType')" prop="from_type"> <el-form-item :label="t('fromType')" prop="from_type">
<el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable :placeholder="t('fromTypePlaceholder')" class="input-width"> <el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable
:placeholder="t('fromTypePlaceholder')" class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item.name" :value="key" v-for="(item,key) in fromTypeList" /> <el-option :label="item.name" :value="key" v-for="(item, key) in fromTypeList" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker <el-date-picker v-model="memberAccountLogTableData.searchParam.create_time" type="datetimerange"
v-model="memberAccountLogTableData.searchParam.create_time" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
type="datetimerange" :end-placeholder="t('endDate')" />
value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="t('startDate')"
:end-placeholder="t('endDate')"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button>
@ -89,45 +91,49 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('memberInfo')" min-width="150" :show-overflow-tooltip="true"> <el-table-column :label="t('memberInfo')" min-width="150" :show-overflow-tooltip="true">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center cursor-pointer" @click="toMember(row.member_id)"> <div class="flex items-center cursor-pointer" @click="toMember(row.member_id)">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="" > <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" > :src="img(row.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span> <span class="">{{ row.member.nickname || '' }}</span>
</div> </div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="mobile" :label="t('mobile')" min-width="100"> <el-table-column prop="mobile" :label="t('mobile')" min-width="100">
<template #default="{ row }"> <template #default="{ row }">
{{ row.member.mobile || '' }} {{ row.member.mobile || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_data" :label="t('accountData')" min-width="80" align="right"> <el-table-column prop="account_data" :label="t('accountData')" min-width="80" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.account_data >= 0">+{{ row.account_data }}</span> <span v-if="row.account_data >= 0">+{{ row.account_data }}</span>
<span v-else>{{ row.account_data }}</span> <span v-else>{{ row.account_data }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_sum" :label="t('accountSum')" min-width="120" align="right"/> <el-table-column prop="account_sum" :label="t('accountSum')" min-width="120" align="right" />
<el-table-column prop="from_type_name" :label="t('fromType')" min-width="180" align="center"/> <el-table-column prop="from_type_name" :label="t('fromType')" min-width="180" align="center" />
<el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')" min-width="150" /> <el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')"
min-width="150" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="100"> <el-table-column :label="t('operation')" align="right" fixed="right" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button> <el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="memberAccountLogTableData.page" v-model:page-size="memberAccountLogTableData.limit" <el-pagination v-model:current-page="memberAccountLogTableData.page"
layout="total, sizes, prev, pager, next, jumper" :total="memberAccountLogTableData.total" v-model:page-size="memberAccountLogTableData.limit" layout="total, sizes, prev, pager, next, jumper"
@size-change="loadMemberAccountLogList()" @current-change="loadMemberAccountLogList" /> :total="memberAccountLogTableData.total" @size-change="loadMemberAccountLogList()"
@current-change="loadMemberAccountLogList" />
</div> </div>
</div> </div>
</el-card> </el-card>
@ -139,58 +145,57 @@
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { FormInstance } from 'element-plus' import { FormInstance } from 'element-plus'
import { getChangeTypeList,getCommissionList,getCommissionSum } from '@/app/api/member' import { getChangeTypeList, getCommissionList, getCommissionSum } from '@/app/api/member'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import moneyInfo from '@/app/views/member/components/member-commission-info.vue' import moneyInfo from '@/app/views/member/components/member-commission-info.vue'
import { useRouter,useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const member_id: number = parseInt(route.query.id || 0) const member_id: number = parseInt(route.query.id || 0)
const pageName = route.meta.title; const pageName = route.meta.title
let memberAccountLogTableData = reactive({ const memberAccountLogTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
keywords:"", keywords: '',
from_type:"", from_type: '',
create_time:"", create_time: '',
mobile:"", mobile: '',
member_id:member_id member_id: member_id
} }
}) })
const fromTypeList = ref([])
let fromTypeList = ref([])
const setFromTypeList = async () => { const setFromTypeList = async () => {
fromTypeList.value = await (await getChangeTypeList('commission')).data fromTypeList.value = await (await getChangeTypeList('commission')).data
} }
setFromTypeList(); setFromTypeList()
/** /**
* 获取佣金总计 * 获取佣金总计
*/ */
const commissionStatistics = ref([]) const commissionStatistics = ref([])
const checkCommissionInfo = () => { const checkCommissionInfo = () => {
getCommissionSum({ getCommissionSum({
member_id member_id
}).then(res => { }).then(res => {
commissionStatistics.value = res.data; commissionStatistics.value = res.data
}) })
} }
checkCommissionInfo() checkCommissionInfo()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadMemberAccountLogList(); loadMemberAccountLogList()
} }
/** /**
@ -204,7 +209,7 @@ const loadMemberAccountLogList = (page: number = 1) => {
getCommissionList({ getCommissionList({
page: memberAccountLogTableData.page, page: memberAccountLogTableData.page,
limit: memberAccountLogTableData.limit, limit: memberAccountLogTableData.limit,
...memberAccountLogTableData.searchParam ...memberAccountLogTableData.searchParam
}).then(res => { }).then(res => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
memberAccountLogTableData.data = res.data.data memberAccountLogTableData.data = res.data.data
@ -221,7 +226,7 @@ const moneyDialog: Record<string, any> | null = ref(null)
* 查看详情 * 查看详情
* @param data * @param data
*/ */
const infoEvent = (data: any) => { const infoEvent = (data: any) => {
moneyDialog.value.setFormData(data) moneyDialog.value.setFormData(data)
moneyDialog.value.showDialog = true moneyDialog.value.showDialog = true
} }
@ -231,11 +236,10 @@ const router = useRouter()
/** /**
* 会员详情 * 会员详情
*/ */
const toMember = (member_id:number) => { const toMember = (member_id: number) => {
router.push(`/member/detail?id=${member_id}`) router.push(`/member/detail?id=${member_id}`)
} }
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -28,9 +28,9 @@ import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { addMemberLabel, updateMemberLabel, getMemberLabelInfo } from '@/app/api/member' import { addMemberLabel, updateMemberLabel, getMemberLabelInfo } from '@/app/api/member'
let showDialog = ref(false) const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
let popTitle:string = ''; let popTitle:string = ''
/** /**
* 表单数据 * 表单数据
@ -39,7 +39,7 @@ const initialFormData = {
label_id: '', label_id: '',
label_name: '', label_name: '',
memo: '', memo: '',
sort: 0, sort: 0
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -49,19 +49,19 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
label_name: [ label_name: [
{ required: true, message: t('labelNamePlaceholder'), trigger: 'blur' } { required: true, message: t('labelNamePlaceholder'), trigger: 'blur' }
], ],
sort:[ sort: [
{ validator: sortVerify, trigger: 'blur' } { validator: sortVerify, trigger: 'blur' }
] ]
} }
}) })
const sortVerify = (rule: any, value: any, callback: any) => { const sortVerify = (rule: any, value: any, callback: any) => {
if (value < 0) { if (value < 0) {
callback(new Error(t('sortVerifyOne'))) callback(new Error(t('sortVerifyOne')))
} else if (value.toString().indexOf(".") != -1) { } else if (value.toString().indexOf('.') != -1) {
callback(new Error(t('sortVerifyTwo'))) callback(new Error(t('sortVerifyTwo')))
} else { } else {
callback() callback()
@ -76,19 +76,19 @@ const emit = defineEmits(['complete'])
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.label_id ? updateMemberLabel : addMemberLabel const save = formData.label_id ? updateMemberLabel : addMemberLabel
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData const data = formData
save(data).then(res => { save(data).then(res => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
// showDialog.value = false // showDialog.value = false
}) })
@ -100,15 +100,16 @@ const setFormData = async (row: any = null) => {
loading.value = true loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
popTitle = t('addMemberLabel') popTitle = t('addMemberLabel')
if(row){ if (row) {
popTitle = t('updateMemberLabel') popTitle = t('updateMemberLabel')
const data = await (await getMemberLabelInfo(row.label_id)).data const data = await (await getMemberLabelInfo(row.label_id)).data
if (data) Object.keys(formData).forEach((key: string) => { if (data) {
if (data[key] != undefined) formData[key] = data[key] Object.keys(formData).forEach((key: string) => {
}) if (data[key] != undefined) formData[key] = data[key]
})
}
} }
loading.value = false loading.value = false
} }
defineExpose({ defineExpose({

View File

@ -13,12 +13,12 @@
</el-form-item> </el-form-item>
<el-form-item :label="t('sex')" v-if="type == 'sex'"> <el-form-item :label="t('sex')" v-if="type == 'sex'">
<el-select v-model="saveData.sex" clearable :placeholder="t('sexPlaceholder')" class="input-width"> <el-select v-model="saveData.sex" clearable :placeholder="t('sexPlaceholder')" class="input-width">
<el-option :label="item['name']" :value="item['id']" v-for="item in sexSelectData" /> <el-option :label="item['name']" :value="item['id']" v-for="(item,index) in sexSelectData" :key="index" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('memberLabel')" v-if="type == 'member_label'"> <el-form-item :label="t('memberLabel')" v-if="type == 'member_label'">
<el-select v-model="saveData.member_label" multiple collapse-tags :placeholder="t('memberLabelPlaceholder')" class="input-width"> <el-select v-model="saveData.member_label" multiple collapse-tags :placeholder="t('memberLabelPlaceholder')" class="input-width">
<el-option :label="item['label_name']" :value="item['label_id']" v-for="item in labelSelectData" /> <el-option :label="item['label_name']" :value="item['label_id']" v-for="(item,index) in labelSelectData" :key="index"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -39,11 +39,11 @@ import type { FormInstance } from 'element-plus'
import { editMemberDetail, getMemberLabelAll } from '@/app/api/member' import { editMemberDetail, getMemberLabelAll } from '@/app/api/member'
// //
let type = ref('') const type = ref('')
let title = ref('') const title = ref('')
// id // id
let memberId = ref('') const memberId = ref('')
let showDialog = ref(false) const showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
const sexSelectData = ref([ const sexSelectData = ref([
{ {
@ -58,14 +58,13 @@ const sexSelectData = ref([
id: 2, id: 2,
name: t('girlSex') name: t('girlSex')
} }
]); ])
let labelSelectData = ref(null) const labelSelectData = ref(null)
// //
const getMemberLabelAllFn = async () => { const getMemberLabelAllFn = async () => {
labelSelectData.value = await (await getMemberLabelAll()).data labelSelectData.value = await (await getMemberLabelAll()).data
} }
getMemberLabelAllFn(); getMemberLabelAllFn()
/** /**
* 表单数据 * 表单数据
@ -79,7 +78,6 @@ const initialFormData = {
} }
const saveData: Record<string, any> = reactive({ ...initialFormData }) const saveData: Record<string, any> = reactive({ ...initialFormData })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
/** /**
@ -88,7 +86,7 @@ const emit = defineEmits(['complete'])
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
loading.value = true loading.value = true
let data = ref({ const data = ref({
member_id: memberId.value, member_id: memberId.value,
field: type.value, field: type.value,
value: saveData[type.value] value: saveData[type.value]
@ -98,25 +96,24 @@ const confirm = async (formEl: FormInstance | undefined) => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
// showDialog.value = false // showDialog.value = false
}) })
} }
const setDialogType = async (row: any = null) => { const setDialogType = async (row: any = null) => {
loading.value = true; loading.value = true
type.value = row.type; type.value = row.type
title.value = row.title; title.value = row.title
memberId.value = row.id; memberId.value = row.id
saveData[type.value] = row.data[type.value] saveData[type.value] = row.data[type.value]
if (type.value == "member_label" && saveData[type.value]) { if (type.value == 'member_label' && saveData[type.value]) {
saveData[type.value].forEach((item, index) => { saveData[type.value].forEach((item:any, index:any) => {
saveData[type.value][index] = Number.parseFloat(item); saveData[type.value][index] = Number.parseFloat(item)
}); })
} }
loading.value = false; loading.value = false
} }
defineExpose({ defineExpose({

View File

@ -36,7 +36,6 @@
import { ref, reactive, computed } from 'vue' import { ref, reactive, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common'
import { adjustBalance } from '@/app/api/member' import { adjustBalance } from '@/app/api/member'
const showDialog = ref(false) const showDialog = ref(false)
@ -47,11 +46,11 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
member_id: 0, member_id: 0,
balance:'', balance: '',
memo:'', memo: '',
adjust:'', adjust: '',
account_data:'', account_data: '',
adjust_type:1, adjust_type: 1
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -64,9 +63,9 @@ const formRules = computed(() => {
{ required: true, message: t('adjustBalancePlaceholder'), trigger: 'blur' }, { required: true, message: t('adjustBalancePlaceholder'), trigger: 'blur' },
{ {
validator: (rule: any, value: string, callback: any) => { validator: (rule: any, value: string, callback: any) => {
let adjust = Math.abs(parseFloat(formData.adjust)); const adjust = Math.abs(parseFloat(formData.adjust))
if(!adjust){ if (!adjust) {
callback(new Error(t('adjustBalancePlaceholder'))) callback(new Error(t('adjustBalancePlaceholder')))
} }
@ -78,7 +77,7 @@ const formRules = computed(() => {
}, },
trigger: 'blur' trigger: 'blur'
} }
], ]
} }
}) })
@ -86,20 +85,20 @@ const formRules = computed(() => {
* 确认 * 确认
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
formData.account_data = Math.abs(parseFloat(formData.adjust)) * formData.adjust_type; formData.account_data = Math.abs(parseFloat(formData.adjust)) * formData.adjust_type
let data = formData const data = formData
adjustBalance(data).then(res => { adjustBalance(data).then(res => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
// showDialog.value = false // showDialog.value = false
}) })
@ -107,7 +106,6 @@ const formRules = computed(() => {
}) })
} }
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {

View File

@ -61,20 +61,20 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
account_data: 0, account_data: 0,
account_type:'', account_type: '',
create_time:'', create_time: '',
from_type:'', from_type: '',
from_type_name:'', from_type_name: '',
member_id:'', member_id: '',
memo:'', memo: '',
related_id:'', related_id: '',
member: { member: {
headimg:'', headimg: '',
mobile:'', mobile: '',
member_no: '', member_no: '',
username:'', username: '',
nickname:'', nickname: ''
} }
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -87,10 +87,10 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {

View File

@ -1,39 +1,41 @@
<template> <template>
<el-dialog v-model="showDialog" :title="t('moneyInfo')" width="550px" :destroy-on-close="true"> <el-dialog v-model="showDialog" :title="t('moneyInfo')" width="550px" :destroy-on-close="true">
<el-form :model="formData" label-width="110px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading"> <el-form :model="formData" label-width="110px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form-item :label="t('headimg')" > <el-form-item :label="t('headimg')">
<div class="flex items-center"> <div class="flex items-center">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="formData.member.headimg" :src="img(formData.member.headimg)" alt="" > <img class="w-[50px] h-[50px] mr-[10px]" v-if="formData.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" > :src="img(formData.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="">
</div> </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('memberId')" > <el-form-item :label="t('memberId')">
<div class="input-width"> {{ formData.member.member_no }} </div> <div class="input-width"> {{ formData.member.member_no }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('nickName')" > <el-form-item :label="t('nickName')">
<div class="input-width"> {{ formData.member.nickname }} </div> <div class="input-width"> {{ formData.member.nickname }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('mobile')" > <el-form-item :label="t('mobile')">
<div class="input-width"> {{ formData.member.mobile }} </div> <div class="input-width"> {{ formData.member.mobile }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('accountData')" > <el-form-item :label="t('accountData')">
<div class="input-width"> {{ formData.account_data }} </div> <div class="input-width"> {{ formData.account_data }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('fromType')" > <el-form-item :label="t('fromType')">
<div class="input-width"> {{ formData.from_type_name }} </div> <div class="input-width"> {{ formData.from_type_name }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('memo')" > <el-form-item :label="t('memo')">
<div class="input-width"> {{ formData.memo }} </div> <div class="input-width"> {{ formData.memo }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" > <el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.create_time }} </div> <div class="input-width"> {{ formData.create_time }} </div>
</el-form-item> </el-form-item>
@ -61,20 +63,20 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
account_data: 0, account_data: 0,
account_type:'', account_type: '',
create_time:'', create_time: '',
from_type:'', from_type: '',
from_type_name:"", from_type_name: '',
member_id:'', member_id: '',
memo:'', memo: '',
related_id:'', related_id: '',
member: { member: {
headimg:'', headimg: '',
mobile:'', mobile: '',
member_no: '', member_no: '',
username:'', username: '',
nickname:'', nickname: ''
} }
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -87,10 +89,10 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {

View File

@ -57,17 +57,17 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
account_data: 0, account_data: 0,
account_type:'', account_type: '',
create_time:'', create_time: '',
from_type:'', from_type: '',
from_type_name:"", from_type_name: '',
headimg:'', headimg: '',
member_id:'', member_id: '',
memo:'', memo: '',
mobile:'', mobile: '',
nickname:'', nickname: '',
related_id:'', related_id: '',
username:'' username: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -81,10 +81,10 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {

View File

@ -36,7 +36,6 @@
import { ref, reactive, computed } from 'vue' import { ref, reactive, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common'
import { adjustPoint } from '@/app/api/member' import { adjustPoint } from '@/app/api/member'
const showDialog = ref(false) const showDialog = ref(false)
@ -47,11 +46,11 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
member_id: 0, member_id: 0,
point:'', point: '',
memo:'', memo: '',
adjust:'', adjust: '',
account_data:'', account_data: '',
adjust_type:1, adjust_type: 1
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -64,11 +63,11 @@ const formRules = computed(() => {
{ required: true, message: t('adjustPointPlaceholder'), trigger: 'blur' }, { required: true, message: t('adjustPointPlaceholder'), trigger: 'blur' },
{ {
validator: (rule: any, value: string, callback: any) => { validator: (rule: any, value: string, callback: any) => {
formData.adjust = Math.floor(formData.adjust); formData.adjust = Math.floor(formData.adjust)
let adjust = Math.abs(parseFloat(formData.adjust)); const adjust = Math.abs(parseFloat(formData.adjust))
if(!adjust){ if (!adjust) {
callback(new Error(t('adjustPointPlaceholder'))) callback(new Error(t('adjustPointPlaceholder')))
} }
@ -80,7 +79,7 @@ const formRules = computed(() => {
}, },
trigger: 'blur' trigger: 'blur'
} }
], ]
} }
}) })
@ -88,20 +87,20 @@ const formRules = computed(() => {
* 确认 * 确认
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
formData.account_data = Math.abs(parseFloat(formData.adjust)) * formData.adjust_type; formData.account_data = Math.abs(parseFloat(formData.adjust)) * formData.adjust_type;
let data = formData const data = formData
adjustPoint(data).then(res => { adjustPoint(data).then(res => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}).catch(err => { }).catch(() => {
loading.value = false loading.value = false
// showDialog.value = false // showDialog.value = false
}) })
@ -112,7 +111,7 @@ const formRules = computed(() => {
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {

View File

@ -61,20 +61,20 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
account_data: 0, account_data: 0,
account_type:'', account_type: '',
create_time:'', create_time: '',
from_type:'', from_type: '',
from_type_name:"", from_type_name: '',
member_id:'', member_id: '',
memo:'', memo: '',
related_id:'', related_id: '',
member: { member: {
headimg:'', headimg: '',
mobile:'', mobile: '',
member_no: '', member_no: '',
username:'', username: '',
nickname:'', nickname: ''
} }
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -87,10 +87,10 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {

View File

@ -59,25 +59,25 @@ import EditMemberLabel from '@/app/views/member/components/edit-label.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
let memberLabelTableData = reactive({ const memberLabelTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
"label_name":"" label_name: ''
} }
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadMemberLabelList(); loadMemberLabelList()
} }
/** /**

View File

@ -3,31 +3,37 @@
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">{{ t('addMember') }}</el-button> <el-button type="primary" @click="addEvent">{{ t('addMember') }}</el-button>
</div> </div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="memberTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="memberTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('memberInfo')" prop="keyword"> <el-form-item :label="t('memberInfo')" prop="keyword">
<el-input v-model="memberTableData.searchParam.keyword" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" /> <el-input v-model="memberTableData.searchParam.keyword" class="w-[240px]"
:placeholder="t('memberInfoPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('registerChannel')" prop="register_channel"> <el-form-item :label="t('registerChannel')" prop="register_channel">
<el-select v-model="memberTableData.searchParam.register_channel" clearable :placeholder="t('channelPlaceholder')" class="input-width"> <el-select v-model="memberTableData.searchParam.register_channel" clearable
:placeholder="t('channelPlaceholder')" class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item" :value="key" v-for="(item, key) in channelList" /> <el-option :label="item" :value="key" v-for="(item, key) in channelList" :key="key" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('memberLabel')" prop="member_label"> <el-form-item :label="t('memberLabel')" prop="member_label">
<el-select v-model="memberTableData.searchParam.member_label" collapse-tags clearable :placeholder="t('memberLabelPlaceholder')" class="input-width"> <el-select v-model="memberTableData.searchParam.member_label" collapse-tags clearable
<el-option :label="t('selectPlaceholder')" value=""/> :placeholder="t('memberLabelPlaceholder')" class="input-width">
<el-option :label="item['label_name']" :value="item['label_id']" v-for="item in labelSelectData" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item['label_name']" :value="item['label_id']"
v-for="(item, index) in labelSelectData" :key="index" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="memberTableData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" /> <el-date-picker v-model="memberTableData.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-form-item> <el-form-item>
<el-button type="primary" @click="loadMemberList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadMemberList()">{{ t('search') }}</el-button>
@ -46,7 +52,8 @@
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center"> <div class="flex items-center">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.headimg" :src="img(row.headimg)" alt=""> <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.headimg" :src="img(row.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt=""> <img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span>{{ row.nickname || '' }}</span> <span>{{ row.nickname || '' }}</span>
</div> </div>
@ -63,21 +70,24 @@
<el-table-column prop="member_label" :label="t('lable')" min-width="120" align="center"> <el-table-column prop="member_label" :label="t('lable')" min-width="120" align="center">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<div v-for="(item, key) in row.member_label_array" class="my-[3px]"> <div v-for="(item, key) in row.member_label_array" class="my-[3px]" :key="key">
<el-tag class="ml-[13px]" type="info">{{item.label_name}}</el-tag> <el-tag class="ml-[13px]" type="info">{{ item.label_name }}</el-tag>
</div> </div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="register_channel_name" :label="t('registerChannel')" min-width="110" align="center"/> <el-table-column prop="register_channel_name" :label="t('registerChannel')" min-width="110"
align="center" />
<el-table-column prop="member_label" :label="t('status')" min-width="120" align="center"> <el-table-column prop="member_label" :label="t('status')" min-width="120" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag type="success" v-if="row.status == 1" @click="lockMember(row, 0)" class="cursor-pointer">{{t('normal')}}</el-tag> <el-tag type="success" v-if="row.status == 1" @click="lockMember(row, 0)"
<el-tag type="error" v-else @click="lockMember(row, 1)" class="cursor-pointer">{{t('lock')}}</el-tag> class="cursor-pointer">{{ t('normal') }}</el-tag>
</template> <el-tag type="error" v-else @click="lockMember(row, 1)"
</el-table-column> class="cursor-pointer">{{ t('lock') }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('createTime')" min-width="150" align="center"> <el-table-column :label="t('createTime')" min-width="150" align="center">
<template #default="{ row }"> <template #default="{ row }">
{{ row.create_time || '' }} {{ row.create_time || '' }}
@ -117,15 +127,14 @@
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { addMember, getRegisterChannelType, getMemberList, getMemberLabelAll, editMemberStatus,deleteMember } from '@/app/api/member' import { addMember, getRegisterChannelType, getMemberList, getMemberLabelAll, editMemberStatus, deleteMember } from '@/app/api/member'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox, FormInstance } from 'element-plus'
import { useRouter } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import AddMember from '@/app/views/member/components/add-member.vue' import AddMember from '@/app/views/member/components/add-member.vue'
import EditMember from '@/app/views/member/components/edit-member.vue' import EditMember from '@/app/views/member/components/edit-member.vue'
import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
const memberTableData = reactive({ const memberTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
@ -136,7 +145,7 @@ const memberTableData = reactive({
keyword: '', keyword: '',
register_type: '', register_type: '',
member_label: '', member_label: '',
register_channel:'', register_channel: '',
create_time: [] create_time: []
} }
}) })
@ -148,21 +157,19 @@ const channelList = ref([])
const setChannelList = async () => { const setChannelList = async () => {
channelList.value = await (await getRegisterChannelType({})).data channelList.value = await (await getRegisterChannelType({})).data
} }
setChannelList(); setChannelList()
// //
let labelSelectData = ref([]) const labelSelectData = ref([])
const getMemberLabelAllFn = async () => { const getMemberLabelAllFn = async () => {
labelSelectData.value = await (await getMemberLabelAll()).data labelSelectData.value = await (await getMemberLabelAll()).data
} }
getMemberLabelAllFn(); getMemberLabelAllFn()
const resetForm = (formEl: FormInstance | undefined) => {
const resetForm = (formEl: FormInstance | undefined)=>{
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadMemberList(); loadMemberList()
} }
// //
@ -188,30 +195,29 @@ const router = useRouter()
const addMemberDialog: Record<string, any> | null = ref(null) const addMemberDialog: Record<string, any> | null = ref(null)
const editMemberDialog: Record<string, any> | null = ref(null) const editMemberDialog: Record<string, any> | null = ref(null)
/** /**
* 获取标签 * 获取标签
*/ */
function memberLable(res: any) { function memberLable(res: any) {
let data; let data
if (!res.member_label_array) return ''; if (!res.member_label_array) return ''
data = res.member_label_array.map((item) => { data = res.member_label_array.map((item:any) => {
return item.label_name; return item.label_name
}); })
data = data.toString(); data = data.toString()
return data return data
} }
/** /**
* 设置标签 * 设置标签
*/ */
function setMemberLable(res: any) { function setMemberLable (res: any) {
let data = ref({ const data = ref({
type: 'member_label', type: 'member_label',
id: res.member_id, id: res.member_id,
title: t('setLable'), title: t('setLable'),
data: res data: res
}); })
editMemberDialog.value.setDialogType(data.value) editMemberDialog.value.setDialogType(data.value)
editMemberDialog.value.showDialog = true editMemberDialog.value.showDialog = true
} }
@ -220,7 +226,6 @@ function setMemberLable(res: any) {
* 删除 * 删除
*/ */
function deleteEvent(res: any) { function deleteEvent(res: any) {
ElMessageBox.confirm(t('memberDeleteTips'), t('warning'), ElMessageBox.confirm(t('memberDeleteTips'), t('warning'),
{ {
confirmButtonText: t('confirm'), confirmButtonText: t('confirm'),
@ -229,14 +234,12 @@ function deleteEvent(res: any) {
} }
).then(() => { ).then(() => {
deleteMember(res.member_id).then(() => { deleteMember(res.member_id).then(() => {
loadMemberList(); loadMemberList()
}).catch(() => { }).catch(() => {
}) })
}) })
} }
/** /**
* 添加会员 * 添加会员
*/ */
@ -261,7 +264,7 @@ const detailEvent = (data: any) => {
/** /**
* 变更会员状态 * 变更会员状态
*/ */
const lockMember = (res, status) => { const lockMember = (res:any, status:any) => {
editMemberStatus({ editMemberStatus({
status: status, status: status,
member_ids: [res.member_id] member_ids: [res.member_id]

View File

@ -237,16 +237,16 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getMemberInfo } from '@/app/api/member' import { getMemberInfo } from '@/app/api/member'
import { ElMessageBox, FormInstance, ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import PointEdit from '@/app/views/member/components/member-point-edit.vue' import PointEdit from '@/app/views/member/components/member-point-edit.vue'
import BalanceEdit from '@/app/views/member/components/member-balance-edit.vue' import BalanceEdit from '@/app/views/member/components/member-balance-edit.vue'
import EditMember from '@/app/views/member/components/edit-member.vue' import EditMember from '@/app/views/member/components/edit-member.vue'
import colorGradient from '../../../../uniapp/src/uni_modules/vk-uview-ui/libs/function/colorGradient' // import colorGradient from '../../../../uniapp/src/uni_modules/vk-uview-ui/libs/function/colorGradient'
import useAppStore from '@/stores/modules/app' import useAppStore from '@/stores/modules/app'
const route = useRoute() const route = useRoute()
@ -260,34 +260,34 @@ const id: number = parseInt(route.query.id || 0)
const formData: any = reactive({ member_label_name: '' }) const formData: any = reactive({ member_label_name: '' })
const getMemberInfoFn = async () => { const getMemberInfoFn = async () => {
loading.value = true loading.value = true
if (id) { if (id) {
const data = await (await getMemberInfo(id)).data const data = await (await getMemberInfo(id)).data
if (!data || Object.keys(data).length == 0) { if (!data || Object.keys(data).length == 0) {
ElMessage.error(t('memberNull')) ElMessage.error(t('memberNull'))
setTimeout(() => { setTimeout(() => {
router.go(-1) router.go(-1)
}, 2000) }, 2000)
return false return false
} }
Object.keys(data).forEach((item) => { Object.keys(data).forEach((item) => {
formData[item] = data[item] formData[item] = data[item]
}) })
if (formData?.member_label_array && Object.keys(formData.member_label_array)?.length) { if (formData?.member_label_array && Object.keys(formData.member_label_array)?.length) {
formData.member_label = Object.values(formData.member_label_array).map((item: any, index) => { formData.member_label = Object.values(formData.member_label_array).map((item: any, index) => {
return item.label_id return item.label_id
}) })
formData.member_label_name = Object.values(formData.member_label_array).map((item: any, index) => { formData.member_label_name = Object.values(formData.member_label_array).map((item: any, index) => {
return item.label_name return item.label_name
}) })
} }
loading.value = false loading.value = false
} else { } else {
loading.value = false loading.value = false
} }
} }
getMemberInfoFn() getMemberInfoFn()
@ -299,29 +299,29 @@ const editMemberDialog: Record<string, any> | null = ref(null)
* 修改会员信息 * 修改会员信息
*/ */
const editMemberInfo = (type: any) => { const editMemberInfo = (type: any) => {
const data = ref({ const data = ref({
type, type,
id, id,
data: formData data: formData
}) })
editMemberDialog.value.setDialogType(data.value) editMemberDialog.value.setDialogType(data.value)
editMemberDialog.value.showDialog = true editMemberDialog.value.showDialog = true
} }
/** /**
* 调整积分 * 调整积分
*/ */
const adjustPoint = (data: any) => { const adjustPoint = (data: any) => {
pointDialog.value.setFormData(data) pointDialog.value.setFormData(data)
pointDialog.value.showDialog = true pointDialog.value.showDialog = true
} }
/** /**
* 调整余额 * 调整余额
*/ */
const adjustBalance = (data: any) => { const adjustBalance = (data: any) => {
balanceDialog.value.setFormData(data) balanceDialog.value.setFormData(data)
balanceDialog.value.showDialog = true balanceDialog.value.showDialog = true
} }
const router = useRouter() const router = useRouter()
@ -330,21 +330,21 @@ const router = useRouter()
* 积分详情 * 积分详情
*/ */
const infoPoint = () => { const infoPoint = () => {
router.push(`/member/point?id=${id}`) router.push(`/member/point?id=${id}`)
} }
/** /**
* 余额详情 * 余额详情
*/ */
const infoBalance = () => { const infoBalance = () => {
router.push(`/member/balance?id=${id}`) router.push(`/member/balance?id=${id}`)
} }
/** /**
* 佣金详情 * 佣金详情
*/ */
const infoCommission = () => { const infoCommission = () => {
router.push(`/member/commission?id=${id}`) router.push(`/member/commission?id=${id}`)
} }
</script> </script>

View File

@ -2,52 +2,52 @@
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]"> <div class="flex justify-between items-center mb-[5px]">
<span class="text-[20x]">{{pageName}}</span> <span class="text-[20x]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="12" class="min-w-[100px]"> <el-col :span="12" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="pointStatistics.point_get ? Number.parseInt(pointStatistics.point_get) : '0'"></el-statistic> <el-statistic
:value="pointStatistics.point_get ? Number.parseInt(pointStatistics.point_get) : '0'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('pointGet') }}</span> <span>{{ t('pointGet') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :span="12" class="min-w-[100px]"> <el-col :span="12" class="min-w-[100px]">
<div class="statistic-card"> <div class="statistic-card">
<el-statistic :value="pointStatistics.point_use ? Number.parseInt(pointStatistics.point_use) : '0'"></el-statistic> <el-statistic
:value="pointStatistics.point_use ? Number.parseInt(pointStatistics.point_use) : '0'"></el-statistic>
<div class="statistic-footer"> <div class="statistic-footer">
<div class="footer-item text-[14px] text-[#666]"> <div class="footer-item text-[14px] text-[#666]">
<span>{{ t('pointUse') }}</span> <span>{{ t('pointUse') }}</span>
</div> </div>
</div> </div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</el-card> </el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="memberAccountLogTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('memberInfo')" prop="keywords"> <el-form-item :label="t('memberInfo')" prop="keywords">
<el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" /> <el-input v-model="memberAccountLogTableData.searchParam.keywords" class="w-[240px]"
:placeholder="t('memberInfoPlaceholder')" />
</el-form-item> </el-form-item>
<el-form-item :label="t('fromType')" prop="from_type"> <el-form-item :label="t('fromType')" prop="from_type">
<el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable :placeholder="t('fromTypePlaceholder')" class="input-width"> <el-select v-model="memberAccountLogTableData.searchParam.from_type" clearable
:placeholder="t('fromTypePlaceholder')" class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item.name" :value="key" v-for="(item,key) in fromTypeList" /> <el-option :label="item.name" :value="key" v-for="(item, key) in fromTypeList" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker <el-date-picker v-model="memberAccountLogTableData.searchParam.create_time" type="datetimerange"
v-model="memberAccountLogTableData.searchParam.create_time" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
type="datetimerange" :end-placeholder="t('endDate')" />
value-format="YYYY-MM-DD HH:mm:ss"
:start-placeholder="t('startDate')"
:end-placeholder="t('endDate')"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button> <el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button>
@ -68,46 +68,50 @@
{{ row.member.member_no }} {{ row.member.member_no }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('memberInfo')" min-width="150" :show-overflow-tooltip="true"> <el-table-column :label="t('memberInfo')" min-width="150" :show-overflow-tooltip="true">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center cursor-pointer" @click="toMember(row.member_id)"> <div class="flex items-center cursor-pointer" @click="toMember(row.member_id)">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="" > <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="" > :src="img(row.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span> <span class="">{{ row.member.nickname || '' }}</span>
</div> </div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="mobile" :label="t('mobile')" min-width="100"> <el-table-column prop="mobile" :label="t('mobile')" min-width="100">
<template #default="{ row }"> <template #default="{ row }">
{{ row.member.mobile || '' }} {{ row.member.mobile || '' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_data" :label="t('accountData')" min-width="80" align="right"> <el-table-column prop="account_data" :label="t('accountData')" min-width="80" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.account_data >= 0">+{{ row.account_data }}</span> <span v-if="row.account_data >= 0">+{{ row.account_data }}</span>
<span v-else>{{ row.account_data }}</span> <span v-else>{{ row.account_data }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account_sum" :label="t('accountSum')" min-width="120" align="right"/> <el-table-column prop="account_sum" :label="t('accountSum')" min-width="120" align="right" />
<el-table-column prop="from_type_name" :label="t('fromType')" min-width="180" align="center"/> <el-table-column prop="from_type_name" :label="t('fromType')" min-width="180" align="center" />
<el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')" min-width="150" /> <el-table-column prop="create_time" :show-overflow-tooltip="true" :label="t('createTime')"
min-width="150" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="100"> <el-table-column :label="t('operation')" align="right" fixed="right" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button> <el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="memberAccountLogTableData.page" v-model:page-size="memberAccountLogTableData.limit" <el-pagination v-model:current-page="memberAccountLogTableData.page"
layout="total, sizes, prev, pager, next, jumper" :total="memberAccountLogTableData.total" v-model:page-size="memberAccountLogTableData.limit" layout="total, sizes, prev, pager, next, jumper"
@size-change="loadMemberAccountLogList()" @current-change="loadMemberAccountLogList" /> :total="memberAccountLogTableData.total" @size-change="loadMemberAccountLogList()"
@current-change="loadMemberAccountLogList" />
</div> </div>
</div> </div>
</el-card> </el-card>
@ -118,61 +122,60 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getChangeTypeList,getPointList,getPointSum } from '@/app/api/member' import { getChangeTypeList, getPointList, getPointSum } from '@/app/api/member'
import { ElMessageBox, FormInstance } from 'element-plus' import { FormInstance } from 'element-plus'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import pointInfo from '@/app/views/member/components/member-point-info.vue' import pointInfo from '@/app/views/member/components/member-point-info.vue'
import { useRouter,useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const member_id: number = parseInt(route.query.id || 0) const member_id: number = parseInt(route.query.id || 0)
const pageName = route.meta.title; const pageName = route.meta.title
let memberAccountLogTableData = reactive({ const memberAccountLogTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam: {
keywords:"", keywords: '',
from_type:"", from_type: '',
create_time:"", create_time: '',
mobile:"", mobile: '',
member_id:member_id member_id: member_id
} }
}) })
/** /**
* 获取积分总计 * 获取积分总计
*/ */
const pointStatistics = ref([]) const pointStatistics = ref([])
const checkPointInfo = () => { const checkPointInfo = () => {
getPointSum({ getPointSum({
member_id member_id
}).then(res => { }).then(res => {
pointStatistics.value = res.data; pointStatistics.value = res.data
}) })
} }
checkPointInfo() checkPointInfo()
let fromTypeList = ref([]) const fromTypeList = ref([])
const setFromTypeList = async () => { const setFromTypeList = async () => {
fromTypeList.value = await (await getChangeTypeList('point')).data fromTypeList.value = await (await getChangeTypeList('point')).data
} }
setFromTypeList(); setFromTypeList()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{ const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields(); formEl.resetFields()
loadMemberAccountLogList(); loadMemberAccountLogList()
} }
/** /**
* *
* 获取会员账单表列表 * 获取会员账单表列表
@ -184,7 +187,7 @@ const loadMemberAccountLogList = (page: number = 1) => {
getPointList({ getPointList({
page: memberAccountLogTableData.page, page: memberAccountLogTableData.page,
limit: memberAccountLogTableData.limit, limit: memberAccountLogTableData.limit,
...memberAccountLogTableData.searchParam ...memberAccountLogTableData.searchParam
}).then(res => { }).then(res => {
memberAccountLogTableData.loading = false memberAccountLogTableData.loading = false
memberAccountLogTableData.data = res.data.data memberAccountLogTableData.data = res.data.data
@ -201,7 +204,7 @@ const pointDialog: Record<string, any> | null = ref(null)
* 查看详情 * 查看详情
* @param data * @param data
*/ */
const infoEvent = (data: any) => { const infoEvent = (data: any) => {
pointDialog.value.setFormData(data) pointDialog.value.setFormData(data)
pointDialog.value.showDialog = true pointDialog.value.showDialog = true
} }
@ -211,11 +214,10 @@ const router = useRouter()
/** /**
* 会员详情 * 会员详情
*/ */
const toMember = (member_id:number) => { const toMember = (member_id: number) => {
router.push(`/member/detail?id=${member_id}`) router.push(`/member/detail?id=${member_id}`)
} }
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -70,7 +70,7 @@ import type { FormInstance } from 'element-plus'
import { getRechargeOrderInfo } from '@/app/api/order' import { getRechargeOrderInfo } from '@/app/api/order'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import useTabbarStore from '@/stores/modules/tabbar' import useTabbarStore from '@/stores/modules/tabbar'
import useAppStore from '@/stores/modules/app' // import useAppStore from '@/stores/modules/app'
const tabbarStore = useTabbarStore() const tabbarStore = useTabbarStore()
const route = useRoute() const route = useRoute()

View File

@ -2,28 +2,30 @@
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]"> <div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{ pageName }}</span>
</div> </div>
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never"> <el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
<el-row class="flex"> <el-row class="flex">
<el-col :span="12" class="min-w-[100px]"> <el-col :span="12" class="min-w-[100px]">
<el-statistic :value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'"> <el-statistic
<template #title> :value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'">
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div> <template #title>
</template> <div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div>
</el-statistic> </template>
</el-col> </el-statistic>
<el-col :span="12" class="min-w-[100px]"> </el-col>
<el-statistic :value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'"> <el-col :span="12" class="min-w-[100px]">
<template #title> <el-statistic
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div> :value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'">
</template> <template #title>
</el-statistic> <div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div>
</el-col> </template>
</el-statistic>
</el-col>
</el-row> </el-row>
</el-card> </el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never"> <el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef"> <el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
@ -34,35 +36,41 @@
<el-form-item :label="t('orderFromName')" prop="order_from"> <el-form-item :label="t('orderFromName')" prop="order_from">
<el-select v-model="orderTableData.searchParam.order_from" clearable class="input-width"> <el-select v-model="orderTableData.searchParam.order_from" clearable class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item" :value="key" v-for="(item, key) in channelList" /> <el-option :label="item" :value="key" v-for="(item, key) in channelList" :key="key"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status"> <el-form-item :label="t('orderStatus')" prop="order_status">
<el-select v-model="orderTableData.searchParam.order_status" clearable class="input-width"> <el-select v-model="orderTableData.searchParam.order_status" clearable class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item['name']" :value="item['status']" v-for="item in statusList" /> <el-option :label="item['name']" :value="item['status']" v-for="(item,index) in statusList" :key="index"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('createTime')" prop="create_time"> <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="orderTableData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" /> <el-date-picker v-model="orderTableData.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-form-item :label="t('rechargeMoney')"> <el-form-item :label="t('rechargeMoney')">
<div class="region-input"> <div class="region-input">
<el-form-item prop="start_money"> <el-form-item prop="start_money">
<input type="text" :placeholder="t('startMoney')" v-model="orderTableData.searchParam.start_money"> <input type="text" :placeholder="t('startMoney')"
v-model="orderTableData.searchParam.start_money">
</el-form-item> </el-form-item>
<span class="separator">-</span> <span class="separator">-</span>
<el-form-item prop="end_money"> <el-form-item prop="end_money">
<input type="text" :placeholder="t('endMoney')" v-model="orderTableData.searchParam.end_money"> <input type="text" :placeholder="t('endMoney')"
v-model="orderTableData.searchParam.end_money">
</el-form-item> </el-form-item>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('payTime')"> <el-form-item :label="t('payTime')">
<el-date-picker v-model="orderTableData.searchParam.pay_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" /> <el-date-picker v-model="orderTableData.searchParam.pay_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-form-item> <el-form-item>
@ -81,8 +89,10 @@
<el-table-column :show-overflow-tooltip="true" :label="t('member')" align="left" min-width="140"> <el-table-column :show-overflow-tooltip="true" :label="t('member')" align="left" min-width="140">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)"> <div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt=""> <img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg"
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt=""> :src="img(row.member.headimg)" alt="">
<img class="w-[50px] h-[50px] mr-[10px]" v-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col"> <div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span> <span class="">{{ row.member.nickname || '' }}</span>
<span class="">{{ row.member.mobile || '' }}</span> <span class="">{{ row.member.mobile || '' }}</span>
@ -91,7 +101,8 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('rechargeNo')" align="center" min-width="140" /> <el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('rechargeNo')" align="center"
min-width="140" />
<el-table-column prop="order_money" :label="t('rechargeMoney')" align="center" min-width="140" /> <el-table-column prop="order_money" :label="t('rechargeMoney')" align="center" min-width="140" />
@ -120,10 +131,13 @@
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button> <el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
<el-button v-if="[1, 10].includes(row.order_status_info.status) && row.is_enable_refund && row.refund_status == 0" type="primary" link @click="refundFn(row)">{{ t('refundBtn') }}</el-button> <el-button
v-if="[1, 10].includes(row.order_status_info.status) && row.is_enable_refund && row.refund_status == 0"
type="primary" link @click="refundFn(row)">{{ t('refundBtn') }}</el-button>
<template v-for="(item, index) in row.order_status_info.action"> <template v-for="(item, index) in row.order_status_info.action" :key="index">
<el-button type="primary" link @click="orderEvent(row, item.class)">{{ item.name }}</el-button> <el-button type="primary" link @click="orderEvent(row, item.class)">{{ item.name
}}</el-button>
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
@ -158,7 +172,7 @@ import { getChannelType } from '@/app/api/sys'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { AnyObject } from '@/types/global' import { AnyObject } from '@/types/global'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
@ -203,7 +217,7 @@ const statusList = ref([])
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const setCategoryList = async () => { const setCategoryList = async () => {
statusList.value = await (await getRechargeOrderStatusList({})).data statusList.value = await (await getRechargeOrderStatusList()).data
} }
setCategoryList() setCategoryList()

View File

@ -45,7 +45,7 @@
<el-form-item :label="t('refundStatus')" prop="status"> <el-form-item :label="t('refundStatus')" prop="status">
<el-select v-model="refundTableData.searchParam.status" clearable class="input-width"> <el-select v-model="refundTableData.searchParam.status" clearable class="input-width">
<el-option :label="t('selectPlaceholder')" value="" /> <el-option :label="t('selectPlaceholder')" value="" />
<el-option :label="item.name" :value="key" v-for="(item, key) in refundList" /> <el-option :label="item.name" :value="key" v-for="(item, key) in refundList" :key="key" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('refundTime')" prop="create_time"> <el-form-item :label="t('refundTime')" prop="create_time">
@ -152,85 +152,85 @@ const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
const refundTableData = reactive({ const refundTableData = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam: {
refund_no: '', refund_no: '',
// member_id, // member_id,
create_time: [], create_time: [],
status: '', status: '',
keywords: '', keywords: '',
order_no: '' order_no: ''
} }
}) })
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadRefundList() loadRefundList()
} }
/** /**
* 获取退款列表 * 获取退款列表
*/ */
const loadRefundList = (page: number = 1) => { const loadRefundList = (page: number = 1) => {
refundTableData.loading = true refundTableData.loading = true
refundTableData.page = page refundTableData.page = page
getRechargeRefund({ getRechargeRefund({
page: refundTableData.page, page: refundTableData.page,
limit: refundTableData.limit, limit: refundTableData.limit,
...refundTableData.searchParam ...refundTableData.searchParam
}).then(res => { }).then(res => {
refundTableData.loading = false refundTableData.loading = false
refundTableData.data = res.data.data refundTableData.data = res.data.data
refundTableData.total = res.data.total refundTableData.total = res.data.total
}).catch(() => { }).catch(() => {
refundTableData.loading = false refundTableData.loading = false
}) })
} }
loadRefundList() loadRefundList()
const refundList = ref([]) const refundList = ref([])
const checkRefundList = () => { const checkRefundList = () => {
getRechargeRefundStatus().then(res => { getRechargeRefundStatus().then(res => {
refundList.value = res.data refundList.value = res.data
}) })
} }
checkRefundList() checkRefundList()
const refundStat = reactive({ const refundStat = reactive({
refund_all_money: 0.00, refund_all_money: 0.00,
refund_have_money: 0.00, refund_have_money: 0.00,
refund_Success_money: 0.00, refund_Success_money: 0.00,
refund_fail_moey: 0.00 refund_fail_moey: 0.00
}) })
const checkRefundStat = () => { const checkRefundStat = () => {
getRechargeRefundStat().then(res => { getRechargeRefundStat().then(res => {
refundStat.refund_all_money = res.data.all.money refundStat.refund_all_money = res.data.all.money
refundStat.refund_have_money = res.data.have.money refundStat.refund_have_money = res.data.have.money
refundStat.refund_Success_money = res.data['3'].money refundStat.refund_Success_money = res.data['3'].money
refundStat.refund_fail_moey = res.data['-1'].money refundStat.refund_fail_moey = res.data['-1'].money
}) })
} }
checkRefundStat() checkRefundStat()
const refundInfoShowDialog = ref(false) const refundInfoShowDialog = ref(false)
const refundInfo = ref({}) const refundInfo = ref({})
const infoEvent = (info) => { const infoEvent = (info:any) => {
refundInfo.value = info refundInfo.value = info
refundInfoShowDialog.value = true refundInfoShowDialog.value = true
} }
/** /**
* 会员详情 * 会员详情
*/ */
const toMember = (memberId: number) => { const toMember = (memberId: number) => {
router.push(`/member/detail?id=${memberId}`) router.push(`/member/detail?id=${memberId}`)
} }
</script> </script>

View File

@ -4,7 +4,7 @@
<span class="text-[20px]">{{pageName}}</span> <span class="text-[20px]">{{pageName}}</span>
</div> </div>
<el-form :model="formData" label-width="150px" ref="ruleFormRef" :rules="formRules" class="page-form" v-loading="loading"> <el-form :model="formData" label-width="150px" ref="ruleFormRef" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('admin') }}</h3> <h3 class="panel-title !text-sm">{{ t('admin') }}</h3>
@ -45,29 +45,29 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getConfigLogin, setConfigLogin } from '@/app/api/sys' import { getConfigLogin, setConfigLogin } from '@/app/api/sys'
import { FormRules, FormInstance } from 'element-plus' import { FormInstance } from 'element-plus'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const loading = ref(true), const loading = ref(true)
ruleFormRef = ref<FormInstance>(), const ruleFormRef = ref<FormInstance>()
formData = reactive<Record<string, number | string>>({ const formData = reactive<Record<string, number | string>>({
is_captcha: 0, is_captcha: 0,
is_site_captcha: 0, is_site_captcha: 0,
bg: '', bg: '',
site_bg: '' site_bg: ''
}); })
const getFormData = async (id: number = 0) => { const getFormData = async (id: number = 0) => {
const data = await (await getConfigLogin()).data const data = await (await getConfigLogin()).data
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (['is_captcha','is_site_captcha'].includes(key)) formData[key] = Boolean(Number(data[key])); if (['is_captcha', 'is_site_captcha'].includes(key)) formData[key] = Boolean(Number(data[key]))
else formData[key] = data[key]; else formData[key] = data[key]
}) })
loading.value = false; loading.value = false
} }
getFormData() getFormData()
@ -75,9 +75,9 @@ const onSave = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
await formEl.validate((valid) => { await formEl.validate((valid) => {
if (valid) { if (valid) {
let save = JSON.parse(JSON.stringify(formData)); const save = JSON.parse(JSON.stringify(formData))
Object.keys(save).forEach((key)=>{ Object.keys(save).forEach((key) => {
if (['is_captcha','is_site_captcha'].includes(key)) save[key] = Number(save[key]); if (['is_captcha', 'is_site_captcha'].includes(key)) save[key] = Number(save[key])
}) })
setConfigLogin(save).then(() => { setConfigLogin(save).then(() => {

View File

@ -38,14 +38,14 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getAgreementList } from '@/app/api/sys' import { getAgreementList } from '@/app/api/sys'
import { useRouter,useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title; const pageName = route.meta.title
let agreementTableData = reactive({ const agreementTableData = reactive({
loading: true, loading: true,
data: [], data: []
}) })
/** /**
@ -53,10 +53,10 @@ let agreementTableData = reactive({
*/ */
const loadAgreementList = () => { const loadAgreementList = () => {
agreementTableData.loading = true agreementTableData.loading = true
agreementTableData.data = []; agreementTableData.data = []
getAgreementList().then(res => { getAgreementList().then(res => {
Object.keys(res.data).forEach((key) => { Object.keys(res.data).forEach((key) => {
return agreementTableData.data.push(res.data[key]); return agreementTableData.data.push(res.data[key])
}) })
agreementTableData.loading = false agreementTableData.loading = false
}).catch(() => { }).catch(() => {

View File

@ -37,9 +37,9 @@ import type { FormInstance } from 'element-plus'
import { getAgreementInfo, editAgreement } from '@/app/api/sys' import { getAgreementInfo, editAgreement } from '@/app/api/sys'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import useTabbarStore from '@/stores/modules/tabbar' import useTabbarStore from '@/stores/modules/tabbar'
import useAppStore from '@/stores/modules/app' // import useAppStore from '@/stores/modules/app'
const appStore = useAppStore() // const appStore = useAppStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const agreement_key: string = route.query.key || '' const agreement_key: string = route.query.key || ''
@ -65,11 +65,10 @@ const setFormData = async (agreement_key: string = '') => {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key] if (data[key] != undefined) formData[key] = data[key]
}) })
loading.value = false; loading.value = false
} }
if (agreement_key) setFormData(agreement_key) if (agreement_key) setFormData(agreement_key)
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
// //
@ -87,10 +86,10 @@ const onSave = async (formEl: FormInstance | undefined) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
const data = formData const data = formData
data.key = formData.agreement_key; data.key = formData.agreement_key
editAgreement(data).then(res => { editAgreement(data).then(res => {
loading.value = false loading.value = false
back(); back()
}).catch(() => { }).catch(() => {
loading.value = false loading.value = false
}) })

View File

@ -57,69 +57,66 @@ import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const loading = ref(true), const loading = ref(true)
ruleFormRef = ref<FormInstance>(), const ruleFormRef = ref<FormInstance>()
formData = reactive<Record<string, string | boolean | Array<string> >>({ const formData = reactive<Record<string, string | boolean | Array<string> >>({
is_auto_transfer: "0", is_auto_transfer: '0',
is_auto_verify: "0", is_auto_verify: '0',
is_open: "0", is_open: '0',
min: "0.01", min: '0.01',
rate: "0", rate: '0',
transfer_type: [] transfer_type: []
}); })
const Transfertype = ref<Array<Object>>([]) const Transfertype = ref<Array<Object>>([])
// //
const getTransfertypeFn = async()=>{ const getTransfertypeFn = async () => {
Transfertype.value = await (await getTransfertype()).data Transfertype.value = await (await getTransfertype()).data
} }
getTransfertypeFn() getTransfertypeFn()
// //
const setFormData = async (id: number = 0) => { const setFormData = async (id: number = 0) => {
const data = await (await getCashOutConfig()).data const data = await (await getCashOutConfig()).data
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]; if (data[key] != undefined) formData[key] = data[key]
}) })
formData.is_open = Boolean(Number(formData.is_open)); formData.is_open = Boolean(Number(formData.is_open))
loading.value = false; loading.value = false
} }
setFormData() setFormData()
const minRules = (rule: any, value: any, callback: any) => { const minRules = (rule: any, value: any, callback: any) => {
if (Number(value) < 0.01) { if (Number(value) < 0.01) {
callback(new Error(t('cashWithdrawalAmountHint'))) callback(new Error(t('cashWithdrawalAmountHint')))
} else { } else {
callback() callback()
} }
} }
const rateRules = (rule: any, value: any, callback: any) => { const rateRules = (rule: any, value: any, callback: any) => {
if (Number(value) > 100 || Number(value) < 0) { if (Number(value) > 100 || Number(value) < 0) {
callback(new Error(t('commissionRatioHint'))) callback(new Error(t('commissionRatioHint')))
} else { } else {
callback() callback()
} }
} }
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
min: [ min: [
{ validator: minRules, trigger: 'blur' } { validator: minRules, trigger: 'blur' }
], ],
rate: [ rate: [
{ validator: rateRules, trigger: 'blur' } { validator: rateRules, trigger: 'blur' }
] ]
}) })
const onSave = async (formEl: FormInstance | undefined) => { const onSave = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
await formEl.validate((valid) => { await formEl.validate((valid) => {
if (valid) { if (valid) {
let save = {...formData}; const save = { ...formData }
save.is_open = Number(save.is_open).toString(); save.is_open = Number(save.is_open).toString()
setCashOutConfig(save).then(() => { setCashOutConfig(save).then(() => {
loading.value = false loading.value = false

View File

@ -1,7 +1,7 @@
<template> <template>
<el-dialog v-model="showDialog" :title="t('cronInfo')" width="550px" :destroy-on-close="true"> <el-dialog v-model="showDialog" :title="t('cronInfo')" width="550px" :destroy-on-close="true">
<el-form :model="formData" label-width="110px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading"> <el-form :model="formData" label-width="110px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('title')" > <el-form-item :label="t('title')" >
<div class="input-width"> {{ formData.title }} </div> <div class="input-width"> {{ formData.title }} </div>
</el-form-item> </el-form-item>
@ -18,7 +18,7 @@
<el-form-item :label="t('count')" > <el-form-item :label="t('count')" >
<div class="input-width"> {{ formData.count }} </div> <div class="input-width"> {{ formData.count }} </div>
</el-form-item> </el-form-item>
<el-form-item :label="t('task')" > <el-form-item :label="t('task')" >
<div class="input-width"> {{ formData.task }} </div> <div class="input-width"> {{ formData.task }} </div>
</el-form-item> </el-form-item>
@ -66,19 +66,19 @@ const loading = ref(true)
*/ */
const initialFormData = { const initialFormData = {
count: 0, count: 0,
create_time:'', create_time: '',
crond_length:'', crond_length: '',
crond_type:'', crond_type: '',
crond_type_name:'', crond_type_name: '',
data:'', data: '',
delete_time:'', delete_time: '',
last_time:'', last_time: '',
next_time:'', next_time: '',
status_desc:'', status_desc: '',
title:'', title: '',
type:'', type: '',
type_name:'', type_name: '',
update_time:'' update_time: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -91,7 +91,7 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true loading.value = true
@ -101,7 +101,6 @@ const setFormData = async (row: any = null) => {
if (row[key] != undefined) formData[key] = row[key] if (row[key] != undefined) formData[key] = row[key]
}) })
} }
loading.value = false loading.value = false
} }

View File

@ -42,7 +42,7 @@
import { ref, reactive, computed } from 'vue' import { ref, reactive, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { editNoticeStatus } from '@/app/api/notice' // import { editNoticeStatus } from '@/app/api/notice'
const showDialog = ref(false) const showDialog = ref(false)
const loading = ref(true) const loading = ref(true)
@ -57,7 +57,7 @@ const initialFormData = {
message_type: '', message_type: '',
name: '', name: '',
nickname: '', nickname: '',
receiver: '', receiver: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -70,10 +70,10 @@ const formRules = computed(() => {
} }
}) })
const emit = defineEmits(['complete']) // const emit = defineEmits(['complete'])
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {

View File

@ -55,7 +55,7 @@ const initialFormData = {
title: '', title: '',
type: '', type: '',
sms_id: '', sms_id: '',
content: '' content: ''
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -66,7 +66,7 @@ const formRules = computed(() => {
return { return {
sms_id: [ sms_id: [
{ required: true, message: t('smsIdPlaceholder'), trigger: 'blur' } { required: true, message: t('smsIdPlaceholder'), trigger: 'blur' }
], ]
} }
}) })
@ -84,7 +84,7 @@ const confirm = async (formEl: FormInstance | undefined) => {
loading.value = true loading.value = true
const data = formData const data = formData
data.status = data.is_sms; data.status = data.is_sms
editNotice(data).then(res => { editNotice(data).then(res => {
loading.value = false loading.value = false
@ -99,13 +99,13 @@ const confirm = async (formEl: FormInstance | undefined) => {
} }
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
loading.value = true; loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (row) { if (row) {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (row[key] != undefined) formData[key] = row[key]; if (row[key] != undefined) formData[key] = row[key]
if (row.sms && row.sms[key] != undefined) formData[key] = row.sms[key] if (row.sms && row.sms[key] != undefined) formData[key] = row.sms[key]
}) })
} }

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