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'
export {}
declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElNotification: typeof import('element-plus/es')['ElNotification']
}

View File

@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"build": "vite build && node publish.cjs",
"preview": "vite preview"
},
"dependencies": {
@ -55,4 +55,4 @@
"vite": "4.1.0",
"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
*/
export function getUserInfo(type: string) {
export function getUserInfo() {
return request.get(`auth/get`)
}

View File

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

View File

@ -675,3 +675,20 @@ export function getAddonList() {
export function getWapIndexList(params: Record<string, any>) {
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>) {
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 {
background-color: var(--el-table-header-bg-color);
}
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style>

View File

@ -19,7 +19,7 @@
<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="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>
</el-scrollbar>
</div>
@ -233,7 +233,7 @@ const open = (addonKey: string = '') => {
}
getUpgradeContent(addonKey).then(({ data }) => {
upgradeContent.value = data
if (data.version == data.last_version) {
if (!data.version_list.length) {
ElMessage({ message: '已经是最新版本了', type: 'error' })
return
}
@ -316,4 +316,7 @@ defineExpose({
.table-head-bg {
background-color: var(--el-table-header-bg-color);
}
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style>

View File

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

View File

@ -21,5 +21,10 @@
"viewPathPlaceholder": "请输入组件路径",
"authIdPlaceholder": "请输入权限标识",
"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": "重置",
"search": "搜索",
"foldText":"展开/折叠",
"mainApp": "套餐主应用",
"mainAppPlaceholder": "请选择套餐主应用",
"containAddon": "套餐内含插件"
"mainApp": "套餐内含应用",
"mainAppPlaceholder": "请选择套餐内包含的应用",
"containAddon": "套餐内含插件",
"appListEmpty": "没有可选择的应用",
"addonListEmpty": "没有可选择的插件"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
<span v-html="`${menuLevel}${prop.menu.menu_name}`"></span>
</el-option>
<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>
@ -12,7 +12,7 @@
<script lang="ts" setup>
import { computed } from 'vue'
const prop = defineProps({
const prop:any = defineProps({
menu: Object,
level: {
type: Number,
@ -31,4 +31,4 @@ const menuLevel = computed(() => {
<style lang="scss" scoped>
</style>
</style>

View File

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

View File

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

View File

@ -1,6 +1,13 @@
<template>
<div class="main-container">
<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">
<template #empty>
<span>{{ !menusTableData.loading ? t('emptyData') : '' }}</span>
@ -22,19 +29,19 @@
<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>
<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> -->
<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>
<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>
</div>
</template>
@ -45,11 +52,10 @@ import { getMenus, deleteMenu } from '@/app/api/sys'
import { t } from '@/lang'
import { ElMessageBox } from 'element-plus'
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const menusTableData = reactive({
loading: true,
data: []
@ -91,7 +97,7 @@ const editEvent = (data: any) => {
/**
* 删除菜单
*/
const deleteEvent = (menu_key: string) => {
const deleteEvent = (key: string) => {
ElMessageBox.confirm(t('menuDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
@ -99,7 +105,7 @@ const deleteEvent = (menu_key: string) => {
type: 'warning'
}
).then(() => {
deleteMenu(menu_key).then(res => {
deleteMenu('admin', key).then(() => {
getMenuList()
}).catch(() => {
})

View File

@ -52,27 +52,23 @@ import { getRoleList, deleteRole } from '@/app/api/sys'
import { ElMessageBox, FormInstance } from 'element-plus'
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({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
seach:''
searchParam: {
seach: ''
}
})
const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields();
loadRoleList();
formEl.resetFields()
loadRoleList()
}
/**
* 获取角色列表

View File

@ -1,39 +1,91 @@
<template>
<div class="main-container">
<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">
<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-tabs v-model="active">
<el-tab-pane :label="t('system')" name="system">
<el-table :data="menusTableData.system" 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-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" />
</el-card>
@ -49,11 +101,12 @@ import EditMenu from '@/app/views/auth/components/edit-menu.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const active = ref('system')
const menusTableData = reactive({
const menusTableData = reactive<Record<string, any>>({
loading: true,
data: []
system: [],
application: []
})
/**
@ -61,9 +114,15 @@ const menusTableData = reactive({
*/
const getMenuList = () => {
menusTableData.loading = true
getMenus('site').then(res => {
getMenus('site').then(({ data }) => {
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(() => {
})
@ -92,7 +151,7 @@ const editEvent = (data: any) => {
/**
* 删除菜单
*/
const deleteEvent = (menu_key: string) => {
const deleteEvent = (key: string) => {
ElMessageBox.confirm(t('menuDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
@ -100,7 +159,7 @@ const deleteEvent = (menu_key: string) => {
type: 'warning'
}
).then(() => {
deleteMenu(menu_key).then(res => {
deleteMenu('site', key).then(res => {
getMenuList()
}).catch(() => {
})

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -137,10 +137,10 @@
</el-col>
<el-col :span="4">
<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>
<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>
</template>
</el-image>
@ -155,26 +155,26 @@
</template>
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import { t } from "@/lang";
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { getWeappConfig } from '@/app/api/weapp'
const router = useRouter();
let activeName = ref("/channel/weapp");
let active = ref(2);
let qr_code = ref('')
const router = useRouter()
const activeName = ref('/channel/weapp')
const active = ref(2)
const qrCode = ref('')
onMounted(async () => {
let res = await getWeappConfig()
qr_code.value = res.data.qr_code
const res = await getWeappConfig()
qrCode.value = res.data.qr_code
})
const linkEvent = (url: string) => {
window.open(url, "_blank");
};
window.open(url, '_blank')
}
const handleClick = (val: any) => {
router.push({ path: activeName.value });
};
router.push({ path: activeName.value })
}
</script>
<style lang="scss" scoped>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -99,16 +99,16 @@ const button = ref<Record<string, any>[]>([])
const buttonIndex = ref<number>(0)
const subButtonIndex = ref<number>(-1)
const formRef = ref<Record<string, any>[] | null>(null)
let activeName = ref("/channel/wechat/menu");
const activeName = ref('/channel/wechat/menu')
const handleClick = (val: any) => {
router.push({ path: activeName.value });
};
router.push({ path: activeName.value })
}
/**
* 获取公众号菜单配置
*/
getWechatMenu().then((res) => {
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>
<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 router = useRouter()
const pageName = route.meta.title;
const pageName = route.meta.title
const cronTableData = reactive({
loading: true,
data: []
})
let activeName = ref("/channel/wechat/message");
const activeName = ref('/channel/wechat/message')
const handleClick = (val: any) => {
router.push({ path: activeName.value });
};
router.push({ path: activeName.value })
}
/**
* 获取消息模板列表
*/

View File

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

View File

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

View File

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

View File

@ -60,105 +60,103 @@
</template>
<script lang="ts" setup>
import {t} from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import {ref, reactive,onMounted, nextTick} from 'vue'
import {img} from '@/utils/common'
import { getWapIndexList } from '@/app/api/sys'
import Sortable from 'sortablejs'
import {range} from 'lodash-es'
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { ref, reactive, onMounted, nextTick } from 'vue'
import { img } from '@/utils/common'
import { getWapIndexList } from '@/app/api/sys'
import Sortable from 'sortablejs'
import { range } from 'lodash-es'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; //
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
//
diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''};
// if (diyStore.value[index].list.length === 0) {
// res.code = false;
// res.message = t('selectAddonTips');
// }
return res;
};
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// if (diyStore.value[index].list.length === 0) {
// res.code = false;
// res.message = t('selectAddonTips');
// }
return res
}
const showDialog = ref(false)
const showDialog = ref(false)
const addonBoxRef = ref()
const addonBoxRef = ref()
onMounted(() => {
nextTick(() => {
const sortable = Sortable.create(addonBoxRef.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();
})
);
}
})
});
})
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
onMounted(() => {
nextTick(() => {
const sortable = Sortable.create(addonBoxRef.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()
})
)
}
})
})
})
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) => {
let item:any = {
id: diyStore.generateRandom(),
key: '',
title: '',
url: '',
icon: '',
desc: ''
};
for (let k in val) {
item[k] = val[k];
}
const addAddon = () => {
showDialog.value = true
}
diyStore.editComponent.list.push(item)
showDialog.value = false
}
const addAddon = () => {
showDialog.value = true;
}
defineExpose({})
defineExpose({})
</script>
<style lang="scss">
</style>
<style lang="scss" scoped>
</style>
</style>

View File

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

View File

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

View File

@ -33,41 +33,41 @@
</template>
<script lang="ts" setup>
import {t} from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import {img} from '@/utils/common'
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; //
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
//
diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''};
if (diyStore.value[index].imageUrl === '') {
res.code = false;
res.message = t('imageUrlTip');
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;
};
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if (diyStore.value[index].imageUrl === '') {
res.code = false
res.message = t('imageUrlTip')
return res
}
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>
<style lang="scss" scoped>
</style>
</style>

View File

@ -44,112 +44,112 @@
</template>
<script lang="ts" setup>
import {ref, watch, onMounted, nextTick} from 'vue'
import {t} from '@/lang'
import Sortable from 'sortablejs'
import {img} from '@/utils/common'
import {range} from 'lodash-es'
import useDiyStore from '@/stores/modules/diy'
import { ref, watch, onMounted, nextTick } from 'vue'
import { t } from '@/lang'
import Sortable from 'sortablejs'
import { img } from '@/utils/common'
import { range } from 'lodash-es'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; //
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
//
diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''};
if(diyStore.value[index].imageHeight == 0){
res.code = false;
res.message = t('imageHeightPlaceholder');
return res;
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if (diyStore.value[index].imageHeight == 0) {
res.code = false
res.message = t('imageHeightPlaceholder')
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;
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;
})
return res
}
diyStore.editComponent.list.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom()
})
watch(
() => 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(
() => diyStore.editComponent.list,
(newValue, oldValue) => {
//
handleHeight();
},
{deep: true}
)
const blurImageHeight = () => {
diyStore.editComponent.imageHeight = parseInt(diyStore.editComponent.imageHeight)
}
const addImageAd = () => {
diyStore.editComponent.list.push({
id: diyStore.generateRandom(),
imageUrl: '',
imgWidth: 0,
imgHeight: 0,
link: {name: ''}
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)
}
})
}
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>
<style lang="scss" scoped>
@ -167,4 +167,4 @@
}
}
}
</style>
</style>

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@
<span>{{ selectTemplate.name }}</span>
</el-form-item>
<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"/>
</li>
</ul>
@ -20,7 +20,7 @@
<el-form label-width="80px" class="px-[10px]">
<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">
<img class="!w-full !h-full" :src="img(diyStore.editComponent.list[i].imageUrl)"/>
</div>
@ -31,7 +31,7 @@
</li>
</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')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg"/>
</el-form-item>
@ -72,423 +72,422 @@
</template>
<script lang="ts" setup>
import {ref, watch, onMounted, nextTick, computed} from 'vue'
import {t} from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import {img} from '@/utils/common'
import { ref, computed } from 'vue'
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; //
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
//
diyStore.editComponent.verify = (index: number) => {
var res = {code: true, message: ''};
diyStore.value[index].list.forEach((item: any) => {
if (item.imageUrl === '') {
res.code = false;
res.message = t('imageUrlTip');
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"
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
diyStore.value[index].list.forEach((item: any) => {
if (item.imageUrl === '') {
res.code = false
res.message = t('imageUrlTip')
return res
}
]);
})
return res
}
let rubikCubeList = ref([]);
const selectTemplate = computed(() => {
var data;
templateList.value.forEach((item) => {
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);
}
const templateList = ref([
{
name: '1行2个',
src: 'iconyihangliangge',
className: 'row1-of2',
dimensionScale: [
{
desc: '宽度50%',
size: '200px * 200px',
name: '图一'
},
{
desc: '宽度50%',
size: '200px * 200px',
name: '图二'
}
})
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) => {
for (var i = 0; i < templateList.value.length; i++) {
if (i == v) {
diyStore.editComponent.mode = templateList.value[i].className;
var count = templateList.value[i].dimensionScale.length;
const rubikCubeList = ref([])
const selectTemplate = computed(() => {
let data
templateList.value.forEach((item) => {
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
})
//
if (count > diyStore.editComponent.list.length) {
for (var j = 0; j < count; j++) {
if ((j + 1) > diyStore.editComponent.list.length) diyStore.editComponent.list.push({
imageUrl: "",
const changeTemplateList = (v: number) => {
for (let i = 0; i < templateList.value.length; i++) {
if (i == v) {
diyStore.editComponent.mode = templateList.value[i].className
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,
imgHeight: 0,
link: {name: ""}
});
link: { name: '' }
})
}
} else {
//
if (count != diyStore.editComponent.list.length) {
for (var j = 0; j < diyStore.editComponent.list.length; j++) {
if ((j + 1) > count) {
diyStore.editComponent.list.splice(j, 1);
j = 0;
}
}
} else {
//
if (count != diyStore.editComponent.list.length) {
for (let j = 0; j < diyStore.editComponent.list.length; j++) {
if ((j + 1) > count) {
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
* 比例原图高/原图宽示例322/690=0.46
* 高度宽度*比例示例187.5*0.46=86.25
*/
const calcSingleRow = (type) => {
let maxHeight = 0;
var paramsRatio = 2;
var paramsWidth = 'calc(100% / 2)';
if(type == 'row1-of3'){
paramsRatio = 3;
paramsWidth = 'calc(100% / 3)';
}
if(type == 'row1-of4'){
paramsRatio = 4
paramsWidth = 'calc(100% / 4)';
}
const calcSingleRow = (type:any) => {
let maxHeight = 0
let paramsRatio = 2
let paramsWidth = 'calc(100% / 2)'
if (type == 'row1-of3') {
paramsRatio = 3
paramsWidth = 'calc(100% / 3)'
}
if (type == 'row1-of4') {
paramsRatio = 4
paramsWidth = 'calc(100% / 4)'
}
rubikCubeList.value.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth
let width = 330;
item.imgWidth = width / paramsRatio;
item.imgHeight = item.imgWidth * ratio;
const width = 330
item.imgWidth = width / paramsRatio
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) => {
item.widthStyle = paramsWidth;
item.imgHeight = maxHeight;
});
};
rubikCubeList.value.forEach((item:any, index) => {
item.widthStyle = paramsWidth
item.imgHeight = maxHeight
})
};
/**
/**
* 魔方四方型各占50%
*/
const calcFourSquare = () => {
let maxHeightFirst = 0;
let maxHeightTwo = 0;
rubikCubeList.value.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
item.imgWidth = 330;
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
const calcFourSquare = () => {
let maxHeightFirst = 0
let maxHeightTwo = 0
rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
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右
*/
const calcRowOneLeftOfTwoRight = () => {
let rightHeight = 0; //
let divide = 'left'; // leftright
if (rubikCubeList.value[1].imgWidth === rubikCubeList.value[2].imgWidth) divide = 'right';
rubikCubeList.value.forEach((item, index) => {
if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; //
item.imgWidth = 330;
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
rightHeight = item.imgHeight / 2;
item.imgWidth += 'px';
} else {
item.imgWidth = rubikCubeList.value[0].imgWidth;
item.imgHeight = rightHeight;
}
});
}
const calcRowOneLeftOfTwoRight = () => {
let rightHeight = 0 //
let divide = 'left' // leftright
if (rubikCubeList.value[1].imgWidth === rubikCubeList.value[2].imgWidth) divide = 'right'
rubikCubeList.value.forEach((item:any, index) => {
if (index == 0) {
const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio
rightHeight = item.imgHeight / 2
item.imgWidth += 'px'
} else {
item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rightHeight
}
})
}
/**
/**
* 魔方1上2下
*/
const calcRowOneTopOfTwoBottom = () => {
var maxHeight = 0;
rubikCubeList.value.forEach((item, index) => {
const calcRowOneTopOfTwoBottom = () => {
let maxHeight = 0
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; //
if (index == 0) {
item.imgWidth = 330;
} else if (index > 0) {
item.imgWidth = 330;
item.imgWidth = item.imgWidth / 2;
}
item.imgHeight = item.imgWidth * ratio
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右
*/
const calcRowOneLeftOfOneTopOfTwoBottom = () => {
rubikCubeList.value.forEach((item, index) => {
//
if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; //
item.imgWidth = 330;
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
} else if (index == 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth;
item.imgHeight = rubikCubeList.value[0].imgHeight / 2;
} else if (index > 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth / 2;
item.imgHeight = rubikCubeList.value[1].imgHeight;
}
});
const calcRowOneLeftOfOneTopOfTwoBottom = () => {
rubikCubeList.value.forEach((item:any, index) => {
//
if (index == 0) {
const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio
} else if (index == 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rubikCubeList.value[0].imgHeight / 2
} else if (index > 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth / 2
item.imgHeight = rubikCubeList.value[1].imgHeight
}
})
rubikCubeList.value.forEach((item, index) => {
item.imgWidth += 'px';
});
}
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth += 'px'
})
}
</script>

View File

@ -5,9 +5,10 @@
<h3 class="mb-[10px]">{{ t('styleSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<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>
<ArrowRight/>
<ArrowRight />
</el-icon>
</el-form-item>
</el-form>
@ -16,15 +17,16 @@
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<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 :label="t('link')">
<diy-link v-model="diyStore.editComponent.link"/>
<diy-link v-model="diyStore.editComponent.link" />
</el-form-item>
<el-form-item :label="t('textAlign')" v-show="diyStore.editComponent.style == 'style-1'">
<el-radio-group v-model="diyStore.editComponent.textAlign">
<el-radio :label="'left'">{{t('textAlignLeft')}}</el-radio>
<el-radio :label="'center'">{{t('textAlignCenter')}}</el-radio>
<el-radio :label="'left'">{{ t('textAlignLeft') }}</el-radio>
<el-radio :label="'center'">{{ t('textAlignCenter') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
@ -34,13 +36,15 @@
<h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<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 :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 :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>
</div>
@ -49,16 +53,17 @@
<h3 class="mb-[10px]">{{ t('moreContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<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 :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 :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 :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>
</div>
@ -66,19 +71,21 @@
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="40%">
<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'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png"/>
<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'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
</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'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png"/>
<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'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png" />
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel')}}</el-button>
<el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button>
</span>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
@ -91,16 +98,17 @@
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<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 :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<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>
</div>
@ -109,51 +117,49 @@
<slot name="style"></slot>
</div>
</template>
<script lang="ts" setup>
import {t} from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import {ref, reactive} from 'vue'
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { ref } from 'vue'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = []; //
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
const showDialog = ref(false)
const showDialog = ref(false)
const showStyle = () => {
showDialog.value = true
const showStyle = () => {
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)
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({})
defineExpose({})
</script>
<style lang="scss">
.horz-blank-slider {
.el-slider__input {
width: 100px;
}
.horz-blank-slider {
.el-slider__input {
width: 100px;
}
</style>
<style lang="scss" scoped></style>
}</style>
<style lang="scss" scoped></style>

File diff suppressed because it is too large Load Diff

View File

@ -1,460 +1,457 @@
<template>
<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]"
: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">
{{item.use_template.title}}</p>
<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]"
: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">
{{ item.use_template.title }}</p>
<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"
: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 class="font-bold text-xl mb-[40px]">{{t('developTitle')}}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable/>
</div>
<div 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"
: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 class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
<div class="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
</div>
<div class="flex">
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
</div>
</div>
</div>
</div>
</div>
<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)"/>
</div>
<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)" />
</div>
<p class="text-[12px] text-[#999] mt-[10px] mx-auto truncate text-center w-[250px]">
{{item.use_template.desc}}</p>
<p class="text-[12px] text-[#999] mt-[10px] mx-auto truncate text-center w-[250px]">
{{ item.use_template.desc }}</p>
<div class="item-hide absolute inset-x-0 inset-y-0 bg-black bg-opacity-50 text-center"
: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">
<el-button @click="show(key,item)">{{ t('changePage') }}</el-button>
<el-button @click="toDecorate(item.use_template)"
v-show="item.use_template.mode != 'other' || item.use_template.action == 'decorate'">{{
t('decorate') }}
</el-button>
<el-button @click="toPreview(item.use_template)">{{ t('preview') }}</el-button>
</div>
</div>
<div class="item-hide absolute inset-x-0 inset-y-0 bg-black bg-opacity-50 text-center"
: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">
<el-button @click="show(key, item)">{{ t('changePage') }}</el-button>
<el-button @click="toDecorate(item.use_template)"
v-show="item.use_template.mode != 'other' || item.use_template.action == 'decorate'">{{
t('decorate') }}
</el-button>
<el-button @click="toPreview(item.use_template)">{{ t('preview') }}</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
<el-dialog v-model="showDialog" :title="t('changeTemplate')" width="400px" :close-on-press-escape="false"
:destroy-on-close="true" :close-on-click-modal="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">
<el-form :model="form" label-width="0px" v-if="formData.type">
<el-form-item label="">
<div>{{t('hopeBeforeTip')}}<span class="text-primary px-[5px]">{{ page[formData.type].title }}</span>{{t('hopeAfterTip')}}
</div>
</el-form-item>
<el-form :model="form" label-width="0px" v-if="formData.type">
<el-form-item label="">
<div>{{ t('hopeBeforeTip') }}<span class="text-primary px-[5px]">{{ page[formData.type].title
}}</span>{{ t('hopeAfterTip') }}
</div>
</el-form-item>
<el-form-item label="">
<el-select v-model="hope" class="w-full">
<el-option :label="t('changeTemplateTip') + ' ' + page[formData.type].title + ' ' + t('template')"
value="template"/>
<el-option :label="t('changeMyPageTip') + ' ' + page[formData.type].title" value="diy"/>
<el-option :label="t('changeOtherPageTip') + ' ' + page[formData.type].title" value="other"/>
</el-select>
</el-form-item>
<el-form-item label="">
<el-select v-model="hope" class="w-full">
<el-option :label="t('changeTemplateTip') + ' ' + page[formData.type].title + ' ' + t('template')"
value="template" />
<el-option :label="t('changeMyPageTip') + ' ' + page[formData.type].title" value="diy" />
<el-option :label="t('changeOtherPageTip') + ' ' + page[formData.type].title" value="other" />
</el-select>
</el-form-item>
<el-form-item label="" v-show="hope == 'template'">
<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-select>
</el-form-item>
<el-form-item label="" v-show="hope == 'template'">
<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" :key="key"/>
</el-select>
</el-form-item>
<el-form-item label="" v-show="hope == 'diy'">
<el-select v-model="formData.id" class="w-full">
<el-option v-for="(item, index) in page[formData.type].my_page" :label="item.title"
:value="item.id"/>
</el-select>
<div class="mt-[10px]">
<span class="cursor-pointer text-primary mr-[10px]" @click="toDiyList">{{ t('createPage') }}</span>
<span class="cursor-pointer text-primary" @click="refreshMyPage">{{ t('refreshPage') }}</span>
</div>
</el-form-item>
<el-form-item label="" v-show="hope == 'diy'">
<el-select v-model="formData.id" class="w-full">
<el-option v-for="(item, index) in page[formData.type].my_page" :label="item.title" :value="item.id" :key="index" />
</el-select>
<div class="mt-[10px]">
<span class="cursor-pointer text-primary mr-[10px]" @click="toDiyList">{{ t('createPage') }}</span>
<span class="cursor-pointer text-primary" @click="refreshMyPage">{{ t('refreshPage') }}</span>
</div>
</el-form-item>
<el-form-item label="" v-show="hope == 'other'">
<el-select v-model="formData.page" class="w-full">
<el-option v-for="(item, index) in page[formData.type].other_page" :label="item.title"
:value="item.page"/>
</el-select>
</el-form-item>
<el-form-item label="" v-show="hope == 'other'">
<el-select v-model="formData.page" class="w-full">
<el-option v-for="(item, index) in page[formData.type].other_page" :label="item.title"
:value="item.page" :key="index" />
</el-select>
</el-form-item>
</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>
</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>
<script lang="ts" setup>
import {reactive, ref, watch} from 'vue'
import {t} from '@/lang'
import {img} from '@/utils/common'
import {useRouter} from 'vue-router'
import {ElMessage} from 'element-plus'
import {getDecoratePage, getDiyList, changeTemplate} from '@/app/api/diy'
import storage from '@/utils/storage'
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getDecoratePage, getDiyList, changeTemplate } from '@/app/api/diy'
import storage from '@/utils/storage'
const page: any = reactive({})
const showDialog = ref(false)
const router = useRouter()
const hope = ref('template')
const wapDomain = ref('')
const page: any = reactive({})
const showDialog = ref(false)
const router = useRouter()
const hope = ref('template')
const wapDomain = ref('')
//
const formData = reactive({
type: '',
name: '',
mode: '',
template: '',
id: '',
page: '',
title: '',
action: ''
})
//
const formData = reactive({
type: '',
name: '',
mode: '',
template: '',
id: '',
page: '',
title: '',
action: ''
})
//
const refreshData = () => {
formData.type = '';
formData.name = '';
formData.mode = '';
formData.template = '';
formData.id = '';
formData.page = '';
formData.title = '';
formData.action = '';
getDecoratePage({}).then((res => {
for (let key in res.data) {
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)
//
const refreshData = () => {
formData.type = ''
formData.name = ''
formData.mode = ''
formData.template = ''
formData.id = ''
formData.page = ''
formData.title = ''
formData.action = ''
getDecoratePage({}).then(res => {
for (const key in res.data) {
page[key] = res.data[key]
}
}, false);
// uniapp
const postMessage = (key: string) => {
var diyData = JSON.stringify({
type: 'appOnReady',
message: '加载完成'
});
if (window['previewIframe_' + key]) window['previewIframe_' + key].contentWindow.postMessage(diyData, '*');
};
for (const 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
//
const initLoad = (key: string) => {
page[key].loadingDev = true;
page[key].isDisabledPop = true;
page[key].loadingIframe = false;
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 {
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 = () => {
if (wapDomain.value.trim().length == 0) {
// uniapp
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({
type: 'warning',
message: `${t('wapDomainPlaceholder')}`,
});
return;
message: `${t('placeholderTemplate')}`
})
return
}
let wapUrl = wapDomain.value + '/wap';
storage.set({key: 'wap_domain', data: wapUrl});
for (let key in page) {
if (page[key].use_template.url) {
page[key].wapUrl = wapUrl;
setDomain(key);
}
} else if (hope.value == 'diy') {
if (formData.id == '') {
ElMessage({
type: 'warning',
message: `${t('placeholderMyPage')}`
})
return
}
setTimeout(() => {
for (let 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;
} else if (hope.value == 'other') {
if (formData.page == '') {
ElMessage({
type: 'warning',
message: `${t('placeholderOtherPage')}`
})
return
}
}
//
const toDecorate = (data: any) => {
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);
}
if (isRepeat.value) return
isRepeat.value = true
//
const toPreview = (data: any) => {
let page = data.page;
if (data.url) {
page = data.url;
} else if (data.id) {
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();
})
}
changeTemplate({
...formData
}).then((res) => {
isRepeat.value = false
showDialog.value = false
refreshData()
})
}
</script>
<style lang="scss" scoped>
.page-item {
.page-item {
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
background-image: url(@/app/assets/images/iphone_bg.png);
background-color: var(--el-bg-color);
background-size: 100%;
.item-hide {
display: none;
.item-hide {
display: none;
.item-btn-box {
.item-btn-box {
button {
height: 35px;
width: 100px;
button {
height: 35px;
width: 100px;
& ~ button {
margin-top: 15px;
margin-left: 0;
}
}
&~button {
margin-top: 15px;
margin-left: 0;
}
}
}
}
}
}
&:hover {
.item-hide:not(.disabled) {
display: block !important;
}
}
}
&:hover {
.item-hide:not(.disabled) {
display: block !important;
}
}
}
</style>

View File

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

View File

@ -53,140 +53,140 @@
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue'
import {t} from '@/lang'
import {useRoute} from 'vue-router'
import {getWeappConfig} from '@/app/api/weapp'
import {getUrl} from '@/app/api/sys'
import {useClipboard} from '@vueuse/core'
import {ElMessage} from 'element-plus'
import {img} from '@/utils/common'
import QRCode from "qrcode";
import storage from '@/utils/storage'
import {getPreviewData} from '@/app/api/diy'
import { ref, reactive, watch } from 'vue'
import { t } from '@/lang'
import { useRoute } from 'vue-router'
import { getWeappConfig } from '@/app/api/weapp'
import { getUrl } from '@/app/api/sys'
import { useClipboard } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import { img } from '@/utils/common'
import QRCode from 'qrcode'
import storage from '@/utils/storage'
import { getPreviewData } from '@/app/api/diy'
const wapUrl = ref('')
const wapDomain = ref('')
const wapImage = ref('')
const wapPreview = ref('')
const wapUrl = ref('')
const wapDomain = ref('')
const wapImage = ref('')
const wapPreview = ref('')
const loading = ref(false)
const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) //
const timeFrame = ref(0)
const loading = ref(false)
const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) //
const timeFrame = ref(0)
var time = new Date().getTime();
const route = useRoute();
route.query.id = route.query.id || 0;
route.query.name = route.query.name || '';
let time = new Date().getTime()
const route = useRoute()
route.query.id = route.query.id || 0
route.query.name = route.query.name || ''
getUrl().then((res: any) => {
wapDomain.value = res.data.wap_domain;
wapUrl.value = res.data.wap_url;
setDomain();
getUrl().then((res: any) => {
wapDomain.value = res.data.wap_domain
wapUrl.value = res.data.wap_url
setDomain()
//
if (import.meta.env.MODE == 'production') return;
//
if (import.meta.env.MODE == 'production') return
// envwap
if (wapDomain.value) return;
// envwap
if (wapDomain.value) return
let wap_domain_storage = storage.get('wap_domain');
if (wap_domain_storage) {
wapUrl.value = wap_domain_storage
setDomain();
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;
let wap_domain_storage = storage.get('wap_domain')
if (wap_domain_storage) {
wapUrl.value = wap_domain_storage
setDomain()
return
}
const setDomain = () => {
getPreviewData({
id: route.query.id,
name: route.query.name,
}).then((res: any) => {
let data = res.data;
wapPreview.value = `${wapUrl.value}/${data.page}`;
timeFrame.value = new Date().getTime()
})
// id
if (import.meta.env.MODE == 'development') {
let 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
})
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 = () => {
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
const loadIframe = () => {
if (!wapPreview.value) return;
var loadTime = new Date().getTime();
var 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
watch(copied, () => {
if (copied.value) {
ElMessage({
message: t('copySuccess'),
type: 'success'
})
}
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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,215 +1,211 @@
<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">
<iframe v-show="loadingIframe" class="w-[375px]" :src="wapPreview" frameborder="0"
id="previewIframe"></iframe>
<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="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable/>
</div>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
</div>
<div class="flex full-container">
<iframe v-show="loadingIframe" class="w-[375px]" :src="wapPreview" frameborder="0" id="previewIframe"></iframe>
<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="mb-[20px] flex flex-col">
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
</div>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
</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>
<el-form label-width="40px" class="px-[20px]">
<div class="px-[20px] pb-[10px] font-bold">{{ t('h5') }}</div>
<el-form label-width="40px" class="px-[20px]">
<el-form-item :label="t('link')" v-show="wapPreview">
<el-input readonly :value="wapPreview">
<template #append>
<el-button @click="copyEvent(wapPreview)" class="bg-primary copy">{{ t('copy') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('link')" v-show="wapPreview">
<el-input readonly :value="wapPreview">
<template #append>
<el-button @click="copyEvent(wapPreview)" class="bg-primary copy">{{ t('copy') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label=" " v-show="wapImage">
<el-image :src="wapImage"/>
</el-form-item>
<el-form-item label=" " v-show="wapImage">
<el-image :src="wapImage" />
</el-form-item>
</el-form>
</el-form>
<div class="px-[20px] pb-[10px] font-bold mt-[40px]">{{t('weapp')}}</div>
<el-form label-width="40px" class="px-[20px]">
<el-form-item label=" " v-if="weappConfig.qr_code">
<el-image class="w-[100px] h-[100px]" :src="img(weappConfig.qr_code)"/>
</el-form-item>
<el-form-item label=" " v-else>
<span class="text-gray-400">{{t('weappNotSet')}}</span>
</el-form-item>
</el-form>
<div class="px-[20px] pb-[10px] font-bold mt-[40px]">{{ t('weapp') }}</div>
<el-form label-width="40px" class="px-[20px]">
<el-form-item label=" " v-if="weappConfig.qr_code">
<el-image class="w-[100px] h-[100px]" :src="img(weappConfig.qr_code)" />
</el-form-item>
<el-form-item label=" " v-else>
<span class="text-gray-400">{{ t('weappNotSet') }}</span>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue'
import {t} from '@/lang'
import {useRoute} from 'vue-router'
import {getWeappConfig} from '@/app/api/weapp'
import {getUrl} from '@/app/api/sys'
import {useClipboard} from '@vueuse/core'
import {ElMessage} from 'element-plus'
import {img} from '@/utils/common'
import QRCode from "qrcode";
import storage from '@/utils/storage'
import { ref, reactive, watch } from 'vue'
import { t } from '@/lang'
import { useRoute } from 'vue-router'
import { getWeappConfig } from '@/app/api/weapp'
import { getUrl } from '@/app/api/sys'
import { useClipboard } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import { img } from '@/utils/common'
import QRCode from 'qrcode'
import storage from '@/utils/storage'
const wapUrl = ref('')
const wapDomain = ref('')
const wapImage = ref('')
const wapPreview = ref('')
const wapUrl = ref('')
const wapDomain = ref('')
const wapImage = ref('')
const wapPreview = ref('')
const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) //
const timeIframe = ref(0) // iframe
const difference = ref(0) // 1000wap
const loadingIframe = ref(false) // iframe
const loadingDev = ref(false) //
const timeIframe = ref(0) // iframe
const difference = ref(0) // 1000wap
var time = new Date().getTime();
const route = useRoute();
route.query.page = route.query.page || ''; //
const route = useRoute()
route.query.page = route.query.page || '' //
getUrl().then((res: any) => {
wapUrl.value = res.data.wap_url;
setDomain();
getUrl().then((res: any) => {
wapUrl.value = res.data.wap_url
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
if (wapDomain.value) {
wapUrl.value = wapDomain.value + '/wap';
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;
// envwap
if (wapDomain.value) {
wapUrl.value = wapDomain.value + '/wap'
setDomain()
}
const setDomain = () => {
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);
}
const wap_domain_storage = storage.get('wap_domain')
if (wap_domain_storage) {
wapUrl.value = wap_domain_storage
setDomain()
}
})
// uni-app
window.addEventListener('message', (event) => {
try {
let data = JSON.parse(event.data);
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
loadingDev.value = false;
loadingIframe.value = true;
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 = '';
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 weappConfig = reactive({
qr_code: ''
const setDomain = () => {
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) => {
if (res.code == 1) {
let data = res.data;
weappConfig.qr_code = data.qr_code;
}
})
//
const initLoad = () => {
loadingDev.value = true
loadingIframe.value = false
wapPreview.value = ''
wapImage.value = ''
}
//
const {copy, isSupported, copied} = useClipboard()
const copyEvent = (text: string) => {
if (!isSupported.value) {
ElMessage({
message: t('notSupportCopy'),
type: 'warning'
})
}
copy(text)
const weappConfig = reactive({
qr_code: ''
})
//
getWeappConfig().then((res: any) => {
if (res.code == 1) {
const data = res.data
weappConfig.qr_code = data.qr_code
}
})
watch(copied, () => {
if (copied.value) {
ElMessage({
message: t('copySuccess'),
type: 'success'
})
}
})
//
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>
<style lang="scss">
body {
background: #edf0f3;
}
body {
background: #edf0f3;
}
.copy {
background: var(--el-color-primary) !important;
color: var(--el-color-white) !important;
}
</style>
<style lang="scss" scoped>
.copy {
background: var(--el-color-primary) !important;
color: var(--el-color-white) !important;
}
</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-row>
<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">
<span>{{ item.dir }}</span>
</el-col>
@ -266,7 +266,7 @@
</el-col>
</el-row>
<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">
<span>{{ item.dir }}</span>
</el-col>
@ -308,7 +308,7 @@
<div v-show="installStep == 3" class="h-[50vh] mt-[20px] flex flex-col">
<el-result icon="success" :title="t('addonInstallSuccess')"></el-result>
<!-- 提示信息 -->
<div v-for="item 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" />
</div>
</div>
@ -333,7 +333,7 @@
</el-col>
</el-row>
<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">
<span>{{ item.dir }}</span>
</el-col>
@ -349,7 +349,7 @@
</span>
</el-col>
</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">
<span>{{ item.dir }}</span>
</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 { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
import { img } from '@/utils/common'
import 'vue-web-terminal/lib/theme/dark.css'
import { Terminal, TerminalFlash } from 'vue-web-terminal'
import { findFirstValidRoute } from '@/router/routers'
@ -421,7 +420,7 @@ const downEventHintFn = () => {
downEvent(currDownData.value, true)
}
const activeNameTabFn = (data) => {
const activeNameTabFn = (data:any) => {
activeName.value = data
storage.set({ key: 'storeActiveName', data })
}
@ -563,7 +562,7 @@ const onExecCmd = (key, command, success, failed, name)=> {
}
function makeIterator(array: string[]) {
var nextIndex = 0
let nextIndex = 0
return {
next() {
if ((nextIndex + 1) == array.length) {
@ -614,6 +613,7 @@ const getInstallTask = (first: boolean = true) => {
}
}
if (res.data.error) {
ElMessage({ message: '插件安装失败', type: 'error', duration: 5000 })
return
}
if (res.data.mode == 'cloud') {
@ -982,6 +982,9 @@ html.dark .table-head-bg {
height: calc(100vh - 120px);
box-sizing: border-box;
}
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
</style>
<style>

View File

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

View File

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

View File

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

View File

@ -2,72 +2,74 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-[20px]">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">
<el-col :span="6" class="min-w-[100px]">
<el-row class="flex">
<el-col :span="6" class="min-w-[100px]">
<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="footer-item text-[14px] text-[#666]">
<span>{{ t('totalCommission') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="6" class="min-w-[100px]">
</el-col>
<el-col :span="6" class="min-w-[100px]">
<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="footer-item text-[14px] text-[#666]">
<span>{{ t('commission') }}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="6" class="min-w-[100px]">
</el-col>
<el-col :span="6" class="min-w-[100px]">
<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="footer-item text-[14px] text-[#666]">
<span>{{ t('withdrawnCommission') }}</span>
</div>
</div>
</div>
</el-col>
</el-col>
<el-col :span="6" class="min-w-[100px]">
<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="footer-item text-[14px] text-[#666]">
<span>{{ t('cashOutingCommission') }}</span>
</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</el-card>
<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-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 :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="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-form-item>
<el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker
v-model="memberAccountLogTableData.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="memberAccountLogTableData.searchParam.create_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
:end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadMemberAccountLogList()">{{ t('search') }}</el-button>
@ -89,45 +91,49 @@
</template>
</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 }">
<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-else src="@/app/assets/images/default_headimg.png" alt="" >
<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-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="mobile" :label="t('mobile')" min-width="100">
<template #default="{ row }">
{{ row.member.mobile || '' }}
<el-table-column prop="mobile" :label="t('mobile')" min-width="100">
<template #default="{ row }">
{{ row.member.mobile || '' }}
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="account_data" :label="t('accountData')" min-width="80" align="right">
<template #default="{ row }">
<span v-if="row.account_data >= 0">+{{ row.account_data }}</span>
<span v-else>{{ row.account_data }}</span>
<template #default="{ row }">
<span v-if="row.account_data >= 0">+{{ row.account_data }}</span>
<span v-else>{{ row.account_data }}</span>
</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="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="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="create_time" :show-overflow-tooltip="true" :label="t('createTime')"
min-width="150" />
<el-table-column :label="t('operation')" align="right" fixed="right" width="100">
<template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template>
<template #default="{ row }">
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="memberAccountLogTableData.page" v-model:page-size="memberAccountLogTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="memberAccountLogTableData.total"
@size-change="loadMemberAccountLogList()" @current-change="loadMemberAccountLogList" />
<el-pagination v-model:current-page="memberAccountLogTableData.page"
v-model:page-size="memberAccountLogTableData.limit" layout="total, sizes, prev, pager, next, jumper"
:total="memberAccountLogTableData.total" @size-change="loadMemberAccountLogList()"
@current-change="loadMemberAccountLogList" />
</div>
</div>
</el-card>
@ -139,58 +145,57 @@
import { reactive, ref } from 'vue'
import { t } from '@/lang'
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 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 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,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
keywords:"",
from_type:"",
create_time:"",
mobile:"",
member_id:member_id
searchParam: {
keywords: '',
from_type: '',
create_time: '',
mobile: '',
member_id: member_id
}
})
let fromTypeList = ref([])
const fromTypeList = ref([])
const setFromTypeList = async () => {
fromTypeList.value = await (await getChangeTypeList('commission')).data
}
setFromTypeList();
setFromTypeList()
/**
* 获取佣金总计
*/
const commissionStatistics = ref([])
const commissionStatistics = ref([])
const checkCommissionInfo = () => {
getCommissionSum({
member_id
}).then(res => {
commissionStatistics.value = res.data;
})
getCommissionSum({
member_id
}).then(res => {
commissionStatistics.value = res.data
})
}
checkCommissionInfo()
const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields();
loadMemberAccountLogList();
formEl.resetFields()
loadMemberAccountLogList()
}
/**
@ -204,7 +209,7 @@ const loadMemberAccountLogList = (page: number = 1) => {
getCommissionList({
page: memberAccountLogTableData.page,
limit: memberAccountLogTableData.limit,
...memberAccountLogTableData.searchParam
...memberAccountLogTableData.searchParam
}).then(res => {
memberAccountLogTableData.loading = false
memberAccountLogTableData.data = res.data.data
@ -221,7 +226,7 @@ const moneyDialog: Record<string, any> | null = ref(null)
* 查看详情
* @param data
*/
const infoEvent = (data: any) => {
const infoEvent = (data: any) => {
moneyDialog.value.setFormData(data)
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}`)
}
</script>
<style lang="scss" scoped></style>

View File

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

View File

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

View File

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

View File

@ -61,20 +61,20 @@ const loading = ref(true)
*/
const initialFormData = {
account_data: 0,
account_type:'',
create_time:'',
from_type:'',
from_type_name:'',
member_id:'',
memo:'',
related_id:'',
member: {
headimg:'',
mobile:'',
member_no: '',
username:'',
nickname:'',
}
account_type: '',
create_time: '',
from_type: '',
from_type_name: '',
member_id: '',
memo: '',
related_id: '',
member: {
headimg: '',
mobile: '',
member_no: '',
username: '',
nickname: ''
}
}
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) => {
loading.value = true;
loading.value = true
Object.assign(formData, initialFormData)
if (row) {

View File

@ -1,39 +1,41 @@
<template>
<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">
<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="" >
<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')" >
<div class="input-width"> {{ formData.member.member_no }} </div>
</el-form-item>
<el-form-item :label="t('memberId')">
<div class="input-width"> {{ formData.member.member_no }} </div>
</el-form-item>
<el-form-item :label="t('nickName')" >
<el-form-item :label="t('nickName')">
<div class="input-width"> {{ formData.member.nickname }} </div>
</el-form-item>
<el-form-item :label="t('mobile')" >
<el-form-item :label="t('mobile')">
<div class="input-width"> {{ formData.member.mobile }} </div>
</el-form-item>
<el-form-item :label="t('accountData')" >
<el-form-item :label="t('accountData')">
<div class="input-width"> {{ formData.account_data }} </div>
</el-form-item>
<el-form-item :label="t('fromType')" >
<el-form-item :label="t('fromType')">
<div class="input-width"> {{ formData.from_type_name }} </div>
</el-form-item>
<el-form-item :label="t('memo')" >
<el-form-item :label="t('memo')">
<div class="input-width"> {{ formData.memo }} </div>
</el-form-item>
<el-form-item :label="t('createTime')" >
<el-form-item :label="t('createTime')">
<div class="input-width"> {{ formData.create_time }} </div>
</el-form-item>
@ -61,20 +63,20 @@ const loading = ref(true)
*/
const initialFormData = {
account_data: 0,
account_type:'',
create_time:'',
from_type:'',
from_type_name:"",
member_id:'',
memo:'',
related_id:'',
member: {
headimg:'',
mobile:'',
member_no: '',
username:'',
nickname:'',
}
account_type: '',
create_time: '',
from_type: '',
from_type_name: '',
member_id: '',
memo: '',
related_id: '',
member: {
headimg: '',
mobile: '',
member_no: '',
username: '',
nickname: ''
}
}
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) => {
loading.value = true;
loading.value = true
Object.assign(formData, initialFormData)
if (row) {

View File

@ -57,17 +57,17 @@ const loading = ref(true)
*/
const initialFormData = {
account_data: 0,
account_type:'',
create_time:'',
from_type:'',
from_type_name:"",
headimg:'',
member_id:'',
memo:'',
mobile:'',
nickname:'',
related_id:'',
username:''
account_type: '',
create_time: '',
from_type: '',
from_type_name: '',
headimg: '',
member_id: '',
memo: '',
mobile: '',
nickname: '',
related_id: '',
username: ''
}
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) => {
loading.value = true;
loading.value = true
Object.assign(formData, initialFormData)
if (row) {

View File

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

View File

@ -61,20 +61,20 @@ const loading = ref(true)
*/
const initialFormData = {
account_data: 0,
account_type:'',
create_time:'',
from_type:'',
from_type_name:"",
member_id:'',
memo:'',
related_id:'',
member: {
headimg:'',
mobile:'',
member_no: '',
username:'',
nickname:'',
}
account_type: '',
create_time: '',
from_type: '',
from_type_name: '',
member_id: '',
memo: '',
related_id: '',
member: {
headimg: '',
mobile: '',
member_no: '',
username: '',
nickname: ''
}
}
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) => {
loading.value = true;
loading.value = true
Object.assign(formData, initialFormData)
if (row) {
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'
const route = useRoute()
const pageName = route.meta.title;
const pageName = route.meta.title
let memberLabelTableData = reactive({
const memberLabelTableData = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"label_name":""
searchParam: {
label_name: ''
}
})
const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined)=>{
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields();
loadMemberLabelList();
formEl.resetFields()
loadMemberLabelList()
}
/**

View File

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

View File

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

View File

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

View File

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

View File

@ -2,28 +2,30 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-[20px]">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
<el-row class="flex">
<el-col :span="12" class="min-w-[100px]">
<el-statistic :value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'">
<template #title>
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div>
</template>
</el-statistic>
</el-col>
<el-col :span="12" class="min-w-[100px]">
<el-statistic :value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'">
<template #title>
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div>
</template>
</el-statistic>
</el-col>
<el-row class="flex">
<el-col :span="12" class="min-w-[100px]">
<el-statistic
:value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'">
<template #title>
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div>
</template>
</el-statistic>
</el-col>
<el-col :span="12" class="min-w-[100px]">
<el-statistic
:value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'">
<template #title>
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div>
</template>
</el-statistic>
</el-col>
</el-row>
</el-card>
</el-row>
</el-card>
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
@ -34,35 +36,41 @@
<el-form-item :label="t('orderFromName')" prop="order_from">
<el-select v-model="orderTableData.searchParam.order_from" clearable class="input-width">
<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-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-select v-model="orderTableData.searchParam.order_status" clearable class="input-width">
<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-form-item>
<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 :label="t('rechargeMoney')">
<div class="region-input">
<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>
<span class="separator">-</span>
<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>
</div>
</el-form-item>
<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>
@ -81,8 +89,10 @@
<el-table-column :show-overflow-tooltip="true" :label="t('member')" align="left" min-width="140">
<template #default="{ row }">
<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-else src="@/app/assets/images/default_headimg.png" alt="">
<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-else
src="@/app/assets/images/default_headimg.png" alt="">
<div class="flex flex flex-col">
<span class="">{{ row.member.nickname || '' }}</span>
<span class="">{{ row.member.mobile || '' }}</span>
@ -91,7 +101,8 @@
</template>
</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" />
@ -120,10 +131,13 @@
<template #default="{ row }">
<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">
<el-button type="primary" link @click="orderEvent(row, item.class)">{{ item.name }}</el-button>
<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>
</template>
</template>
</el-table-column>
@ -158,7 +172,7 @@ import { getChannelType } from '@/app/api/sys'
import { useRouter, useRoute } from 'vue-router'
import { AnyObject } from '@/types/global'
import type { FormInstance } from 'element-plus'
import { img } from '@/utils/common'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
@ -203,7 +217,7 @@ const statusList = ref([])
const searchFormRef = ref<FormInstance>()
const setCategoryList = async () => {
statusList.value = await (await getRechargeOrderStatusList({})).data
statusList.value = await (await getRechargeOrderStatusList()).data
}
setCategoryList()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<template>
<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-item :label="t('title')" >
<div class="input-width"> {{ formData.title }} </div>
</el-form-item>
@ -18,7 +18,7 @@
<el-form-item :label="t('count')" >
<div class="input-width"> {{ formData.count }} </div>
</el-form-item>
<el-form-item :label="t('task')" >
<div class="input-width"> {{ formData.task }} </div>
</el-form-item>
@ -66,19 +66,19 @@ const loading = ref(true)
*/
const initialFormData = {
count: 0,
create_time:'',
crond_length:'',
crond_type:'',
crond_type_name:'',
data:'',
delete_time:'',
last_time:'',
next_time:'',
status_desc:'',
title:'',
type:'',
type_name:'',
update_time:''
create_time: '',
crond_length: '',
crond_type: '',
crond_type_name: '',
data: '',
delete_time: '',
last_time: '',
next_time: '',
status_desc: '',
title: '',
type: '',
type_name: '',
update_time: ''
}
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) => {
loading.value = true
@ -101,7 +101,6 @@ const setFormData = async (row: any = null) => {
if (row[key] != undefined) formData[key] = row[key]
})
}
loading.value = false
}

View File

@ -42,7 +42,7 @@
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { editNoticeStatus } from '@/app/api/notice'
// import { editNoticeStatus } from '@/app/api/notice'
const showDialog = ref(false)
const loading = ref(true)
@ -57,7 +57,7 @@ const initialFormData = {
message_type: '',
name: '',
nickname: '',
receiver: '',
receiver: ''
}
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) => {
loading.value = true;
loading.value = true
Object.assign(formData, initialFormData)
if (row) {

View File

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