Compare commits

..

3 Commits

Author SHA1 Message Date
CQ
ca75099899 fix niucloud 2025-10-15 18:13:44 +08:00
CQ
e879cf0b7a fix uni-app 2025-10-15 18:07:46 +08:00
CQ
231f476a6f fix admin 2025-10-15 18:07:03 +08:00
678 changed files with 7461 additions and 7249 deletions

View File

@ -147,7 +147,10 @@ div.edui-box {
overflow: visible;
z-index: 1 !important;
}
/* 全屏状态 */
.edui-default .edui-editor.edui-fullscreen {
z-index: 999 !important;
}
.edui-editor div {
width: auto;
height: auto;

View File

@ -291,13 +291,13 @@ export function getSiteAddons() {
* @returns
*/
export function getShowApp() {
return request.get('site/showApp')
return request.get('site/showCustomer')
}
/**
*
*
* @returns
*/
export function getShowMarketing() {
return request.get('site/showMarketing')
export function getShowSpecialMenu() {
return request.get('site/special_menu')
}

View File

@ -249,7 +249,7 @@ import Storage from '@/utils/storage'
import { useRouter } from 'vue-router'
const router = useRouter()
const terminalId = ref(Date.now());
const terminalId = ref(Date.now());
const showDialog = ref<boolean>(false)
const upgradeContent = ref<null | AnyObject>(null)
const isAllowUpgrade = ref(true) //
@ -299,7 +299,7 @@ const getUpgradeTaskFn = () => {
if (!upgradeContent.value) {
upgradeContent.value = data.upgrade_content
if (upgradeContent.value || !data.upgrade_content || !Array.isArray(data.upgrade_content.content)) {
if (!data.upgrade_content || !Array.isArray(data.upgrade_content.content)) {
return
}
@ -691,7 +691,7 @@ defineExpose({
white-space: pre-wrap;
}
::v-deep .number-of-steps {
:deep(.number-of-steps) {
.el-step__line {
margin: 0 25px;
background: #dddddd;

View File

@ -50,6 +50,7 @@ import { img } from '@/utils/common'
import useUserStore from '@/stores/modules/user'
import { useRouter } from 'vue-router'
import { t } from '@/lang'
import storage from '@/utils/storage'
const addonIndexRoute = useUserStore().addonIndexRoute
const router = useRouter()
@ -73,6 +74,7 @@ const toLink = (item: any) => {
} else {
addonIndexRoute[item.key] && router.push({ name: addonIndexRoute[item.key] })
}
storage.set({ key: 'activeAppKey', data: item.key })
}
</script>

View File

@ -18,7 +18,7 @@
<div class="image-slot">
<img class="w-[40px] h-[40px]" src="@/app/assets/images/index/app_default.png" />
</div>
</template>
</template>
</el-image>
<div class="flex flex-col justify-between w-[180px]">
<div class="text-[14px] flex items-center">
@ -45,7 +45,7 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { getShowMarketing } from '@/app/api/site'
// import { getShowMarketing } from '@/app/api/site'
import { img } from '@/utils/common'
import useUserStore from '@/stores/modules/user'
import { useRouter } from 'vue-router'
@ -57,8 +57,8 @@ const marketingList = ref<Record<string, any>[]>([])
const loading = ref(true)
const getMarketingList = async () => {
const res = await getShowMarketing()
marketingList.value = res.data
// const res = await getShowMarketing()
// marketingList.value = res.data
loading.value = false
}
getMarketingList()

View File

@ -62,7 +62,7 @@
</div>
<div v-show="formData.package_type == 'cloud'">
<el-form-item :label="t('icon')">
<el-form-item :label="t('icon')" prop="build.icon">
<div class="input-width" >
<upload-file v-model="formData.build.icon" accept=".zip" api="sys/document/applet"></upload-file>
</div>
@ -80,7 +80,7 @@
<div class="form-tip flex items-center">证书可以自己生成也可通过niucloud提供的<span class="text-primary cursor-pointer" @click="generateSingCertRef.open()">证书生成工具生成</span></div>
</el-form-item>
<div v-show="formData.cert.type == 'private'">
<el-form-item :label="t('certFile')" prop="cert.cert_file">
<el-form-item :label="t('certFile')" prop="cert.file">
<div class="input-width" >
<upload-file v-model="formData.cert.file" accept="" api="sys/document/android_cert"></upload-file>
</div>
@ -166,6 +166,7 @@ const initialFormData = {
},
cert: {
type: 'public',
file: '',
key_alias: '',
key_password: '',
store_password: ''
@ -211,7 +212,7 @@ const formRules = computed(() => {
'build.icon': [
{ required: formData.package_type == 'cloud', message: '请上传图标文件', trigger: 'blur' },
],
'cert.cert_file': [
'cert.file': [
{ required: formData.package_type == 'cloud' && formData.cert.type == 'private', message: '请上传证书文件', trigger: 'blur' }
],
'cert.key_alias': [

View File

@ -65,7 +65,7 @@
<el-button type="primary" link v-if="row.status == 'upload_success'" @click="releaseEvent(row)">{{ t('release') }}</el-button>
<el-button type="primary" link v-if="row.status == 'create_fail'" @click="handleFailReason(row)">{{ t('failReason') }}</el-button>
<el-button type="primary" link v-if="row.package_path && row.upgrade_type != 'market'" @click="downloadEvent(row)">{{ t('download') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row)">{{ t('delete') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>

View File

@ -35,7 +35,7 @@
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="bottomNavTableData.page" v-model:page-size="bottomNavTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="bottomNavTableData.total"
@size-change="loadbottomNavList()" @current-change="loadbottomNavList" />
@size-change="loadBottomNavList()" @current-change="loadBottomNavList" />
</div>
</el-card>

View File

@ -91,7 +91,7 @@ const editEvent = (data)=> {
<!-- 设置弹窗标题 -->
<style scoped>
/* 使用深度选择器 */
::v-deep .custom-theme-dialog .el-dialog__title {
:deep(.custom-theme-dialog .el-dialog__title) {
font-size: 16px;
}
</style>

View File

@ -336,7 +336,7 @@
<template #content>
<div class="w-[400px]">
{{t("installTips")}}
</div>
</div>
</template>
<el-button :disabled="!installCheckResult.is_pass || cloudInstalling" :loading="localInstalling" @click="handleInstall">{{ t("localInstall") }}</el-button>
</el-tooltip>
@ -344,7 +344,7 @@
<template #content>
<div class="w-[400px]">
{{t("cloudInstallTips")}}
</div>
</div>
</template>
<el-button type="primary" :disabled="!installCheckResult.is_pass || localInstalling" :loading="cloudInstalling" @click="handleCloudInstall">{{ t("cloudInstall") }}</el-button>
</el-tooltip>
@ -771,7 +771,7 @@ const installAddonFn = (key: string) => {
*/
const upgradeStartTime = ref<number | null>(null)
const upgradeDuration = ref(0) //
let upgradeTimer: ReturnType<typeof setInterval> | null = null
let upgradeTimer: ReturnType<typeof setInterval> | null = null
let notificationEl = null
const getInstallTask = (first: boolean = true) => {
@ -816,7 +816,7 @@ const getInstallTask = (first: boolean = true) => {
setTimeout(() => {
getInstallTask(false)
}, 2000)
} else {
if (!first) {
installStep.value = 2
@ -1269,7 +1269,7 @@ html.dark .table-head-bg {
height: 100px;
}
:deep(.el-table__body tr:hover td:first-child) {
// border-bottom: 1px solid var(--el-table-border-color);
// border-bottom: 1px solid var(--el-table-border-color);
}
:deep(.el-table__body tr) {
position: relative;
@ -1383,7 +1383,7 @@ html.dark .table-head-bg {
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
::v-deep .number-of-steps {
:deep(.number-of-steps) {
.el-step__line {
margin: 0 25px;
background: #dddddd;

View File

@ -529,17 +529,20 @@ const save = (callback: any) => {
const api = posterStore.id ? editPoster : addPoster
api(data).then((res: any) => {
isRepeat.value = false
// isRepeat.value = false
if (res.code == 1) {
if (posterStore.id) {
isRepeat.value = false //
} else {
// isRepeat.value = false
location.href = `${location.origin}${backPath}`
}
if (callback) callback(res.data.id)
}
}).catch(() => {
isRepeat.value = false
}).finally(() => {
// isRepeat.value = false
})
}

View File

@ -6,7 +6,7 @@
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true">{{ t('添加海报') }}</el-button>
</div>
<div class="mt-[20px]" v-if="!isImagick">
<div class="mt-[20px]" v-if="!isImagick && !posterTableData.loading">
<el-alert type="warning" show-icon :closable="false">
<template #title>
<span class="!text-[14px]">检测到PHP未安装ImageMagick扩展需安装后才能使用海报功能</span>
@ -277,7 +277,7 @@ const previewPoster = (data: any) => {
if (res.data) {
previewPosterUrl.value = res.data
previewDialogVisible.value = true
}
}
isRepeat.value = false
})
}
@ -287,11 +287,10 @@ const resetForm = (formEl: FormInstance | undefined) => {
formEl.resetFields()
loadPosterPageList()
}
const isImagick = ref(false)
const isImagick = ref(true)
// imagemagick
const checkImagickFn = () => {
checkImagick().then((res:any) => {
console.log(res)
isImagick.value = res.data
})

View File

@ -22,19 +22,19 @@
<h3 class="panel-title !text-[14px] bg-[#F4F5F7] p-3 border-[#E6E6E6] border-solid border-b-[1px]">{{ t('putOnRecordEdit') }}</h3>
<el-form-item :label="t('icp')" prop="icp">
<el-input v-model.trim="formData.icp" :placeholder="t('icpPlaceholder')" class="input-width" clearable maxlength="20"/>
<div class="form-tip">{{ t('网站的ICP备案号显示在H5和PC端底部') }}</div>
<div class="form-tip">{{ t('网站的ICP备案号,显示在PC端底部') }}</div>
</el-form-item>
<el-form-item :label="t('govRecord')" >
<el-input v-model.trim="formData.gov_record" :placeholder="t('govRecordPlaceholder')" class="input-width" clearable maxlength="50"/>
<div class="form-tip">{{ t('公安部门登记的备案信息显示在pc底部') }}</div>
<div class="form-tip">{{ t('公安部门登记的备案信息,显示在PC底部') }}</div>
</el-form-item>
<el-form-item :label="t('govUrl')" >
<el-input v-model.trim="formData.gov_url" :placeholder="t('govUrlPlaceholder')" class="input-width" clearable />
<div class="form-tip">{{ t('H5和PC底部显示的网站公安点击跳转的链接') }}</div>
<div class="form-tip">{{ t('PC底部显示的网站公安点击跳转的链接') }}</div>
</el-form-item>
<el-form-item :label="t('marketSupervisionUrl')" >
<el-input v-model.trim="formData.market_supervision_url" rows="4" clearable :placeholder="t('marketSupervisionUrlPlaceholder')" class="input-width" />
<div class="form-tip">{{ t('H5和PC底部显示的市场监督管理局点击跳转的链接') }}</div>
<div class="form-tip">{{ t('PC底部显示的市场监督管理局点击跳转的链接') }}</div>
</el-form-item>
</div>
</el-card>

View File

@ -1,82 +1,86 @@
<template>
<el-dialog v-model="showDialog" :title="formData.uid ? t('updateUser') : t('addUser')" width="750px" :destroy-on-close="true">
<el-scrollbar>
<div class="max-h-[60vh]">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" autocomplete="off" v-loading="loading">
<el-form-item :label="t('username')" prop="username">
<el-input v-model.trim="formData.username" clearable :placeholder="t('usernamePlaceholder')" class="input-width" :readonly="formData.uid" :disabled="formData.uid" @click="realnameInput = false" @blur="realnameInput = true" />
</el-form-item>
<el-dialog v-model="showDialog" :title="formData.uid ? t('updateUser') : t('addUser')" width="750px" :destroy-on-close="true">
<el-scrollbar>
<div class="max-h-[60vh]">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" autocomplete="off" v-loading="loading">
<el-form-item :label="t('username')" prop="username">
<el-input v-model.trim="formData.username" clearable :placeholder="t('usernamePlaceholder')" class="input-width" :readonly="formData.uid" :disabled="formData.uid" @click="realnameInput = false" @blur="realnameInput = true" />
</el-form-item>
<el-form-item :label="t('headImg')">
<upload-image v-model="formData.head_img" />
</el-form-item>
<el-form-item :label="t('headImg')">
<upload-image v-model="formData.head_img" />
</el-form-item>
<el-form-item :label="t('userRealName')" prop="real_name">
<el-input v-model.trim="formData.real_name" :placeholder="t('userRealNamePlaceholder')" :readonly="realnameInput" @click="realnameInput = false" @blur="realnameInput = true" clearable class="input-width" maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('手机号')" prop="mobile">
<el-input v-model.trim="formData.mobile" :placeholder="t('请输入手机号')" clearable class="input-width" maxlength="11" show-word-limit />
</el-form-item>
<el-form-item :label="t('password')" prop="password">
<el-input v-model.trim="formData.password" :class="passwordType == 'text' ? '' :'displayPass'" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :readonly="passwordInput" @click="passwordInput = false" @blur="passwordInput = true" >
<template #suffix>
<el-icon @click="togglePasswordVisibility" class="cursor-pointer">
<component :is=" passwordType === 'password' ? 'Hide' : 'View'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('userRealName')" prop="real_name">
<el-input v-model.trim="formData.real_name" :placeholder="t('userRealNamePlaceholder')" :readonly="realnameInput" @click="realnameInput = false" @blur="realnameInput = true" clearable class="input-width" maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
<el-input v-model.trim="formData.confirm_password" :class="confirmPasswordType == 'text' ? '' :'displayPass'" :placeholder="t('confirmPasswordPlaceholder')" clearable class="input-width" :readonly="confirmPasswordInput" @click="confirmPasswordInput = false" @blur="confirmPasswordInput = true" >
<template #suffix>
<el-icon @click="toggleConfirmPasswordVisibility" class="cursor-pointer">
<component :is=" confirmPasswordType === 'password' ? 'Hide' : 'View'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('password')" prop="password">
<el-input v-model.trim="formData.password" :class="passwordType == 'text' ? '' :'displayPass'" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :readonly="passwordInput" @click="passwordInput = false" @blur="passwordInput = true" >
<template #suffix>
<el-icon @click="togglePasswordVisibility" class="cursor-pointer">
<component :is=" passwordType === 'password' ? 'Hide' : 'View'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('userCreateSiteLimit')" v-if="!formData.uid && Object.keys(siteGroup).length" prop="create_site_limit">
<div>
<div>{{ t('siteGroup') }}</div>
<el-checkbox-group v-model="formData.group_ids" @change="groupSelect">
<el-checkbox v-for="item in siteGroup" :label="item.group_id">{{ item.group_name }}</el-checkbox>
</el-checkbox-group>
</div>
<div class="w-full">
<div>{{ t('userCreateSiteLimit') }}</div>
<el-table :data="formData.create_site_limit" size="large" class="w-full">
<el-table-column :label="t('siteGroup')" :show-overflow-tooltip="true">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].group_name : '' }}
</template>
</el-table-column>
<el-table-column :label="t('createSiteNum')">
<template #default="{ $index }">
<el-input v-model.number.trim="formData.create_site_limit[$index].num">
</el-input>
</template>
</el-table-column>
<el-table-column :label="t('siteMonth')">
<template #default="{ $index }">
<el-input v-model.number.trim="formData.create_site_limit[$index].month">
<template #append>{{ t('month') }}</template>
</el-input>
</template>
</el-table-column>
</el-table>
</div>
</el-form-item>
</el-form>
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
<el-input v-model.trim="formData.confirm_password" :class="confirmPasswordType == 'text' ? '' :'displayPass'" :placeholder="t('confirmPasswordPlaceholder')" clearable class="input-width" :readonly="confirmPasswordInput" @click="confirmPasswordInput = false" @blur="confirmPasswordInput = true" >
<template #suffix>
<el-icon @click="toggleConfirmPasswordVisibility" class="cursor-pointer">
<component :is=" confirmPasswordType === 'password' ? 'Hide' : 'View'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('userCreateSiteLimit')" v-if="!formData.uid && Object.keys(siteGroup).length" prop="create_site_limit">
<div>
<div>{{ t('siteGroup') }}</div>
<el-checkbox-group v-model="formData.group_ids" @change="groupSelect">
<el-checkbox v-for="item in siteGroup" :label="item.group_id">{{ item.group_name }}</el-checkbox>
</el-checkbox-group>
</div>
</el-scrollbar>
<div class="w-full">
<div>{{ t('userCreateSiteLimit') }}</div>
<el-table :data="formData.create_site_limit" size="large" class="w-full">
<el-table-column :label="t('siteGroup')" :show-overflow-tooltip="true">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].group_name : '' }}
</template>
</el-table-column>
<el-table-column :label="t('createSiteNum')">
<template #default="{ $index }">
<el-input v-model.number.trim="formData.create_site_limit[$index].num">
</el-input>
</template>
</el-table-column>
<el-table-column :label="t('siteMonth')">
<template #default="{ $index }">
<el-input v-model.number.trim="formData.create_site_limit[$index].month">
<template #append>{{ t('month') }}</template>
</el-input>
</template>
</el-table-column>
</el-table>
</div>
</el-form-item>
</el-form>
</div>
</el-scrollbar>
<template #footer>
<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>
</span>
</template>
</el-dialog>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
@ -93,119 +97,135 @@ const userStore = useUserStore()
const showDialog = ref(false)
const loading = ref(true)
const formData = ref({
uid: 0,
username: '',
password: '',
head_img: '',
real_name: '',
confirm_password: '',
create_site_limit: [],
group_ids: []
uid: 0,
username: '',
password: '',
head_img: '',
mobile: '',
real_name: '',
confirm_password: '',
create_site_limit: [],
group_ids: []
})
const siteGroup = ref({})
const formRef = ref<FormInstance>()
const formRules = computed(() => {
return {
username: [
{ required: true, message: t('usernamePlaceholder'), trigger: 'blur' }
],
password: [
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('passwordPlaceholder'), trigger: 'blur' }
],
real_name: [
{ required: true, message: t('userRealNamePlaceholder'), trigger: 'blur' }
],
confirm_password: [
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
{
validator: (rule: any, value: string, callback: any) => {
if (value != formData.value.password) callback(new Error(t('confirmPasswordError')))
else callback()
},
trigger: 'blur'
return {
username: [
{ required: true, message: t('usernamePlaceholder'), trigger: 'blur' }
],
password: [
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('passwordPlaceholder'), trigger: 'blur' }
],
mobile: [
{ required: true, message: t('请输入手机号'), trigger: 'blur' },
{
validator: (rule: any, value: string, callback: any) => {
if (!Test.mobile(value)) {
callback(new Error(t('手机号格式错误')))
} else {
callback()
}
},
trigger: 'blur'
}
],
real_name: [
{ required: true, message: t('userRealNamePlaceholder'), trigger: 'blur' }
],
confirm_password: [
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
{
validator: (rule: any, value: string, callback: any) => {
if (value != formData.value.password) callback(new Error(t('confirmPasswordError')))
else callback()
},
trigger: 'blur'
}
],
create_site_limit: [
{
validator: (rule: any, value: string, callback: any) => {
if (formData.value.uid) callback()
let verify = true
for (let i = 0; i < formData.value.create_site_limit.length; i++) {
const item = formData.value.create_site_limit[i]
if (Test.empty(item.num)) {
callback(t('siteNumPlaceholder'))
verify = false
break
}
],
create_site_limit: [
{
validator: (rule: any, value: string, callback: any) => {
if (formData.value.uid) callback()
let verify = true
for (let i = 0; i < formData.value.create_site_limit.length; i++) {
const item = formData.value.create_site_limit[i]
if (Test.empty(item.num)) {
callback(t('siteNumPlaceholder'))
verify = false
break
}
if (item.num < 1) {
callback(t('siteNumCannotLtOne'))
verify = false
break
}
if (Test.empty(item.month)) {
callback(t('siteMonthPlaceholder'))
verify = false
break
}
if (item.month < 0) {
callback(t('siteMonthCannotLtOne'))
verify = false
break
}
}
if (verify) callback()
}
if (item.num < 1) {
callback(t('siteNumCannotLtOne'))
verify = false
break
}
]
}
if (Test.empty(item.month)) {
callback(t('siteMonthPlaceholder'))
verify = false
break
}
if (item.month < 0) {
callback(t('siteMonthCannotLtOne'))
verify = false
break
}
}
if (verify) callback()
}
}
]
}
})
getSiteGroupAll().then(({ data }) => {
const list: any = {}
data.forEach((item: any) => {
list[item.group_id] = item
})
siteGroup.value = list
const list: any = {}
data.forEach((item: any) => {
list[item.group_id] = item
})
siteGroup.value = list
})
const setFormData = (uid: number = 0) => {
if (uid) {
getUserInfo(uid).then(({ data }) => {
formData.value.uid = data.uid
formData.value.username = data.username
formData.value.real_name = data.real_name
formData.value.head_img = data.head_img
loading.value = false
showDialog.value = true
})
} else {
formData.value = {
uid: 0,
username: '',
password: '',
head_img: '',
real_name: '',
confirm_password: '',
create_site_limit: [],
group_ids: []
}
loading.value = false
showDialog.value = true
if (uid) {
getUserInfo(uid).then(({ data }) => {
formData.value.uid = data.uid
formData.value.username = data.username
formData.value.mobile = data.mobile
formData.value.real_name = data.real_name
formData.value.head_img = data.head_img
loading.value = false
showDialog.value = true
})
} else {
formData.value = {
uid: 0,
username: '',
password: '',
head_img: '',
mobile: '',
real_name: '',
confirm_password: '',
create_site_limit: [],
group_ids: []
}
loading.value = false
showDialog.value = true
}
}
const emits = defineEmits(['complete'])
const groupSelect = (groupIds: number[]) => {
const list:any = []
groupIds.forEach(item => {
list.push({
group_id: item,
num: 1,
month: 1
})
const list:any = []
groupIds.forEach(item => {
list.push({
group_id: item,
num: 1,
month: 1
})
formData.value.create_site_limit = list
})
formData.value.create_site_limit = list
}
/**
@ -213,22 +233,22 @@ const groupSelect = (groupIds: number[]) => {
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
if (loading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const save = formData.value.uid ? editUser : addUser
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const save = formData.value.uid ? editUser : addUser
save(formData.value).then(() => {
loading.value = false
showDialog.value = false
emits('complete')
}).catch(() => {
loading.value = false
})
}
})
save(formData.value).then(() => {
loading.value = false
showDialog.value = false
emits('complete')
}).catch(() => {
loading.value = false
})
}
})
}
const realnameInput = ref(true)
@ -238,23 +258,23 @@ const confirmPasswordInput = ref(true)
const passwordType = ref('password')
const togglePasswordVisibility = () => {
passwordType.value = passwordType.value === 'password' ? 'text' : 'password'
passwordType.value = passwordType.value === 'password' ? 'text' : 'password'
}
const confirmPasswordType = ref('password')
const toggleConfirmPasswordVisibility = () => {
confirmPasswordType.value = confirmPasswordType.value === 'password' ? 'text' : 'password'
confirmPasswordType.value = confirmPasswordType.value === 'password' ? 'text' : 'password'
}
defineExpose({
showDialog,
setFormData
showDialog,
setFormData
})
</script>
<style lang="scss" scoped>
.displayPass {
::v-deep .el-input__inner{
:deep(.el-input__inner){
-webkit-text-security: disc !important;
}
}

View File

@ -1,98 +1,99 @@
<template>
<!--站点用户-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<!--站点用户-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
<div>
<el-button type="primary" class="w-[100px]" @click="userEditRef.setFormData()">{{ t('addUser') }}</el-button>
</div>
</div>
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
<div>
<el-button type="primary" class="w-[100px]" @click="userEditRef.setFormData()">{{ t('addUser') }}</el-button>
</div>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef" class="search-form">
<el-form-item prop="username">
<el-input v-model.trim="userTableData.searchParam.username" :placeholder="t('userNamePlaceholder')" />
</el-form-item>
<!-- <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="userTableData.searchParam.create_time" type="datetimerange"
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef" class="search-form">
<el-form-item prop="username">
<el-input v-model.trim="userTableData.searchParam.username" :placeholder="t('userNamePlaceholder')" />
</el-form-item>
<!-- <el-form-item :label="t('createTime')" prop="create_time">
<el-date-picker v-model="userTableData.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 prop="last_time">
<el-date-picker v-model="userTableData.searchParam.last_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 prop="last_time">
<el-date-picker v-model="userTableData.searchParam.last_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="loadUserList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadUserList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div>
<el-table :data="userTableData.data" size="large" v-loading="userTableData.loading">
<template #empty>
<span>{{ !userTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column :label="t('headImg')" width="100" align="left">
<template #default="{ row }">
<div class="w-[54px] h-[54px] flex items-center justify-center">
<img v-if="row.head_img" :src="img(row.head_img)" class="w-[54px] rounded-full" />
<img v-else src="@/app/assets/images/member_head.png" class="w-[54px] rounded-full" />
</div>
</template>
</el-table-column>
<el-table-column prop="username" :label="t('accountNumber')" min-width="120" show-overflow-tooltip />
<el-table-column prop="real_name" :label="t('userRealName')" min-width="120" show-overflow-tooltip />
<el-table-column prop="site_num" :label="t('siteNum')" min-width="120" show-overflow-tooltip align="center" />
<!-- <el-table-column prop="create_time" :label="t('createTime')" min-width="180" align="center">
<template #default="{ row }">
{{ row.create_time || '' }}
</template>
</el-table-column> -->
<el-table-column prop="last_time" :label="t('lastLoginTime')" min-width="180" align="center">
<template #default="{ row }">
{{ row.last_time || '' }}
</template>
</el-table-column>
<el-table-column :label="t('lastLoginIP')" min-width="180" align="center">
<template #default="{ row }">
{{ row.last_ip || '' }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right" width="180">
<template #default="{ row }">
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
<template v-if="!row.is_super_admin">
<el-button type="primary" link @click="editEvent(row.uid)" >{{ t('edit') }}</el-button>
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
</template>
<!-- <div class="manage-option text-right ">
<template v-if="!row.is_super_admin">
<el-button type="primary" link @click="editEvent(row.uid)" >{{ t('edit') }}</el-button>
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
</template>
</div> -->
</template>
</el-table-column>
</el-table>
<div>
<el-table :data="userTableData.data" size="large" v-loading="userTableData.loading">
<template #empty>
<span>{{ !userTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column :label="t('headImg')" width="100" align="left">
<template #default="{ row }">
<div class="w-[54px] h-[54px] flex items-center justify-center">
<img v-if="row.head_img" :src="img(row.head_img)" class="w-[54px] rounded-full" />
<img v-else src="@/app/assets/images/member_head.png" class="w-[54px] rounded-full" />
</div>
</template>
</el-table-column>
<el-table-column prop="username" :label="t('accountNumber')" min-width="120" show-overflow-tooltip />
<el-table-column prop="mobile" :label="t('手机号')" min-width="120" show-overflow-tooltip />
<el-table-column prop="real_name" :label="t('userRealName')" min-width="120" show-overflow-tooltip />
<el-table-column prop="site_num" :label="t('siteNum')" min-width="120" show-overflow-tooltip align="center" />
<!-- <el-table-column prop="create_time" :label="t('createTime')" min-width="180" align="center">
<template #default="{ row }">
{{ row.create_time || '' }}
</template>
</el-table-column> -->
<el-table-column prop="last_time" :label="t('lastLoginTime')" min-width="180" align="center">
<template #default="{ row }">
{{ row.last_time || '' }}
</template>
</el-table-column>
<el-table-column :label="t('lastLoginIP')" min-width="180" align="center">
<template #default="{ row }">
{{ row.last_ip || '' }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right" width="180">
<template #default="{ row }">
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
<template v-if="!row.is_super_admin">
<el-button type="primary" link @click="editEvent(row.uid)" >{{ t('edit') }}</el-button>
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
</template>
<!-- <div class="manage-option text-right ">
<template v-if="!row.is_super_admin">
<el-button type="primary" link @click="editEvent(row.uid)" >{{ t('edit') }}</el-button>
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
</template>
</div> -->
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="userTableData.page" v-model:page-size="userTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="userTableData.total"
@size-change="loadUserList()" @current-change="loadUserList" />
</div>
</div>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="userTableData.page" v-model:page-size="userTableData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="userTableData.total"
@size-change="loadUserList()" @current-change="loadUserList" />
</div>
</div>
</el-card>
</el-card>
<user-edit ref="userEditRef" @complete="loadUserList()"/>
</div>
<user-edit ref="userEditRef" @complete="loadUserList()"/>
</div>
</template>
<script lang="ts" setup>
@ -111,47 +112,47 @@ const pageName = route.meta.title
const userEditRef = ref(null)
const userTableData = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
username: '',
site_name: '',
// create_time: [],
last_time: []
}
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
username: '',
site_name: '',
// create_time: [],
last_time: []
}
})
const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
if (!formEl) return
formEl.resetFields()
loadUserList()
formEl.resetFields()
loadUserList()
}
/**
* 获取用户列表
*/
const loadUserList = (page: number = 1) => {
userTableData.loading = true
userTableData.page = page
userTableData.loading = true
userTableData.page = page
getUserList({
page: userTableData.page,
limit: userTableData.limit,
...userTableData.searchParam
getUserList({
page: userTableData.page,
limit: userTableData.limit,
...userTableData.searchParam
}).then(res => {
userTableData.loading = false
userTableData.data = res.data.data
userTableData.total = res.data.total
}).catch(() => {
userTableData.loading = false
})
}).then(res => {
userTableData.loading = false
userTableData.data = res.data.data
userTableData.total = res.data.total
}).catch(() => {
userTableData.loading = false
})
}
loadUserList()
@ -159,7 +160,7 @@ loadUserList()
* 查看详情
*/
const detailEvent = (uid: number, tab: string = '') => {
router.push({ path: '/admin/site/user_info', query: { uid, tab } })
router.push({ path: '/admin/site/user_info', query: { uid, tab } })
}
/**
@ -167,69 +168,69 @@ const detailEvent = (uid: number, tab: string = '') => {
* @param uid
*/
const editEvent = (uid: number) => {
userEditRef.value.setFormData(uid)
userEditRef.value.setFormData(uid)
}
/**
* 删除用户
*/
const deleteEvent = (uid: number) => {
ElMessageBox.confirm(t('userDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteUser(uid).then(res => {
loadUserList()
}).catch(() => {
})
ElMessageBox.confirm(t('userDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteUser(uid).then(res => {
loadUserList()
}).catch(() => {
})
})
}
</script>
<style lang="scss" scoped>
:deep(.el-table tr td) {
height: 100px !important;
height: 100px !important;
}
:deep(.el-input__wrapper){
box-shadow: none !important;
border-radius: 4px !important;
border: 1px solid #D1D5DB !important;
height: 32px !important;
box-shadow: none !important;
border-radius: 4px !important;
border: 1px solid #D1D5DB !important;
height: 32px !important;
}
:deep(.el-select__wrapper){
box-shadow: none !important;
border-radius: 4px !important;
border: 1px solid #D1D5DB !important;
height: 32px !important;
box-shadow: none !important;
border-radius: 4px !important;
border: 1px solid #D1D5DB !important;
height: 32px !important;
}
:deep(.el-button){
border-radius: 4px !important;
border-radius: 4px !important;
}
/* 设置 el-select 的 placeholder 颜色 */
:deep(.search-form .el-select__placeholder.is-transparent) {
color: #C4C7DA;
font-size: 12px;
color: #C4C7DA;
font-size: 12px;
}
/* 设置 el-select 选中后的颜色 */
:deep(.search-form .el-select__placeholder) {
color: #4F516D;
font-size: 12px;
color: #4F516D;
font-size: 12px;
}
/* 设置 el-input 的 placeholder 颜色 */
:deep(.search-form .el-input__inner::placeholder) {
color: #C4C7DA;
font-size: 12px;
color: #C4C7DA;
font-size: 12px;
}
/* 设置 el-input 输入内容后的颜色 */
:deep(.search-form .el-input__inner) {
color: #4F516D;
font-size: 12px;
color: #4F516D;
font-size: 12px;
}
/* 设置 el-date-picker 的 placeholder 颜色 */
@ -245,43 +246,43 @@ const deleteEvent = (uid: number) => {
}
.manage-option {
line-height: 50px;
padding: 0 30px;
position: absolute;
right: 0;
width: 100vw;
bottom: 0;
background-color: #f4f6f9;
transition: all .3s;
box-shadow: 0 4px 4px rgba(220, 220, 220, .3);
opacity: 0;
z-index: 999;
white-space: nowrap;
line-height: 50px;
padding: 0 30px;
position: absolute;
right: 0;
width: 100vw;
bottom: 0;
background-color: #f4f6f9;
transition: all .3s;
box-shadow: 0 4px 4px rgba(220, 220, 220, .3);
opacity: 0;
z-index: 999;
white-space: nowrap;
}
/* 当行被 hover 时 */
:deep(.el-table__row:hover) {
position: relative;
z-index: 10;
position: relative;
z-index: 10;
}
/* 当行被 hover 时,其下的单元格允许溢出 */
:deep(.el-table__row:hover .el-table__cell) {
overflow: visible;
overflow: visible;
}
/* 当行被 hover 时,显示 manage-option 并调整其位置 */
:deep(.el-table__row:hover .manage-option) {
opacity: 1;
bottom: -51px;
opacity: 1;
bottom: -51px;
}
:deep(.el-table__fixed-body-wrapper:hover),
:deep(.el-table__fixed-body-wrapper .el-table__row:hover) {
z-index: 10;
:deep(.el-table__fixed-body-wrapper:hover),
:deep(.el-table__fixed-body-wrapper .el-table__row:hover) {
z-index: 10;
}
:deep(.el-table__fixed-body-wrapper .el-table__row:hover .el-table__cell) {
overflow: visible;
overflow: visible;
}
</style>

View File

@ -1,127 +1,135 @@
<template>
<!--用户详情-->
<div class="main-container" v-loading="loading">
<!--用户详情-->
<div class="main-container" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('userInfo') }}</h3>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('userInfo') }}</h3>
<el-row :gutter="20" class="mt-[20px] mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('uid') }}</span>
<span class="text-[14px] text-[#666666]">
<el-row :gutter="20" class="mt-[20px] mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('uid') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.uid }}
</span>
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('username') }}</span>
<span class="text-[14px] text-[#666666]">
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('username') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.username }}
</span>
</el-col>
</el-row>
<el-row :gutter="20" class="mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('realname') }}</span>
<span class="text-[14px] text-[#666666]">
</el-col>
</el-row>
<el-row :gutter="20" class="mb-[20px]">
<el-col :span="6" >
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('realname') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.real_name || '--' }}
</span>
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('addTime') }}</span>
<span class="text-[14px] text-[#666666]">
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('手机号') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.mobile || '--' }}
</span>
</el-col>
</el-row>
<el-row :gutter="20" class="mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('addTime') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.create_time }}
</span>
</el-col>
</el-row>
<el-row :gutter="20" class="mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('lastLoginTime') }}</span>
<span class="text-[14px] text-[#666666]">
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('lastLoginTime') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.last_time || '' }}
</span>
</el-col>
<el-col :span="6" :offset="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('lastLoginIP') }}</span>
<span class="text-[14px] text-[#666666]">
</el-col>
</el-row>
<el-row :gutter="20" class="mb-[20px]">
<el-col :span="6">
<span class="text-[14px] w-[130px] text-right mr-[20px]">{{ t('lastLoginIP') }}</span>
<span class="text-[14px] text-[#666666]">
{{ detail.last_ip || '' }}
</span>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<el-tabs v-model="currTab">
<el-tab-pane :label="t('siteInfo')" name="siteInfo">
<el-table :data="detail.roles" size="large">
<el-table-column prop="site_id" :label="t('siteId')" width="100px" />
<el-table-column prop="site_name" :label="t('siteName')" />
<el-table-column prop="is_admin" :label="t('isAdmin')" min-width="180" align="center">
<template #default="{ row }">
{{ row.is_admin ? t('yes') : t('no') }}
</template>
</el-table-column>
<el-table-column :label="t('status')" min-width="80" align="center">
<template #default="{ row }">
<template v-if="row.site_status_name">
<el-tag class="ml-2" type="success" v-if="row.site_status == 1">{{ row.site_status_name }}</el-tag>
<el-tag class="ml-2" type="error" v-else-if="row.site_status == 3">
{{ row.site_status_name }}
</el-tag>
<el-tag class="ml-2" type="error" v-else>
{{ row.site_status_name }}
</el-tag>
</template>
<el-tag class="ml-2" type="error" v-else>
{{ t('siteEmpty') }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="expire_time" :label="t('expireTime')" />
<el-table-column :label="t('operation')" align="right" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="siteInfo(row)" v-if="row.site_status_name">{{ t('info') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane :label="t('userCreateSiteLimit')" name="userCreateSiteLimit" v-if="!detail.is_super_admin">
<div class="flex justify-end mb-[16px]">
<el-button type="primary" @click="createSiteLimitRef.setFormData()">{{ t('addSserCreateSiteLimit') }}</el-button>
</div>
<el-table :data="userCreateSiteLimit" size="large">
<el-table-column :label="t('siteGroup')">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].group_name : '' }}
</template>
</el-table-column>
<el-table-column :label="t('createdSiteNum')">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].site_num : 0 }}
</template>
</el-table-column>
<el-table-column prop="num" :label="t('createSiteNum')" align="center"/>
<el-table-column prop="month" :label="t('createSiteTimeLimit')" align="center">
<template #default="{ row }">
{{ row.month }}{{ t('month') }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="createSiteLimitRef.setFormData(row.id)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteCreateSiteTimeLimit(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<el-tabs v-model="currTab">
<el-tab-pane :label="t('siteInfo')" name="siteInfo">
<el-table :data="detail.roles" size="large">
<el-table-column prop="site_id" :label="t('siteId')" width="100px" />
<el-table-column prop="site_name" :label="t('siteName')" />
<el-table-column prop="is_admin" :label="t('isAdmin')" min-width="180" align="center">
<template #default="{ row }">
{{ row.is_admin ? t('yes') : t('no') }}
</template>
</el-table-column>
<el-table-column :label="t('status')" min-width="80" align="center">
<template #default="{ row }">
<template v-if="row.site_status_name">
<el-tag class="ml-2" type="success" v-if="row.site_status == 1">{{ row.site_status_name }}</el-tag>
<el-tag class="ml-2" type="error" v-else-if="row.site_status == 3">
{{ row.site_status_name }}
</el-tag>
<el-tag class="ml-2" type="error" v-else>
{{ row.site_status_name }}
</el-tag>
</template>
<el-tag class="ml-2" type="error" v-else>
{{ t('siteEmpty') }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="expire_time" :label="t('expireTime')" />
<el-table-column :label="t('operation')" align="right" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="siteInfo(row)" v-if="row.site_status_name">{{ t('info') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane :label="t('userCreateSiteLimit')" name="userCreateSiteLimit" v-if="!detail.is_super_admin">
<div class="flex justify-end mb-[16px]">
<el-button type="primary" @click="createSiteLimitRef.setFormData()">{{ t('addSserCreateSiteLimit') }}</el-button>
</div>
<el-table :data="userCreateSiteLimit" size="large">
<el-table-column :label="t('siteGroup')">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].group_name : '' }}
</template>
</el-table-column>
<el-table-column :label="t('createdSiteNum')">
<template #default="{ row }">
{{ siteGroup[row.group_id] ? siteGroup[row.group_id].site_num : 0 }}
</template>
</el-table-column>
<el-table-column prop="num" :label="t('createSiteNum')" align="center"/>
<el-table-column prop="month" :label="t('createSiteTimeLimit')" align="center">
<template #default="{ row }">
{{ row.month }}{{ t('month') }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" align="right" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="createSiteLimitRef.setFormData(row.id)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteCreateSiteTimeLimit(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-card>
<create-site-limit ref="createSiteLimitRef" :site-group="siteGroup" :uid="uid" @complete="getUserCreateSiteLimitFn"/>
</div>
<create-site-limit ref="createSiteLimitRef" :site-group="siteGroup" :uid="uid" @complete="getUserCreateSiteLimitFn"/>
</div>
</template>
<script lang="ts" setup>
@ -139,7 +147,7 @@ const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/admin/site/user')
router.push('/admin/site/user')
}
const uid: number = parseInt(route.query.uid || 0)
const loading = ref(true)
@ -150,22 +158,22 @@ const userCreateSiteLimit = ref([])
const createSiteLimitRef = ref(null)
getUserInfo(uid).then(({ data }) => {
detail.value = data
loading.value = false
detail.value = data
loading.value = false
}).catch()
getUserSiteGroupAll({ uid }).then(({ data }) => {
const list: any = {}
data.forEach((item: any) => {
list[item.group_id] = item
})
siteGroup.value = list
const list: any = {}
data.forEach((item: any) => {
list[item.group_id] = item
})
siteGroup.value = list
})
const getUserCreateSiteLimitFn = () => {
getUserCreateSiteLimit(uid).then(({ data }) => {
userCreateSiteLimit.value = data
})
getUserCreateSiteLimit(uid).then(({ data }) => {
userCreateSiteLimit.value = data
})
}
getUserCreateSiteLimitFn()
@ -174,22 +182,22 @@ getUserCreateSiteLimitFn()
* @param data
*/
const siteInfo = (data: any) => {
router.push({ path: '/admin/site/info', query: { id: data.site_id } })
router.push({ path: '/admin/site/info', query: { id: data.site_id } })
}
const deleteCreateSiteTimeLimit = (id: number) => {
ElMessageBox.confirm(t('createSiteTimeLimitDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
delUserCreateSiteLimit(id).then(() => {
getUserCreateSiteLimitFn()
}).catch(() => {
})
ElMessageBox.confirm(t('createSiteTimeLimitDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
delUserCreateSiteLimit(id).then(() => {
getUserCreateSiteLimitFn()
}).catch(() => {
})
})
}
</script>

View File

@ -858,7 +858,7 @@ const batchDelete = () => {
background-color: var(--el-table-header-bg-color);
}
::v-deep .number-of-steps {
:deep(.number-of-steps) {
.el-step__line {
margin: 0 25px;
background: #dddddd;

View File

@ -53,7 +53,7 @@
<el-timeline-item :hollow="true">
<div class="text-[16px] text-[#1D1F3A]">编译uniapp代码</div>
<div class="p-[10px] bg-[#F9F9FB] mt-[10px] text-[#4F516D] text-[14px] w-[1085px] border-[#F1F1F8] border-solid border-[1px] h-[40px] flex items-center rounded-[4px]">
<span>云编会将uniapp端的vue代码编译为对应的html文件同时将生成的代码下载到系统 niucloud下的</span>
<span>云编会将uniapp端的vue代码编译为对应的html文件同时将生成的代码下载到系统 niucloud下的</span>
<span class="text-[#F09000] mx-[3px] font-bold">public/wap</span>
<span>目录中这样手机端网页的访问路径将变为</span>
<span class="text-primary ml-[3px] font-500"> https:///wap</span>
@ -62,7 +62,7 @@
<el-timeline-item :hollow="true">
<div class="text-[16px] text-[#1D1F3A]">编译web代码</div>
<div class="p-[10px] bg-[#F9F9FB] mt-[10px] text-[#4F516D] text-[14px] w-[1085px] border-[#F1F1F8] border-solid border-[1px] h-[40px] flex items-center rounded-[4px]">
<span>云编会将web端的vue代码编译为对应的html文件同时将生成的代码下载到系统 niucloud下的</span>
<span>云编会将web端的vue代码编译为对应的html文件同时将生成的代码下载到系统 niucloud下的</span>
<span class="text-[#F09000] mx-[3px] font-bold">public/web</span>
<span>目录中这样电脑端网页的访问路径将变为</span>
<span class="text-primary ml-[3px] font-500"> https:///web</span>

View File

@ -91,6 +91,17 @@ const handleEditorReady = (editor) => {
emit('handleBlur', editor.getContent()) //
})
//
editor.addListener('fullscreenchanged', (type, fullscreen) =>{
const editorDom = editor.ui.getDom()
if (fullscreen) {
editorDom.classList.add('edui-fullscreen')
} else {
editorDom.classList.remove('edui-fullscreen')
}
console.log('全屏切换', fullscreen)
})
//
const originalCount = editor.getContentLength; //

View File

@ -103,7 +103,7 @@
"405": "请求方法未允许",
"408": "请求超时",
"409": "请求跨域",
"500": "服务器端出错,错误原因:",
"500": "服务器内部错误",
"501": "网络未实现",
"502": "网络错误",
"503": "服务不可用",

View File

@ -42,4 +42,8 @@ const tabbarStore = useTabbarStore()
.bg-page {
background-color: #F7F7FA;
}
:deep(.inter .el-breadcrumb__inner){
font-weight: inherit !important;
color: var(--el-text-color-regular) !important;
}
</style>

View File

@ -38,4 +38,9 @@ const appStore = useAppStore()
const tabbarStore = useTabbarStore()
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
:deep(.inter .el-breadcrumb__inner){
font-weight: inherit !important;
color: var(--el-text-color-regular) !important;
}
</style>

View File

@ -1,18 +1,18 @@
<template>
<template v-if="meta.show">
<el-sub-menu v-if="routes.children" :index="String(routes.name)">
<el-sub-menu v-if="hasVisibleChild" :index="String(routes.name)">
<template #title>
<span :class="['ml-[10px]']">{{ meta.title }}</span>
</template>
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" />
</el-sub-menu>
<template v-else>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<template #title>
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
</template>
</el-menu-item>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-else>
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-else>
<template #title>
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
</template>
@ -29,6 +29,7 @@ import { computed } from 'vue'
import { img } from '@/utils/common'
import menuItem from './menu-item.vue'
import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage'
const router = useRouter()
const props = defineProps({
@ -41,12 +42,37 @@ const userStore = useUserStore()
const siteInfo = userStore.siteInfo
const meta = computed(() => props.routes.meta)
const hasVisibleChild = computed(() => {
if (!props.routes.children || !Array.isArray(props.routes.children)) {
return false
}
return props.routes.children.some(child => child.meta?.show === 1)
})
const addons = computed(() => {
const addons:Record<string, any> = {}
siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
siteInfo?.site_addons.forEach((item: any) => { addons[item.key] = item })
return addons
})
//
const handleJump = (routeName: string) => {
//
const specialMenuNames = storage.get('specialMenuNames')
const specialMenuNamesLevel1 = storage.get('specialMenuNamesLevel1')
const isInSpecialMenus = specialMenuNames.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
if (specialMenuNamesLevel1.includes(routeName)) {
routeName = 'addon_list'
}
//
router.push({ name: routeName })
}
</script>

View File

@ -17,7 +17,7 @@
<el-scrollbar class="h-[calc( 100vh - 64px )]">
<el-menu :default-active="oneMenuActive" :router="true" class="aside-menu" :unique-opened="true">
<template v-for="(item, index) in oneMenuData" :key="index">
<el-menu-item :index="item.original_name" @click="router.push({ name: item.name })" v-if="item.meta.show">
<el-menu-item :index="item.original_name" @click="handleJump(item.name)" v-if="item.meta.show">
<div v-if="item.meta.icon" class="w-[16px] h-[16px] relative flex justify-center">
<icon :name="item.meta.icon" class="absolute top-[50%] -translate-y-[50%]" />
</div>
@ -49,9 +49,10 @@ import { useRoute, useRouter } from 'vue-router'
import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import menuItem from './menu-item.vue'
import { getShowApp, getShowMarketing } from '@/app/api/site'
import { getShowApp,getShowSpecialMenu} from '@/app/api/site'
import { img } from '@/utils/common'
import { findFirstValidRoute } from '@/router/routers'
import { findFirstValidRoute,formatRouters } from '@/router/routers'
import storage from '@/utils/storage'
const systemStore = useSystemStore()
const userStore = useUserStore()
@ -136,87 +137,222 @@ const oneMenuActive = ref(route.matched[1].name)
const appList = ref(null)
const marketingList = ref(null)
// const loading = ref(true);
const getAppList = async () => {
const res = await getShowApp()
appList.value = res.data
// loading.value = false;
// key
storage.set({ key: 'defaultAppList', data: appList.value })
}
const getMarketingList = async () => {
const res = await getShowMarketing()
marketingList.value = res.data
const specialList = ref<Record<string, any>[]>([])
const getShowSpecialMenuList = async () => {
const res = await getShowSpecialMenu()
// specialList.value = formatRouters(res.data.list)
specialList.value = res.data.list
//
storage.set({ key: 'specialAppList', data: specialList.value })
}
onMounted(async () => {
await getAppList() //
await getMarketingList()
const specialMenuNames = ref<string[]>([])
const specialMenuNamesLevel1 = ref<string[]>([])
onMounted(() => {
getAppList()
getShowSpecialMenuList()
const processedSpecialMenus = handleSpecialMenus();
specialMenuNamesLevel1.value = collectSpecialMenuNamesLevel1(processedSpecialMenus)
specialMenuNames.value = collectSpecialMenuNames(processedSpecialMenus)
storage.set({ key: 'specialMenuNames', data: specialMenuNames.value })
storage.set({ key: 'specialMenuNamesLevel1', data: specialMenuNamesLevel1.value })
})
watchEffect(() => {
// if (!appList.value || loading.value) return; //
const addonKeys = appList.value?.addon?.list?.map(item => item.key) ?? []
const toolKeys = appList.value?.tool?.list?.map(item => item.key) ?? []
const allKeys = [...addonKeys, ...toolKeys]
const marketingKeys = marketingList.value?.marketing?.list?.map(item => item.key) ?? []
const matchedName = route.matched[1]?.name
if (allKeys.includes(matchedName)) {
oneMenuActive.value = 'addon'
twoMenuData.value = route.matched[1]?.children ?? []
} else if (marketingKeys.includes(matchedName)) {
oneMenuActive.value = 'active'
twoMenuData.value = route.matched[1]?.children ?? []
} else if (route.meta.attr !== '') {
oneMenuActive.value = route.matched[2]?.name
twoMenuData.value = route.matched[1]?.children ?? []
} else {
//
if (siteInfo?.apps.length > 1) {
twoMenuData.value = route.matched[1]?.children
oneMenuActive.value = route.matched[1]?.name
} else {
//
const oneMenu = route.matched[1]
if (oneMenu.meta.addon === '') {
oneMenuActive.value = route.matched[1]?.name
twoMenuData.value = route.matched[1]?.children ?? []
} else {
if (oneMenu.meta.addon === siteInfo?.apps[0]?.key) {
oneMenuActive.value = route.matched[2]?.name
twoMenuData.value = route.matched[2]?.children ?? []
} else {
oneMenuActive.value = route.matched[1]?.name
twoMenuData.value = route.matched[1]?.children ?? []
}
}
}
}
})
// watch(route, () => {
// if (route.meta.attr != '') {
// oneMenuActive.value = route.matched[2].name
// twoMenuData.value = route.matched[1].children ?? []
// onMounted(async () => {
// await getAppList() //
// })
// watchEffect(() => {
// // if (!appList.value || loading.value) return; //
// const addonKeys = appList.value?.addon?.list?.map(item => item.key) ?? []
// const toolKeys = appList.value?.tool?.list?.map(item => item.key) ?? []
// const allKeys = [...addonKeys, ...toolKeys]
// const marketingKeys = marketingList.value?.marketing?.list?.map(item => item.key) ?? []
// const matchedName = route.matched[1]?.name
// if (allKeys.includes(matchedName)) {
// oneMenuActive.value = 'addon'
// twoMenuData.value = route.matched[1]?.children ?? []
// } else if (marketingKeys.includes(matchedName)) {
// oneMenuActive.value = 'active'
// twoMenuData.value = route.matched[1]?.children ?? []
// } else if (route.meta.attr !== '') {
// oneMenuActive.value = route.matched[2]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// } else {
// //
// if (siteInfo?.apps.length > 1) {
// twoMenuData.value = route.matched[1].children
// oneMenuActive.value = route.matched[1].name
// twoMenuData.value = route.matched[1]?.children
// oneMenuActive.value = route.matched[1]?.name
// } else {
// //
// const oneMenu = route.matched[1]
// if (oneMenu.meta.addon == '') {
// oneMenuActive.value = route.matched[1].name
// twoMenuData.value = route.matched[1].children ?? []
// if (oneMenu.meta.addon === '') {
// oneMenuActive.value = route.matched[1]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// } else {
// if (oneMenu.meta.addon == siteInfo?.apps[0].key) {
// oneMenuActive.value = route.matched[2].name
// twoMenuData.value = route.matched[2].children ?? []
// if (oneMenu.meta.addon === siteInfo?.apps[0]?.key) {
// oneMenuActive.value = route.matched[2]?.name
// twoMenuData.value = route.matched[2]?.children ?? []
// } else {
// oneMenuActive.value = route.matched[1].name
// twoMenuData.value = route.matched[1].children ?? []
// oneMenuActive.value = route.matched[1]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// }
// }
// }
// }
// }, { immediate: true })
// })
// addonKeys key
const getAddonAllKeys = (addonData) => {
if (!addonData || typeof addonData !== 'object') return [];
const allKeys = [];
Object.values(addonData).forEach(category => {
if (Array.isArray(category.list)) {
category.list.forEach(item => {
if (item.key) allKeys.push(item.key);
});
}
});
return allKeys;
};
// specialMenusKeys show
const handleSpecialMenus = () => {
const specialMenusKeys = storage.get('specialAppList')
if (Array.isArray(specialMenusKeys) && specialMenusKeys.length) {
const processedSpecialMenus = JSON.parse(JSON.stringify(specialMenusKeys));
const activeAppKey = storage.get('activeAppKey');
// name
processedSpecialMenus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
const traverseChildren = (children) => {
children.forEach(child => {
if (child && child.is_show !== undefined) {
child.is_show = (child.menu_key === activeAppKey) ? 1 : 0;
}
});
};
traverseChildren(menu.children);
}
});
// children
const filteredSpecialMenus = processedSpecialMenus.filter(menu => {
return menu.children && menu.children.length > 0;
});
return formatRouters(filteredSpecialMenus);
}
return [];
};
// name
const collectSpecialMenuNames = (menus: any[]) => {
const names: string[] = []
const traverse = (children: any[]) => {
children.forEach(child => {
if (child.name) {
names.push(child.name)
}
//
if (child.children && Array.isArray(child.children)) {
traverse(child.children)
}
})
}
menus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
traverse(menu.children)
}
})
return names
}
// name
const collectSpecialMenuNamesLevel1 = (menus: any[]) =>{
const names: string[] = []
menus.forEach(menu => {
if (menu.name) {
names.push(menu.name)
}
})
return names
}
//
const handleJump = (routeName: string) => {
//
const isInSpecialMenus = specialMenuNames.value.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
router.push({ name: routeName })
}
watch(route, () => {
if (route.meta.attr != '') {
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
} else {
//
if (siteInfo?.apps.length > 1) {
twoMenuData.value = route.matched[1].children
oneMenuActive.value = route.matched[1].name
} else {
//
const oneMenu = route.matched[1]
if (oneMenu.meta.addon == '') {
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
} else {
if (oneMenu.meta.addon == siteInfo?.apps[0].key) {
oneMenuActive.value = route.matched[2].name
twoMenuData.value = route.matched[2].children ?? []
} else {
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
}
}
}
}
const addonKeys = storage.get('defaultAppList')
const addonAllKeys = getAddonAllKeys(addonKeys);
twoMenuData.value = twoMenuData.value.filter((child) =>{
return !child.name || !addonAllKeys.includes(child.name);
});
if(oneMenuActive.value == 'addon'){
// twoMenuData addon_list
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length) {
// addon_list twoMenuData
const addonListIndex = twoMenuData.value.findIndex(
(item) => item.name === 'addon_list'
);
if (addonListIndex !== -1) {
// addon_list
twoMenuData.value.splice(
addonListIndex + 1,
0,
...processedSpecialMenus
);
} else {
// addon_list twoMenuData
twoMenuData.value.push(...processedSpecialMenus);
}
}
}
}, { immediate: true })
</script>
<style lang="scss">
@ -309,6 +445,27 @@ watchEffect(() => {
.el-menu-item{
padding-left: 20px !important;
}
.el-sub-menu{
.el-sub-menu__title{
margin: 0 8px 2px;
height: 40px;
padding-left: 18px;
border-radius: 2px;
span{
height: 40px;
display: flex;
align-items: center;
font-size: 14px;
}
&:hover{
background-color: transparent;
color: var(--el-color-primary);
}
}
.el-menu-item{
padding-left: 30px !important;
}
}
}
}
}

View File

@ -1,6 +1,6 @@
<template>
<template v-if="meta.show">
<el-sub-menu v-if="routes.children" :index="String(routes.name)">
<el-sub-menu v-if="hasVisibleChild" :index="String(routes.name)">
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -15,7 +15,7 @@
</template>
</el-sub-menu>
<template v-else>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -23,7 +23,7 @@
<span class="ml-[10px]">{{ meta.title }}</span>
</template>
</el-menu-item>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-else>
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-else>
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -39,11 +39,12 @@
<script lang="ts" setup>
import { useRouter, useRoute } from 'vue-router'
import { ref, computed, watch, onMounted } from 'vue'
import { ref, computed, watch , onMounted, onUnmounted} from 'vue'
import menuItem from './menu-item.vue'
import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage'
import { findFirstValidRoute ,formatRouters} from '@/router/routers'
const router = useRouter()
const route = useRoute()
@ -62,6 +63,9 @@ const props = defineProps({
const systemStore = useSystemStore()
const meta = computed(() => props.routes.meta)
// name
const specialMenuNames = ref<string[]>([])
const specialMenuNamesLevel1 = ref<string[]>([])
const addons = computed(() => {
const addons:Record<string, any> = {}
userStore.siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
@ -72,7 +76,12 @@ const addons = computed(() => {
const systemAddonKeys = computed(() => {
return userStore.siteInfo?.site_addons.map((item: any) => item.key)
})
const hasVisibleChild = computed(() => {
if (!props.routes.children || !Array.isArray(props.routes.children)) {
return false
}
return props.routes.children.some(child => child.meta?.show === 1)
})
const addonRouters: Record<string, any> = {}
routers.forEach(item => {
item.original_name = item.name
@ -86,8 +95,135 @@ routers.forEach(item => {
const addonsMenus = ref(null)
// name
const collectSpecialMenuNames = (menus: any[]) => {
const names: string[] = []
const traverse = (children: any[]) => {
children.forEach(child => {
if (child.name) {
names.push(child.name)
}
//
if (child.children && Array.isArray(child.children)) {
traverse(child.children)
}
})
}
menus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
traverse(menu.children)
}
})
return names
}
// name
const collectSpecialMenuNamesLevel1 = (menus: any[]) =>{
const names: string[] = []
menus.forEach(menu => {
if (menu.name) {
names.push(menu.name)
}
})
return names
}
// 1. addonKeys key list
const getAddonAllKeys = (addonData) => {
// addonKeys
if (!addonData || typeof addonData !== 'object') return [];
// key
const allKeys = [];
// addonKeys.data marketing_activemarketing_tool
Object.values(addonData).forEach(category => {
// list
if (Array.isArray(category.list)) {
// list keypush allKeys
category.list.forEach(item => {
if (item.key) allKeys.push(item.key);
});
}
});
return allKeys;
};
// specialMenusKeys show
const handleSpecialMenus = () => {
const specialMenusKeys = storage.get('specialAppList')
if (Array.isArray(specialMenusKeys) && specialMenusKeys.length) {
const processedSpecialMenus = JSON.parse(JSON.stringify(specialMenusKeys));
const activeAppKey = storage.get('activeAppKey');
// name
processedSpecialMenus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
const traverseChildren = (children) => {
children.forEach(child => {
if (child && child.is_show !== undefined) {
child.is_show = (child.menu_key === activeAppKey) ? 1 : 0;
}
});
};
traverseChildren(menu.children);
}
});
// children
const filteredSpecialMenus = processedSpecialMenus.filter(menu => {
return menu.children && menu.children.length > 0;
});
return formatRouters(filteredSpecialMenus);
}
return [];
};
//
const handleJump = (routeName: string) => {
//
const isInSpecialMenus = specialMenuNames.value.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
if (specialMenuNamesLevel1.value.includes(routeName)) {
routeName = 'addon_list'
}
//
router.push({ name: routeName })
}
watch(route, () => {
const addonKeys = storage.get('defaultAppList')
// console.log('addonKeys', addonKeys)
if (props.routes.name == 'addon_list') {
const addonAllKeys = getAddonAllKeys(addonKeys);
// 2 children name addonAllKeys
if (props.routes.children) {
props.routes.children = props.routes.children.filter(child => {
// child name name addonAllKeys
return !child.name || !addonAllKeys.includes(child.name);
});
// specialMenusKeys activeAppKey show
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length) {
const newChildren = [...(props.routes.children || [])];
processedSpecialMenus.forEach(special => {
const index = newChildren.findIndex(child => child.name === special.name);
if (index !== -1) {
// show
newChildren[index] = special;
} else {
newChildren.push(special);
}
});
props.routes.children = newChildren;
}
}
if (systemAddonKeys.value.includes(route.meta.addon) && addonRouters[route.meta.addon]) {
addonsMenus.value = addonRouters[route.meta.addon]
} else if (route.meta.attr && addonRouters[route.meta.attr]) {
@ -97,7 +233,7 @@ watch(route, () => {
}
}
const marketingKeys = storage.get('darksideMarketingKeys')
const marketingKeys = storage.get('defaultMarketingKeys')
const matchedName = route.matched[1]?.name
if (props.routes.name == 'marketing_list') {
if (marketingKeys && marketingKeys.includes(matchedName)) {
@ -107,7 +243,42 @@ watch(route, () => {
addonsMenus.value = null
}
}
}, { immediate: true })
// localStorage activeAppKey
onMounted(() => {
const processedSpecialMenus = handleSpecialMenus();
specialMenuNames.value = collectSpecialMenuNames(processedSpecialMenus)
specialMenuNamesLevel1.value = collectSpecialMenuNamesLevel1(processedSpecialMenus)
const handleStorageChange = (event: StorageEvent) => {
if (event.key === 'activeAppKey') {
if (props.routes.name == 'addon_list') {
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length && props.routes.children) {
const newChildren = [...(props.routes.children || [])];
processedSpecialMenus.forEach(special => {
const index = newChildren.findIndex(child => child.name === special.name);
if (index !== -1) {
// show
newChildren[index] = special;
} else {
newChildren.push(special);
}
});
props.routes.children = newChildren;
}
}
}
};
window.addEventListener('storage', handleStorageChange);
//
onUnmounted(() => {
window.removeEventListener('storage', handleStorageChange);
});
});
</script>
<style lang="scss">

View File

@ -30,9 +30,9 @@ import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import menuItem from './menu-item.vue'
import { img } from '@/utils/common'
import { findFirstValidRoute } from '@/router/routers'
import { getShowMarketing } from '@/app/api/site'
import { findFirstValidRoute ,formatRouters} from '@/router/routers'
import storage from '@/utils/storage'
import {getShowApp, getShowSpecialMenu} from '@/app/api/site'
const systemStore = useSystemStore()
const userStore = useUserStore()
@ -46,20 +46,26 @@ const logoUrl = computed(() => {
return userStore.siteInfo.icon ? userStore.siteInfo.icon : systemStore.website.icon
})
const getMarketingList = async () => {
const res = await getShowMarketing()
const marketingList = res.data
const marketingKeys = marketingList?.marketing?.list?.map(item => item.key) ?? []
// menuData.value.forEach((item, index, arr) => {
// if (marketingKeys.includes(item.name)) {
// arr.splice(index, 1)
// }
// })
storage.set({ key: 'darksideMarketingKeys', data: marketingKeys })
const appList = ref<Record<string, any>[]>([])
const getAppList = async () => {
const res = await getShowApp()
appList.value = res.data
storage.set({ key: 'defaultAppList', data: appList.value })
}
const specialList = ref<Record<string, any>[]>([])
const getShowSpecialMenuList = async () => {
const res = await getShowSpecialMenu()
// specialList.value = formatRouters(res.data.list)
specialList.value = res.data.list
storage.set({ key: 'specialAppList', data: specialList.value })
}
onMounted(() => {
getMarketingList()
getAppList()
getShowSpecialMenuList()
})
routers.forEach((item, index) => {

View File

@ -1,6 +1,6 @@
<template>
<template v-if="meta.show">
<el-sub-menu v-if="routes.children" :index="String(routes.name)">
<el-sub-menu v-if="hasVisibleChild" :index="String(routes.name)">
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -15,7 +15,7 @@
</template>
</el-sub-menu>
<template v-else>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -23,7 +23,7 @@
<span class="ml-[10px]">{{ meta.title }}</span>
</template>
</el-menu-item>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-else>
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-else>
<template #title>
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
@ -34,16 +34,16 @@
</template>
<div v-if="routes.is_border" class="!border-0 !border-t-[1px] border-solid mx-[25px] bg-[#f7f7f7] my-[5px]"></div>
</template>
</template>
<script lang="ts" setup>
import { useRouter, useRoute } from 'vue-router'
import { ref, computed, watch } from 'vue'
import { ref, computed, watch , onMounted, onUnmounted} from 'vue'
import menuItem from './menu-item.vue'
import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage'
import { findFirstValidRoute ,formatRouters} from '@/router/routers'
const router = useRouter()
const route = useRoute()
@ -62,8 +62,11 @@ const props = defineProps({
const systemStore = useSystemStore()
const meta = computed(() => props.routes.meta)
// name
const specialMenuNames = ref<string[]>([])
const specialMenuNamesLevel1 = ref<string[]>([])
const addons = computed(() => {
const addons:Record<string, any> = {}
const addons: Record<string, any> = {}
userStore.siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
userStore.siteInfo?.site_addons.forEach((item: any) => { addons[item.key] = item })
return addons
@ -72,7 +75,12 @@ const addons = computed(() => {
const systemAddonKeys = computed(() => {
return userStore.siteInfo?.site_addons.map((item: any) => item.key)
})
const hasVisibleChild = computed(() => {
if (!props.routes.children || !Array.isArray(props.routes.children)) {
return false
}
return props.routes.children.some(child => child.meta?.show === 1)
})
const addonRouters: Record<string, any> = {}
routers.forEach(item => {
item.original_name = item.name
@ -86,8 +94,125 @@ routers.forEach(item => {
const addonsMenus = ref(null)
// name
const collectSpecialMenuNames = (menus: any[]) => {
const names: string[] = []
const traverse = (children: any[]) => {
children.forEach(child => {
if (child.name) {
names.push(child.name)
}
//
if (child.children && Array.isArray(child.children)) {
traverse(child.children)
}
})
}
menus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
traverse(menu.children)
}
})
return names
}
// name
const collectSpecialMenuNamesLevel1 = (menus: any[]) =>{
const names: string[] = []
menus.forEach(menu => {
if (menu.name) {
names.push(menu.name)
}
})
return names
}
// addonKeys key
const getAddonAllKeys = (addonData) => {
if (!addonData || typeof addonData !== 'object') return [];
const allKeys = [];
Object.values(addonData).forEach(category => {
if (Array.isArray(category.list)) {
category.list.forEach(item => {
if (item.key) allKeys.push(item.key);
});
}
});
return allKeys;
};
// specialMenusKeys show
const handleSpecialMenus = () => {
const specialMenusKeys = storage.get('specialAppList')
if (Array.isArray(specialMenusKeys) && specialMenusKeys.length) {
const processedSpecialMenus = JSON.parse(JSON.stringify(specialMenusKeys));
const activeAppKey = storage.get('activeAppKey');
// name
processedSpecialMenus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
const traverseChildren = (children) => {
children.forEach(child => {
if (child && child.is_show !== undefined) {
child.is_show = (child.menu_key === activeAppKey) ? 1 : 0;
}
});
};
traverseChildren(menu.children);
}
});
// children
const filteredSpecialMenus = processedSpecialMenus.filter(menu => {
return menu.children && menu.children.length > 0;
});
return formatRouters(filteredSpecialMenus);
}
return [];
};
//
const handleJump = (routeName: string) => {
//
const isInSpecialMenus = specialMenuNames.value.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
if (specialMenuNamesLevel1.value.includes(routeName)) {
routeName = 'addon_list'
}
//
router.push({ name: routeName })
}
watch(route, () => {
const addonKeys = storage.get('defaultAppList')
if (props.routes.name == 'addon_list') {
const addonAllKeys = getAddonAllKeys(addonKeys);
if (props.routes.children) {
//
props.routes.children = props.routes.children.filter(child => {
return !child.name || !addonAllKeys.includes(child.name);
});
//
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length) {
const newChildren = [...(props.routes.children || [])];
processedSpecialMenus.forEach(special => {
const index = newChildren.findIndex(child => child.name === special.name);
if (index !== -1) {
newChildren[index] = special;
} else {
newChildren.push(special);
}
});
props.routes.children = newChildren;
}
}
if (systemAddonKeys.value.includes(route.meta.addon) && addonRouters[route.meta.addon]) {
addonsMenus.value = addonRouters[route.meta.addon]
} else if (route.meta.attr && addonRouters[route.meta.attr]) {
@ -107,12 +232,46 @@ watch(route, () => {
addonsMenus.value = null
}
}
// console.log('addonsMenus', props.routes)
}, { immediate: true })
// localStorage activeAppKey
onMounted(() => {
const processedSpecialMenus = handleSpecialMenus();
specialMenuNames.value = collectSpecialMenuNames(processedSpecialMenus)
specialMenuNamesLevel1.value = collectSpecialMenuNamesLevel1(processedSpecialMenus)
const handleStorageChange = (event: StorageEvent) => {
if (event.key === 'activeAppKey') {
if (props.routes.name == 'addon_list') {
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length && props.routes.children) {
const newChildren = [...(props.routes.children || [])];
processedSpecialMenus.forEach(special => {
const index = newChildren.findIndex(child => child.name === special.name);
if (index !== -1) {
newChildren[index] = special;
} else {
newChildren.push(special);
}
});
props.routes.children = newChildren;
}
}
}
};
window.addEventListener('storage', handleStorageChange);
//
onUnmounted(() => {
window.removeEventListener('storage', handleStorageChange);
});
});
</script>
<style lang="scss">
.el-sub-menu{
.el-icon{
.el-sub-menu {
.el-icon {
width: auto;
}
}

View File

@ -30,8 +30,9 @@ import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import menuItem from './menu-item.vue'
import { img } from '@/utils/common'
import { findFirstValidRoute } from '@/router/routers'
import { getShowMarketing } from '@/app/api/site'
import { findFirstValidRoute ,formatRouters} from '@/router/routers'
import { getShowApp,getShowSpecialMenu} from '@/app/api/site'
import storage from '@/utils/storage'
const systemStore = useSystemStore()
@ -46,20 +47,27 @@ const logoUrl = computed(() => {
return userStore.siteInfo.icon ? userStore.siteInfo.icon : systemStore.website.icon
})
const getMarketingList = async () => {
const res = await getShowMarketing()
const marketingList = res.data
const marketingKeys = marketingList?.marketing?.list?.map(item => item.key) ?? []
// menuData.value.forEach((item, index, arr) => {
// if (marketingKeys.includes(item.name)) {
// arr.splice(index, 1)
// }
// })
storage.set({ key: 'defaultMarketingKeys', data: marketingKeys })
const appList = ref<Record<string, any>[]>([])
const getAppList = async () => {
const res = await getShowApp()
appList.value = res.data
storage.set({ key: 'defaultAppList', data: appList.value })
}
const specialList = ref<Record<string, any>[]>([])
const getShowSpecialMenuList = async () => {
const res = await getShowSpecialMenu()
// specialList.value = formatRouters(res.data.list)
specialList.value = res.data.list
storage.set({ key: 'specialAppList', data: specialList.value })
}
onMounted(() => {
getMarketingList()
getAppList()
getShowSpecialMenuList()
})
routers.forEach(item => {
@ -87,6 +95,7 @@ routers.forEach(item => {
addonRouters[item.meta.addon] = item
}
// console.log('menuData', menuData.value)
// ,
// menuData.value.sort((a, b) => {
// if (a.meta.sort && b.meta.sort) {

View File

@ -128,7 +128,7 @@ const dark = computed(() => {
})
const isMenuSearch = ref(false)
const routers = userStore.routers
const getParentTitleChain=(meta:any) =>{
const getParentTitleChain = (meta: any) => {
let titles = []
let current = meta?.parent_route
@ -139,35 +139,47 @@ const getParentTitleChain=(meta:any) =>{
current = current.parent_route
}
return titles.join(' - ')
}
const flattenRoutes = (routes:any, parent = null)=> {
let flat = [];
routes.forEach(route => {
const { path, name, meta = {}, short_title, children } = route
const isLeaf = meta.type ==1 && meta.show==1
if(isLeaf){
const title = meta.title || short_title || ''
const parentTitleChain = getParentTitleChain(meta)
const fullTitle = parentTitleChain ? `${parentTitleChain} - ${title}` : title
const item = {
path,
name,
title,
parent_title: parentTitleChain,
full_title: fullTitle
};
return titles.join(' - ');
};
flat.push(item);
// 2. flattenRoutes parentShow show
const flattenRoutes = (routes: any, parent = null, parentShow = 1) => {
let flat = [];
routes.forEach(route => {
const { path, name, meta = {}, short_title, children } = route;
// show = show1 && show1
// show 1
const currentShow = meta.show === undefined ? 1 : meta.show;
const finalShow = currentShow && parentShow; //
// type=1 + show=1+
const isLeaf = meta.type === 1 && finalShow === 1;
if (isLeaf) {
const title = meta.title || short_title || '';
const parentTitleChain = getParentTitleChain(meta);
const fullTitle = parentTitleChain ? `${parentTitleChain} - ${title}` : title;
const item = {
path,
name,
title,
parent_title: parentTitleChain,
full_title: fullTitle
};
flat.push(item);
}
// finalShow parentShow
if (children && children.length > 0) {
flat = flat.concat(flattenRoutes(children, route))
flat = flat.concat(flattenRoutes(children, route, finalShow));
}
});
return flat;
}
const flatRoutes = flattenRoutes(routers)
};
const flatRoutes = flattenRoutes(routers);
const selectedRoute = ref('')
const handleRouteSelect = (name:any) => {
if (name) {

View File

@ -1,18 +1,18 @@
<template>
<template v-if="meta.show">
<el-sub-menu v-if="routes.children" :index="String(routes.name)">
<el-sub-menu v-if="hasVisibleChild" :index="String(routes.name)">
<template #title>
<span :class="['ml-[10px]']">{{ meta.title }}</span>
</template>
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" />
</el-sub-menu>
<template v-else>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
<template #title>
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
</template>
</el-menu-item>
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-else>
<el-menu-item :index="String(routes.name)" @click="handleJump(routes.name)" v-else>
<template #title>
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
</template>
@ -28,6 +28,7 @@ import { useRouter } from 'vue-router'
import { computed } from 'vue'
import menuItem from './menu-item.vue'
import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage'
const router = useRouter()
const props = defineProps({
@ -40,13 +41,37 @@ const userStore = useUserStore()
const siteInfo = userStore.siteInfo
const meta = computed(() => props.routes.meta)
const hasVisibleChild = computed(() => {
if (!props.routes.children || !Array.isArray(props.routes.children)) {
return false
}
return props.routes.children.some(child => child.meta?.show === 1)
})
const addons = computed(() => {
const addons:Record<string, any> = {}
siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
siteInfo?.site_addons.forEach((item: any) => { addons[item.key] = item })
return addons
})
//
const handleJump = (routeName: string) => {
//
const specialMenuNames = storage.get('specialMenuNames')
const specialMenuNamesLevel1 = storage.get('specialMenuNamesLevel1')
const isInSpecialMenus = specialMenuNames.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
if (specialMenuNamesLevel1.includes(routeName)) {
routeName = 'addon_list'
}
//
router.push({ name: routeName })
}
</script>
<style lang="scss">

View File

@ -20,7 +20,7 @@
<el-scrollbar class="h-[calc( 100vh - 64px )]">
<el-menu :default-active="oneMenuActive" :router="true" class="aside-menu" :unique-opened="true" :collapse="systemStore.menuIsCollapse">
<template v-for="(item, index) in oneMenuData" :key="index">
<el-menu-item :index="item.original_name" @click="router.push({ name: item.name })" v-if="item.meta.show">
<el-menu-item :index="item.original_name" @click="handleJump(item.name)" v-if="item.meta.show">
<div v-if="item.meta.icon" class="w-[16px] h-[16px] relative flex justify-center">
<el-image class="w-[16px] h-[16px] rounded-[50%] overflow-hidden" :src="item.meta.icon" fit="fill" v-if="isUrl(item.meta.icon)"/>
<icon :name="item.meta.icon" class="absolute top-[50%] -translate-y-[50%]" v-else />
@ -38,8 +38,8 @@
</el-scrollbar>
</div>
<el-scrollbar v-if="twoMenuData.length" class="two-menu w-[132px]">
<div class="w-[132px] h-[64px] flex items-center justify-center text-[16px] border-b-[1px] border-solid border-[var(--el-border-color-lighter)]">
<el-scrollbar v-if="twoMenuData.length" class="two-menu w-[152px]">
<div class="w-[152px] h-[64px] flex items-center justify-center text-[16px] border-b-[1px] border-solid border-[var(--el-border-color-lighter)]">
{{ route.matched[1].meta.title }}
</div>
@ -57,12 +57,13 @@
import { ref, watch, computed, onMounted, watchEffect } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import useSystemStore from '@/stores/modules/system'
import { getShowApp, getShowMarketing } from '@/app/api/site'
import useUserStore from '@/stores/modules/user'
import { img, isUrl } from '@/utils/common'
import { findFirstValidRoute } from '@/router/routers'
import menuItem from './menu-item.vue'
import { cloneDeep } from 'lodash-es'
import { getShowApp,getShowSpecialMenu} from '@/app/api/site'
import { findFirstValidRoute,formatRouters } from '@/router/routers'
import storage from '@/utils/storage'
const route = useRoute()
const router = useRouter()
@ -147,20 +148,35 @@ const marketingList = ref(null)
// const loading = ref(true);
const oneMenuActive = ref(route.matched[1].name)
const getAppList = async () => {
const res = await getShowApp()
appList.value = res.data
// loading.value = false;
storage.set({ key: 'defaultAppList', data: appList.value })
}
const getMarketingList = async () => {
const res = await getShowMarketing()
marketingList.value = res.data
const specialList = ref<Record<string, any>[]>([])
const getShowSpecialMenuList = async () => {
const res = await getShowSpecialMenu()
// specialList.value = formatRouters(res.data.list)
specialList.value = res.data.list
storage.set({ key: 'specialAppList', data: specialList.value })
}
onMounted(async () => {
await getAppList() //
await getMarketingList()
const specialMenuNames = ref<string[]>([])
const specialMenuNamesLevel1 = ref<string[]>([])
onMounted(() => {
getAppList()
getShowSpecialMenuList()
const processedSpecialMenus = handleSpecialMenus();
specialMenuNames.value = collectSpecialMenuNames(processedSpecialMenus)
specialMenuNamesLevel1.value = collectSpecialMenuNamesLevel1(processedSpecialMenus)
storage.set({ key: 'specialMenuNames', data: specialMenuNames.value })
storage.set({ key: 'specialMenuNamesLevel1', data: specialMenuNamesLevel1.value })
})
//
const menuOption = ref([])
const secondMenuShowWayFn = () => {
@ -173,75 +189,192 @@ const secondMenuShowWayFn = () => {
}
}
watchEffect(() => {
// if (!appList.value || loading.value) return; //
const addonKeys = appList.value?.addon?.list?.map(item => item.key) ?? []
const toolKeys = appList.value?.tool?.list?.map(item => item.key) ?? []
const allKeys = [...addonKeys, ...toolKeys]
const marketingKeys = marketingList.value?.marketing?.list?.map(item => item.key) ?? []
const matchedName = route.matched[1]?.name
if (allKeys.includes(matchedName)) {
oneMenuActive.value = 'addon'
twoMenuData.value = route.matched[1]?.children ?? []
} else if (marketingKeys.includes(matchedName)) {
oneMenuActive.value = 'active'
twoMenuData.value = route.matched[1]?.children ?? []
} else if (route.meta.attr !== '') {
oneMenuActive.value = route.matched[2]?.name
twoMenuData.value = route.matched[1]?.children ?? []
// watchEffect(() => {
// // if (!appList.value || loading.value) return; //
// const addonKeys = appList.value?.addon?.list?.map(item => item.key) ?? []
// const toolKeys = appList.value?.tool?.list?.map(item => item.key) ?? []
// const allKeys = [...addonKeys, ...toolKeys]
// const marketingKeys = marketingList.value?.marketing?.list?.map(item => item.key) ?? []
// const matchedName = route.matched[1]?.name
// if (allKeys.includes(matchedName)) {
// oneMenuActive.value = 'addon'
// twoMenuData.value = route.matched[1]?.children ?? []
// } else if (marketingKeys.includes(matchedName)) {
// oneMenuActive.value = 'active'
// twoMenuData.value = route.matched[1]?.children ?? []
// } else if (route.meta.attr !== '') {
// oneMenuActive.value = route.matched[2]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// } else {
// //
// if (siteInfo?.apps.length > 1) {
// twoMenuData.value = route.matched[1]?.children
// oneMenuActive.value = route.matched[1]?.name
// } else {
// //
// const oneMenu = route.matched[1]
// if (oneMenu.meta.addon === '') {
// oneMenuActive.value = route.matched[1]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// } else {
// if (oneMenu.meta.addon === siteInfo?.apps[0]?.key) {
// oneMenuActive.value = route.matched[2]?.name
// twoMenuData.value = route.matched[2]?.children ?? []
// } else {
// oneMenuActive.value = route.matched[1]?.name
// twoMenuData.value = route.matched[1]?.children ?? []
// }
// }
// }
// }
// secondMenuShowWayFn()
// })
// addonKeys key
const getAddonAllKeys = (addonData) => {
if (!addonData || typeof addonData !== 'object') return [];
const allKeys = [];
Object.values(addonData).forEach(category => {
if (Array.isArray(category.list)) {
category.list.forEach(item => {
if (item.key) allKeys.push(item.key);
});
}
});
return allKeys;
};
// specialMenusKeys show
const handleSpecialMenus = () => {
const specialMenusKeys = storage.get('specialAppList')
if (Array.isArray(specialMenusKeys) && specialMenusKeys.length) {
const processedSpecialMenus = JSON.parse(JSON.stringify(specialMenusKeys));
const activeAppKey = storage.get('activeAppKey');
// name
processedSpecialMenus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
const traverseChildren = (children) => {
children.forEach(child => {
if (child && child.is_show !== undefined) {
child.is_show = (child.menu_key === activeAppKey) ? 1 : 0;
}
});
};
traverseChildren(menu.children);
}
});
// children
const filteredSpecialMenus = processedSpecialMenus.filter(menu => {
return menu.children && menu.children.length > 0;
});
return formatRouters(filteredSpecialMenus);
}
return [];
};
// name
const collectSpecialMenuNames = (menus: any[]) => {
const names: string[] = []
const traverse = (children: any[]) => {
children.forEach(child => {
if (child.name) {
names.push(child.name)
}
//
if (child.children && Array.isArray(child.children)) {
traverse(child.children)
}
})
}
menus.forEach(menu => {
if (menu.children && Array.isArray(menu.children)) {
traverse(menu.children)
}
})
return names
}
// name
const collectSpecialMenuNamesLevel1 = (menus: any[]) =>{
const names: string[] = []
menus.forEach(menu => {
if (menu.name) {
names.push(menu.name)
}
})
return names
}
//
const handleJump = (routeName: string) => {
//
const isInSpecialMenus = specialMenuNames.value.includes(routeName)
// activeAppKey
if (!isInSpecialMenus) {
storage.remove('activeAppKey')
} else {
}
//
router.push({ name: routeName })
}
watch(route, () => {
if (route.meta.attr != '') {
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
} else {
//
if (siteInfo?.apps.length > 1) {
twoMenuData.value = route.matched[1]?.children
oneMenuActive.value = route.matched[1]?.name
twoMenuData.value = route.matched[1].children
oneMenuActive.value = route.matched[1].name
} else {
//
const oneMenu = route.matched[1]
if (oneMenu.meta.addon === '') {
oneMenuActive.value = route.matched[1]?.name
twoMenuData.value = route.matched[1]?.children ?? []
if (oneMenu.meta.addon == '') {
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
} else {
if (oneMenu.meta.addon === siteInfo?.apps[0]?.key) {
oneMenuActive.value = route.matched[2]?.name
twoMenuData.value = route.matched[2]?.children ?? []
if (oneMenu.meta.addon == siteInfo?.apps[0].key) {
oneMenuActive.value = route.matched[2].name
twoMenuData.value = route.matched[2].children ?? []
} else {
oneMenuActive.value = route.matched[1]?.name
twoMenuData.value = route.matched[1]?.children ?? []
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
}
}
}
}
secondMenuShowWayFn()
})
// watch(route, () => {
// if (route.meta.attr != '') {
// oneMenuActive.value = route.matched[2].name
// twoMenuData.value = route.matched[1].children ?? []
// } else {
// //
// if (siteInfo?.apps.length > 1) {
// twoMenuData.value = route.matched[1].children
// oneMenuActive.value = route.matched[1].name
// } else {
// //
// const oneMenu = route.matched[1]
// if (oneMenu.meta.addon == '') {
// oneMenuActive.value = route.matched[1].name
// twoMenuData.value = route.matched[1].children ?? []
// } else {
// if (oneMenu.meta.addon == siteInfo?.apps[0].key) {
// oneMenuActive.value = route.matched[2].name
// twoMenuData.value = route.matched[2].children ?? []
// } else {
// oneMenuActive.value = route.matched[1].name
// twoMenuData.value = route.matched[1].children ?? []
// }
// }
// }
// }
// }, { immediate: true })
const addonKeys = storage.get('defaultAppList')
const addonAllKeys = getAddonAllKeys(addonKeys);
twoMenuData.value = twoMenuData.value.filter((child) =>{
return !child.name || !addonAllKeys.includes(child.name);
});
if(oneMenuActive.value == 'addon'){
// twoMenuData addon_list
const processedSpecialMenus = handleSpecialMenus();
if (processedSpecialMenus.length) {
// addon_list twoMenuData
const addonListIndex = twoMenuData.value.findIndex(
(item) => item.name === 'addon_list'
);
if (addonListIndex !== -1) {
// addon_list
twoMenuData.value.splice(
addonListIndex + 1,
0,
...processedSpecialMenus
);
} else {
// addon_list twoMenuData
twoMenuData.value.push(...processedSpecialMenus);
}
}
}
}, { immediate: true })
</script>
<style lang="scss">
@ -287,7 +420,7 @@ watchEffect(() => {
.two-menu {
.aside-menu:not(.el-menu--collapse) {
width: 132px;
width: 152px;
padding-top: 16px;
border: 0;
@ -343,6 +476,30 @@ watchEffect(() => {
margin-left: 0 !important;
}
}
.el-sub-menu{
.el-sub-menu__title{
margin: 0 8px 2px;
height: 40px;
padding-left: 18px;
border-radius: 2px;
span{
height: 40px;
display: flex;
align-items: center;
font-size: 14px;
}
&:hover{
background-color: transparent;
color: var(--el-color-primary);
}
}
.el-menu-item{
padding-left: 40px !important;
span{
margin-left: 0 !important;
}
}
}
}
}
}

View File

@ -1 +1 @@
/* addon-iconfont.css */
/* addon-iconfont.css */

View File

@ -1 +1 @@
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = {auth_key} [DATABASE] TYPE = mysql HOSTNAME = {dbhost} DATABASE = {dbname} USERNAME = {dbuser} PASSWORD = {dbpwd} HOSTPORT = {dbport} PREFIX = {dbprefix} CHARSET = utf8mb4 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [QUEUE] state = false [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_SITE_ID_NAME = site-id API_SITE_ID_NAME = site-id ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 86400 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret =
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = {auth_key} [DATABASE] TYPE = mysql HOSTNAME = {dbhost} DATABASE = {dbname} USERNAME = {dbuser} PASSWORD = {dbpwd} HOSTPORT = {dbport} PREFIX = {dbprefix} CHARSET = utf8mb4 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [QUEUE] state = false [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_SITE_ID_NAME = site-id API_SITE_ID_NAME = site-id ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 2592000 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret =

View File

@ -89,13 +89,6 @@ class ExceptionHandle extends Handle
'previous' => $e->getPrevious(),
] : [];
// 添加自定义异常处理机制
if (strpos($e->getMessage(), 'open_basedir') !== false) {
return fail('OPEN_BASEDIR_ERROR');
}
if (strpos($e->getMessage(), 'Allowed memory size of') !== false) {
return fail('PHP_SCRIPT_RUNNING_OUT_OF_MEMORY');
}
if ($e instanceof DbException) {
return fail(get_lang('DATA_GET_FAIL').':'.$e->getMessage(), [
'file' => $e->getFile(),
@ -122,17 +115,28 @@ class ExceptionHandle extends Handle
}
private function handleException(Throwable $e) {
// 添加自定义异常处理机制
if (strpos($e->getMessage(), 'open_basedir') !== false) {
return fail('OPEN_BASEDIR_ERROR');
}
if (strpos($e->getMessage(), 'Allowed memory size of') !== false) {
return fail('PHP_SCRIPT_RUNNING_OUT_OF_MEMORY');
}
if (preg_match('/^(fopen|file_get_contents|file_put_contents|include|require)\((.+?)\):.*Permission denied/', $e->getMessage(), $matches)) {
$filePath = $matches[2]; // 提取出来的文件路径
return fail("请检查文件{$filePath}是否存在或权限是否正确");
}
$trace = array_map(function ($class){
return str_replace('\\', '/', $class);
}, array_column($e->getTrace(), 'class'));
$debug = env("APP_DEBUG", false);
foreach ($trace as $class) {
if (preg_match('#^addon/([^/]+)/#', $class, $matches)) {
return fail("{$matches[1]}插件内{$class}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage());
return fail("{$matches[1]}插件内{$class}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage(),$debug?$e->getTrace():[]);
}
}
$debug = env("APP_DEBUG", false);
return fail("{$trace[0]}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage(), $debug ? $e->getTrace() : []);
}

View File

@ -78,7 +78,6 @@ class App extends BaseAdminController
["is_forced_upgrade",0],
["package_path", ""],
["package_type", ""],
["package_type", ""],
["build", []],
["cert", []],
["upgrade_type", ""],
@ -102,7 +101,6 @@ class App extends BaseAdminController
["is_forced_upgrade",0],
["package_path", ""],
["package_type", ""],
["package_type", ""],
["build", []],
["cert", []],
["upgrade_type", ""],

View File

@ -178,14 +178,13 @@ class Site extends BaseAdminController
return success(data: $data);
}
public function showApp()
/**
* 统一展示 安装的插件 应用 营销工具等。。
* @return Response
*/
public function showCustomer()
{
return success((new SiteService())->getShowAppTools());
}
public function showMarketing()
{
return success((new SiteService())->getShowMarketingTools());
return success((new SiteService())->showCustomer());
}
/**
@ -232,5 +231,11 @@ class Site extends BaseAdminController
return success(( new CaptchaService() )->create());
}
public function getSpecialMenuList()
{
return success('SUCCESS', (new SiteService())->getSpecialMenuList());
}
}

View File

@ -30,7 +30,8 @@ class Config extends BaseAdminController
*/
public function getWebsite()
{
return success(( new ConfigService() )->getWebSite());
$site_id = $this->request->header()['site-id'];
return success(( new ConfigService() )->getWebSite($site_id));
}
/**
@ -84,7 +85,8 @@ class Config extends BaseAdminController
*/
public function getCopyright()
{
return success(( new ConfigService() )->getCopyright());
$site_id = $this->request->header()['site-id'];
return success(( new ConfigService() )->getCopyright($site_id));
}
/**

View File

@ -106,6 +106,7 @@ class User extends BaseAdminController
$data = $this->request->params([
['username', ''],
['password', ''],
['mobile', ''],
['real_name', ''],
['status', UserDict::ON],
['head_img', ''],
@ -124,6 +125,7 @@ class User extends BaseAdminController
public function edit($uid) {
$data = $this->request->params([
['password', ''],
['mobile', ''],
['real_name', ''],
['head_img', ''],
]);

View File

@ -97,9 +97,8 @@ Route::group('site', function () {
// 获取店铺包含的插件
Route::get('addons', 'site.Site/addons');
// 获取应用列表
Route::get('showapp', 'site.Site/showApp');
// 获取营销列表
Route::get('showMarketing', 'site.Site/showMarketing');
Route::get('showCustomer', 'site.Site/showCustomer');
Route::get('special_menu', 'site.Site/getSpecialMenuList');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

View File

@ -54,7 +54,7 @@ class App extends BaseController
'mobile' => 'mobile'
]);
// 校验手机验证码(电脑端扫码)
// 校验手机验证码
( new LoginService() )->checkMobileCode($data[ 'mobile' ]);
$wechat_app_service = new WechatAppService();

View File

@ -0,0 +1,27 @@
<?php
declare (strict_types = 1);
namespace app\command;
use app\job\refreshArea;
use app\service\admin\auth\LoginService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class refreshAreaCommand extends Command
{
protected function configure()
{
// 指令配置
$this->setName('refreshArea')
->setDescription('更新地区命令');
}
protected function execute(Input $input, Output $output)
{
(new refreshArea())->execute($output);
// 指令输出
$output->writeln('地区更新成功');
}
}

View File

@ -28,6 +28,7 @@ class CommonActiveDict
const NEWCOMER_DISCOUNT = 'newcomer_discount'; // 新人专享 新
const PINTUAN = 'pintuan'; // 新人专享 新
const SECKILL = 'seckill'; // 秒杀 秒
const RELAY = 'relay'; // 接龙 接
public static function getActiveShort($active = '')
{
@ -72,6 +73,11 @@ class CommonActiveDict
'active_name' => get_lang('common_active_short.pintuan_name'),
'bg_color' => '#FF1C77'
],
self::RELAY => [
'name' => get_lang('common_active_short.relay_short'),
'active_name' => get_lang('common_active_short.relay_name'),
'bg_color' => '#0EB108'
],
];
return !empty($active) ? $data[$active] ?? [] : $data;
}

View File

@ -869,37 +869,37 @@ return [
],
],
],
[
'menu_name' => '营销管理',
'menu_key' => 'active',
'menu_short_name' => '营销',
'parent_key' => '',
'menu_type' => '0',
'icon' => 'iconfont iconyingxiao2',
'api_url' => '',
'router_path' => 'app/marketing',
'view_path' => '',
'methods' => '',
'sort' => '87',
'status' => '1',
'is_show' => '1',
'children' => [
[
'menu_name' => '营销列表',
'menu_key' => 'marketing_list',
'menu_short_name' => '营销列表',
'menu_type' => '1',
'icon' => 'iconfont iconmanage-apply',
'api_url' => 'marketing/list',
'router_path' => 'app/marketing',
'view_path' => 'app/marketing',
'methods' => 'get',
'sort' => '160',
'status' => '1',
'is_show' => '1',
],
],
],
// [
// 'menu_name' => '营销管理',
// 'menu_key' => 'active',
// 'menu_short_name' => '营销',
// 'parent_key' => '',
// 'menu_type' => '0',
// 'icon' => 'iconfont iconyingxiao2',
// 'api_url' => '',
// 'router_path' => 'app/marketing',
// 'view_path' => '',
// 'methods' => '',
// 'sort' => '87',
// 'status' => '1',
// 'is_show' => '1',
// 'children' => [
// [
// 'menu_name' => '营销列表',
// 'menu_key' => 'marketing_list',
// 'menu_short_name' => '营销列表',
// 'menu_type' => '1',
// 'icon' => 'iconfont iconmanage-apply',
// 'api_url' => 'marketing/list',
// 'router_path' => 'app/marketing',
// 'view_path' => 'app/marketing',
// 'methods' => 'get',
// 'sort' => '160',
// 'status' => '1',
// 'is_show' => '1',
// ],
// ],
// ],
[
'menu_name' => '核销管理',
'menu_key' => 'verify',
@ -911,7 +911,7 @@ return [
'router_path' => 'marketing/verify/index',
'view_path' => '',
'methods' => 'get',
'sort' => '48',
'sort' => '30',
'status' => '1',
'is_show' => '1',
'children' => [
@ -1021,14 +1021,14 @@ return [
'menu_name' => '签到管理',
'menu_key' => 'sign',
'menu_short_name' => '签到管理',
'parent_key' => 'active',
'parent_key' => 'addon',
'menu_type' => '0',
'icon' => 'element FolderChecked',
'api_url' => '',
'router_path' => 'marketing/sign/config',
'view_path' => '',
'methods' => 'get',
'sort' => '30',
'sort' => '91',
'status' => '1',
'is_show' => '1',
'children' => [
@ -1086,8 +1086,8 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconyingyong21',
'api_url' => '',
'router_path' => '',
'view_path' => '',
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => '',
'sort' => '86',
'status' => '1',
@ -1103,7 +1103,7 @@ return [
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => 'get',
'sort' => '130',
'sort' => '999',
'status' => '1',
'is_show' => '1',
],
@ -2578,7 +2578,7 @@ return [
'router_path' => '',
'view_path' => '',
'methods' => '',
'sort' => '0',
'sort' => '29',
'status' => '1',
'is_show' => '1',
'menu_attr' => 'diy_form',
@ -2628,7 +2628,7 @@ return [
'router_path' => '',
'view_path' => '',
'methods' => '',
'sort' => '0',
'sort' => '27',
'status' => '1',
'is_show' => '1',
'menu_attr' => 'setting_export',
@ -2678,7 +2678,7 @@ return [
'router_path' => '',
'view_path' => '',
'methods' => '',
'sort' => '0',
'sort' => '28',
'status' => '1',
'is_show' => '1',
'menu_attr' => 'printer_management',

View File

@ -18,6 +18,10 @@ class SiteDict
public const ON = 1;//正常
public const CLOSE = 3;//停止
public const ADDON_CHILD_MENU_DICT_SYSTEM_TOOL = 'system_tool';
public const ADDON_CHILD_MENU_DICT_MARKING_TOOL = 'marketing_tool';
public const ADDON_CHILD_MENU_DICT_MARKING_ACTIVE = 'marketing_active';
public const ADDON_CHILD_MENU_DICT_ADDON_TOOL = 'addon_tool';
/**
* 站点状态
@ -32,4 +36,39 @@ class SiteDict
];
}
/**
* 站点应用管理特殊子菜单
* @return array
*/
public static function getAddonChildMenu()
{
//注意 sort 倒序排序使用
return [
self::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL,
'name' => get_lang('dict_site_addon_menu.system_tool'),
'short_name' => get_lang('dict_site_addon_menu.system_tool_short'),
'sort' => 97
],
self::ADDON_CHILD_MENU_DICT_MARKING_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_MARKING_TOOL,
'name' => get_lang('dict_site_addon_menu.marking_tool'),
'short_name' => get_lang('dict_site.marking_tool_short'),
'sort' => 99
],
self::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE => [
'key' => self::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE,
'name' => get_lang('dict_site_addon_menu.marking_active'),
'short_name' => get_lang('dict_site_addon_menu.marking_active_short'),
'sort' => 100
],
self::ADDON_CHILD_MENU_DICT_ADDON_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_ADDON_TOOL,
'name' => get_lang('dict_site_addon_menu.addon_tool'),
'short_name' => get_lang('dict_site_addon_menu.addon_tool_short'),
'sort' => 98
],
];
}
}

View File

@ -40,6 +40,7 @@ class ConfigKeyDict
public const SMS = 'SMS';//短信配置
public const PINTUAN_ORDER_CONFIG = 'PINTUAN_ORDER_CONFIG';//拼团订单配置
public const RELAY_ORDER_CONFIG = 'RELAY_ORDER_CONFIG';//接龙订单配置
public const APP = 'app';
}

View File

@ -11,9 +11,9 @@ $system_event = [
/**
* 系统事件
*/
'AppInit' => [ 'app\listener\system\AppInitListener' ],
'AppInit' => ['app\listener\system\AppInitListener'],
//站点初始化
'SiteInit' => [ 'app\listener\system\SiteInitListener' ],
'SiteInit' => ['app\listener\system\SiteInitListener'],
// 站点创建之后
'AddSiteAfter' => [
'app\listener\system\AddSiteAfterListener'
@ -26,26 +26,26 @@ $system_event = [
* 会员相关事件
*/
//会员注册事件
'MemberRegister' => [ 'app\listener\member\MemberRegisterListener' ],
'MemberRegister' => ['app\listener\member\MemberRegisterListener'],
//会员登录事件
'MemberLogin' => [ 'app\listener\member\MemberLoginListener' ],
'MemberLogin' => ['app\listener\member\MemberLoginListener'],
//会员账户变化事件
'MemberAccount' => [ 'app\listener\member\MemberAccountListener' ],
'MemberAccount' => ['app\listener\member\MemberAccountListener'],
//扫码事件
'Scan' => [ 'app\listener\scan\ScanListener' ],
'Scan' => ['app\listener\scan\ScanListener'],
/**
* 支付相关事件
*/
'PayCreate' => [ 'app\listener\pay\PayCreateListener' ],
'PayCreate' => ['app\listener\pay\PayCreateListener'],
//支付成功
'PaySuccess' => [ 'app\listener\pay\PaySuccessListener' ],
'PaySuccess' => ['app\listener\pay\PaySuccessListener'],
//退款成功
'RefundSuccess' => [ 'app\listener\pay\RefundSuccessListener' ],
'RefundSuccess' => ['app\listener\pay\RefundSuccessListener'],
//转账成功
'TransferSuccess' => [ 'app\listener\pay\TransferSuccessListener' ],
'TransferSuccess' => ['app\listener\pay\TransferSuccessListener'],
// 任务失败统一回调,有四种定义方式
'queue_failed' => [
[ 'app\listener\job\QueueFailedLoggerListener', 'report' ],
['app\listener\job\QueueFailedLoggerListener', 'report'],
],
//系统应用管理加载
'AppManage' => [
@ -118,25 +118,28 @@ $system_event = [
'StatField' => [],
// 获取海报数据
'GetPosterType' => [ 'app\listener\system\PosterType' ],
'GetPosterData' => [ 'app\listener\system\Poster' ],
'GetPosterType' => ['app\listener\system\PosterType'],
'GetPosterData' => ['app\listener\system\Poster'],
// 小程序授权变更事件
'WeappAuthChangeAfter' => [ 'app\listener\system\WeappAuthChangeAfter' ],
'WeappAuthChangeAfter' => ['app\listener\system\WeappAuthChangeAfter'],
'ShowApp' => [
'app\listener\system\ShowAppListener'
],
'ShowMarketing' => [
'app\listener\system\ShowMarketingListener'
],
'ShowCustomer' => [
'app\listener\system\ShowCustomerListener'
],
//获取微信转账场景配置
'GetWechatTransferTradeScene' => [
'app\listener\transfer\TransferCashOutListener'
],
//主题色
'ThemeColor' => [ 'app\listener\diy\ThemeColorListener' ],
'ThemeColor' => ['app\listener\diy\ThemeColorListener'],
],
'subscribe' => [
],
];
return ( new DictLoader("Event") )->load($system_event);
return (new DictLoader("Event"))->load($system_event);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -27,16 +27,12 @@ class AutoClearPosterAndQrcode extends BaseJob
// 清理海报目录
$dir = 'upload/poster';
$dir = public_path($dir);
Log::write('AutoClearPosterAndQrcode尝试清理海报目录: ' . $dir);
$res = $this->clearDirectory($dir);
Log::write('AutoClearPosterAndQrcode海报目录清理结果: ' . ($res ? '成功' : '失败'));
// 清理二维码目录
$qrcode_dir = 'upload/qrcode';
$qrcode_dir = public_path($qrcode_dir);
Log::write('AutoClearPosterAndQrcode尝试清理二维码目录: ' . $qrcode_dir);
$res = $this->clearDirectory($qrcode_dir);
Log::write('AutoClearPosterAndQrcode二维码目录清理结果: ' . ($res ? '成功' : '失败'));
return true;
} catch (\Exception $e) {

View File

@ -68,6 +68,7 @@ return [
'NOT_EXIST_UPGRADE_CONTENT' => '没有获取到可以升级的内容',
'CLOUD_BUILD_AUTH_CODE_NOT_FOUND' => '请先填写授权码',
'TASK_CYCLE_ERROR' => '任务周期填写错误',
'UPGRADE_TASK_EXIST' => '有正在执行的升级任务,可以展开正在升级的任务,也可以在开发>更新缓存中清除缓存重新开始升级',
//登录注册重置账号....
'LOGIN_SUCCESS' => '登录成功',
@ -106,6 +107,7 @@ return [
'NO_SITE_USER_ROLE' => '用户不存在关联权限',
'ADMIN_NOT_ALLOW_EDIT_ROLE' => '超级管理员不允许改动权限',
'USERNAME_REPEAT' => '账号重复',
'MOBILE_REPEAT' => '手机号重复',
'SITE_USER_EXIST' => '该用户已存在',
//角色管理

View File

@ -467,5 +467,21 @@ return [
'pintuan_name' => '拼团',
'seckill_short' => '秒',
'seckill_name' => '秒杀',
'relay_short' => '接',
'relay_name' => '接龙',
],
//应用菜单下 特殊菜单定义
'dict_site_addon_menu' => [
'system_tool_short' => '系统',
'system_tool' => '系统工具',
'marking_tool_short' => '工具',
'marking_tool' => '营销工具',
'marking_active_short' => '活动',
'marking_active' => '营销活动',
'addon_tool_short' => '插件',
'addon_tool' => '应用插件',
]
];

View File

@ -0,0 +1,75 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\system;
use app\dict\site\SiteDict;
/**
* 查询营销列表
* Class ShowAppListener
* @package app\listener\system
*/
class ShowCustomerListener
{
public function handle()
{
// 应用app、addon 待定
// 营销marketing
// 工具tool
return [
// 应用
SiteDict::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL => [
[
'title' => '核销管理',
'desc' => '管理核销员及核销记录',
'icon' => 'static/resource/images/marketing/verifier.png',
'key' => 'verify',
'url' => '/marketing/verify/index',
],
[
'title' => '万能表单',
'desc' => '适用于各种应用场景,满足多样化的业务需求',
'icon' => 'static/resource/images/diy_form/icon.png',
'key' => 'diy_form',
'url' => '/diy_form/list',
],
[
'title' => '小票打印',
'desc' => '支持打印机添加,便捷创建小票打印模板',
'icon' => 'static/resource/images/tool/printer_icon.png',
'key' => 'printer_management',
'url' => '/printer/list',
],
[
'title' => '数据导出',
'desc' => '展示导出文件,支持删除与下载',
'icon' => 'static/resource/images/tool/export_icon.png',
'key' => 'setting_export',
'url' => '/setting/export',
],
],
// 工具
SiteDict::ADDON_CHILD_MENU_DICT_MARKING_TOOL => [
],
// 营销
SiteDict::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE => [
[
'title' => '签到管理',
'desc' => '客户每日签到发放奖励',
'icon' => 'static/resource/images/marketing/sign.png',
'key' => 'sign',
'url' => '/marketing/sign/config',
],
]
];
}
}

View File

@ -42,7 +42,7 @@ class AuthService extends BaseAdminService
{
$site_id = $request->adminSiteId();
//todo 将站点编号转化为站点id
$site_info = ( new CoreSiteService() )->getSiteCache($site_id);
$site_info = (new CoreSiteService())->getSiteCache($site_id);
//站点不存在
if (empty($site_info)) throw new AuthException('SITE_NOT_EXIST');
//没有当前站点的信息
@ -51,7 +51,7 @@ class AuthService extends BaseAdminService
}
$request->siteId($site_id);
$request->appType($site_info[ 'app_type' ]);
$request->appType($site_info['app_type']);
return true;
}
@ -67,19 +67,19 @@ class AuthService extends BaseAdminService
$rule = strtolower(trim($request->rule()->getRule()));
$method = strtolower(trim($request->method()));
$site_info = ( new AuthSiteService() )->getSiteInfo();
$site_info = (new AuthSiteService())->getSiteInfo();
if ($method != 'get') {
if ($site_info[ 'status' ] == SiteDict::EXPIRE) throw new AuthException('SITE_EXPIRE_NOT_ALLOW');
if ($site_info[ 'status' ] == SiteDict::CLOSE) throw new AuthException('SITE_CLOSE_NOT_ALLOW');
if ($site_info['status'] == SiteDict::EXPIRE) throw new AuthException('SITE_EXPIRE_NOT_ALLOW');
if ($site_info['status'] == SiteDict::CLOSE) throw new AuthException('SITE_CLOSE_NOT_ALLOW');
}
$menu_service = new MenuService();
$all_menu_list = $menu_service->getAllApiList($this->app_type);
//先判断当前访问的接口是否收到权限的限制
$method_menu_list = $all_menu_list[ $method ] ?? [];
$method_menu_list = $all_menu_list[$method] ?? [];
if (!in_array($rule, $method_menu_list)) {
$other_menu_list = $menu_service->getAllApiList($this->app_type == AppTypeDict::ADMIN ? AppTypeDict::SITE : AppTypeDict::ADMIN);
$method_menu_list = $other_menu_list[ $method ] ?? [];
$method_menu_list = $other_menu_list[$method] ?? [];
if (!in_array($rule, $method_menu_list)) {
return true;
} else {
@ -88,7 +88,7 @@ class AuthService extends BaseAdminService
}
$auth_role_list = $this->getAuthApiList();
if (!empty($auth_role_list[ $method ]) && in_array($rule, $auth_role_list[ $method ]))
if (!empty($auth_role_list[$method]) && in_array($rule, $auth_role_list[$method]))
return true;
throw new AuthException('NO_PERMISSION');
@ -118,15 +118,15 @@ class AuthService extends BaseAdminService
if (empty($user_role_info))
return [];
$is_admin = $user_role_info[ 'is_admin' ];//是否是超级管理员组
$is_admin = $user_role_info['is_admin'];//是否是超级管理员组
}
$menu_service = new MenuService();
if ($is_admin) {//查询全部启用的权限
//获取站点信息
return ( new AuthSiteService() )->getApiList(1);
return (new AuthSiteService())->getApiList(1);
} else {
$user_role_ids = $user_role_info[ 'role_ids' ];
$user_role_ids = $user_role_info['role_ids'];
$role_service = new RoleService();
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
@ -147,19 +147,20 @@ class AuthService extends BaseAdminService
$user_role_info = $this->getAuthRole($this->site_id);
if (empty($user_role_info))
return [];
$is_admin = $user_role_info[ 'is_admin' ];//是否是超级管理员组
$is_admin = $user_role_info['is_admin'];//是否是超级管理员组
}
$menu_service = new MenuService();
if ($is_admin) {
// 查询全部启用的权限
return ( new MenuService() )->getAllMenuList($this->app_type, 1, $is_tree, 1);
$menu_list = (new MenuService())->getAllMenuList($this->app_type, 1, $is_tree, 1);
} else {
$user_role_ids = $user_role_info[ 'role_ids' ];
$user_role_ids = $user_role_info['role_ids'];
$role_service = new RoleService();
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
return $menu_service->getMenuListByMenuKeys($this->site_id, $menu_keys, $this->app_type, $is_tree, $addon);
$menu_list = $menu_service->getMenuListByMenuKeys($this->site_id, $menu_keys, $this->app_type, $is_tree, $addon);
}
return $menu_list;
}
/**
@ -167,7 +168,7 @@ class AuthService extends BaseAdminService
*/
public function getAuthInfo()
{
return ( new SiteUserService() )->getInfo($this->uid);
return (new SiteUserService())->getInfo($this->uid);
}
/**
@ -178,7 +179,7 @@ class AuthService extends BaseAdminService
*/
public function modifyAuth(string $field, $data)
{
return ( new SiteUserService() )->modify($this->uid, $field, $data);
return (new SiteUserService())->modify($this->uid, $field, $data);
}
/**
@ -188,14 +189,14 @@ class AuthService extends BaseAdminService
*/
public function editAuth(array $data)
{
if (!empty($data[ 'password' ])) {
if (!empty($data['password'])) {
//检测原始密码是否正确
$user = ( new UserService() )->find($this->uid);
if (!check_password($data[ 'original_password' ], $user->password))
$user = (new UserService())->find($this->uid);
if (!check_password($data['original_password'], $user->password))
throw new AuthException('OLD_PASSWORD_ERROR');
}
return ( new UserService() )->edit($this->uid, $data);
return (new UserService())->edit($this->uid, $data);
}
/**
@ -207,14 +208,14 @@ class AuthService extends BaseAdminService
$super_admin_uid = Cache::get('super_admin_uid');
if (!$super_admin_uid) {
$super_admin_uid = ( new SysUserRole() )->where([
[ 'site_id', '=', request()->defaultSiteId() ],
[ 'is_admin', '=', 1 ]
$super_admin_uid = (new SysUserRole())->where([
['site_id', '=', request()->defaultSiteId()],
['is_admin', '=', 1]
])->value('uid');
Cache::set('super_admin_uid', $super_admin_uid);
}
return $super_admin_uid == ( new self() )->uid;
return $super_admin_uid == (new self())->uid;
}
}

View File

@ -120,7 +120,7 @@ class NiuSmsService extends BaseAdminService
{
$account_info = $this->niu_service->loginAccount($params);
if ($account_info) {
(new CoreNiuSmsService())->setNiuLoginConfig($params, true);
$this->niu_service->setNiuLoginConfig($params, true);
}
return $account_info;
}

View File

@ -423,142 +423,63 @@ class SiteService extends BaseAdminService
}
/**
* 查询应用列表todo 完善
* @return array
* @return array[]
*/
public function getShowAppTools()
public function showCustomer($is_sort=true)
{
$list = [
'tool' => $this->getAllAddonAndTool()['tool'],
// 'promotion' => [
// 'title' => '营销活动',
// 'list' => []
// ]
];
return $list;
}
/**
* 查询营销列表
* @return array
*/
public function getShowMarketingTools()
{
$all = $this->getAllAddonAndTool();
$list = [
'marketing' => $all['marketing'],
'addon' => $all['addon'],
];
return $list;
}
private function getMarketing()
{
$list = [
'marketing' => [
'title' => '营销活动',
'list' => []
]
];
$apps = event('ShowMarketing', ['site_id' => $this->site_id]);
$keys = [];
foreach ($apps as $v) {
foreach ($v as $ck => $cv) {
if (!empty($cv)) {
foreach ($cv as $addon_k => $addon_v) {
if (in_array($addon_v['key'], $keys)) {
continue;
}
$list[$ck]['list'][] = $addon_v;
$keys[] = $addon_v['key'];
}
$show_list = event('ShowCustomer', ['site_id' => $this->site_id]);
$addon_type_list = SiteDict::getAddonChildMenu();
$return = [];
foreach ($show_list as $item) {
foreach ($addon_type_list as $key => $value) {
if (!isset($return[$key])) {
$return[$key] = [
'title' => $value['name'],
'sort' => $value['sort'],
'list' => [],
];
}
$return[$key]['list'] = array_merge($return[$key]['list'], $item[$key] ?? []);
}
}
return $list;
}
private function getAllAddonAndTool()
{
$markting_list = $this->getMarketing() ?? [];
$markting = $markting_list['marketing'];
$marking_addon = $markting_list['tool']['list'] ?? [];
$list = [
'marketing' => $markting,
'addon' => [
'title' => '营销工具',
'list' => $marking_addon
],
'tool' => [
'title' => '系统工具',
'list' => []
],
// 'promotion' => [
// 'title' => '营销活动',
// 'list' => []
// ]
];
$apps = event('ShowApp');
//防止有未实现对应事件的插件额外做一次查询 未实现的直接放到 addon_tool 里面
$keys = [];
foreach ($apps as $v) {
foreach ($v as $ck => $cv) {
if (!empty($cv)) {
foreach ($cv as $addon_k => $addon_v) {
if (in_array($addon_v['key'], $keys)) {
continue;
}
$list[$ck]['list'][] = $addon_v;
$keys[] = $addon_v['key'];
}
}
foreach ($return as $item) {
foreach ($item['list'] as $value) {
$keys[] = $value['key'];
}
}
$site_addon = $this->getSiteAddons([]);
$menu_model = (new SysMenu());
$site_addons = $this->getSiteAddons([]);
$addon_urls = $menu_model
->where([['addon', 'in', array_column($site_addons, 'key')], ['is_show', '=', 1], ['menu_type', '=', 1]])
->where([['addon', 'in', array_column($site_addon, 'key')], ['addon', 'not in', $keys], ['is_show', '=', 1], ['menu_type', '=', 1]])
->order('id asc')
->group('addon')
->column('router_path', 'addon');
if (!empty($site_addons)) {
foreach ($site_addons as $k => $v) {
$continue = true;
if (!empty($markting['list'])) {
foreach ($markting['list'] as $key => $val) {
if ($v['key'] == $val['key']) {
unset($site_addons[$k]);
$continue = false;
}
}
}
if ($continue && !in_array($v['key'], $keys)) {
$url = $addon_urls[$v['key']] ?? '';
$list['addon']['list'][] = [
'title' => $v['title'],
'desc' => $v['desc'],
'icon' => $v['icon'],
'key' => $v['key'],
'url' => $url ? '/' . $url : ''
];
if (!empty($site_addon)) {
foreach ($site_addon as $k => $v) {
if (in_array($v['key'], $keys)) {
continue;
}
$url = $addon_urls[$v['key']] ?? '';
$return['addon_tool']['list'][] = [
'title' => $v['title'],
'desc' => $v['desc'],
'icon' => $v['icon'],
'key' => $v['key'],
'url' => $url ? '/' . $url : ''
];
}
}
return $list;
if($is_sort){
usort($return, function (array $a, array $b) {
$sortA = isset($a['sort']) ? (int)$a['sort'] : 0;
$sortB = isset($b['sort']) ? (int)$b['sort'] : 0;
return $sortB <=> $sortA;
});
}
return $return;
}
/**
@ -600,5 +521,53 @@ class SiteService extends BaseAdminService
return $config;
}
//生成菜单数据
public function getSpecialMenuList()
{
$auth_menu_list = (new AuthService())->getAuthMenuList(1);
$auth_menu_list = array_column($auth_menu_list, null, 'menu_key');
$auth_menu_list = $auth_menu_list['addon'];
$list = $this->showCustomer(false);//获取对应的需要展示的key
$addon_menu_list = SiteDict::getAddonChildMenu();
$menu_list = [];
foreach ($addon_menu_list as $item) {
$menu_key_list = array_column($list[$item['key']]['list'] ?? [], 'key');
$temp_menu = [
'app_type'=>'site',
'menu_name' => $item['name'],
'menu_key' => $item['key'],
'menu_short_name' => $item['short_name'],
'parent_key' => 'addon',
'menu_type' => '0',
'icon' => 'iconfont iconzhuangxiu3',
'api_url' => '',
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => 'get',
'sort' => $item['sort'],
'status' => '1',
'is_show' => '1',
];
$children = [];
foreach ($auth_menu_list['children'] as $datum_item) {
if (in_array($datum_item['menu_key'], $menu_key_list)) {
$children[] = $datum_item;
}
}
$temp_menu['children'] = $children;
$menu_list[] = $temp_menu;
}
usort($menu_list, function (array $a, array $b) {
$sortA = isset($a['sort']) ? (int)$a['sort'] : 0;
$sortB = isset($b['sort']) ? (int)$b['sort'] : 0;
return $sortB <=> $sortA;
});
return [
'parent_key' => 'addon',
'list' => $menu_list
];
}
}

View File

@ -37,9 +37,9 @@ class ConfigService extends BaseAdminService
* 获取版权信息(网站整体,不按照站点设置)
* @return array|mixed
*/
public function getCopyright()
public function getCopyright($site_id)
{
return ( new CoreSysConfigService() )->getCopyright($this->site_id);
return ( new CoreSysConfigService() )->getCopyright($site_id);
}
/**
@ -66,9 +66,10 @@ class ConfigService extends BaseAdminService
* 获取网站信息
* @return array
*/
public function getWebSite()
public function getWebSite($site_id = 0)
{
$info = ( new SiteService() )->getInfo($this->site_id);
$site_id = $site_id != 0 ? $site_id : $this->site_id;
$info = ( new SiteService() )->getInfo($site_id);
$service_info = $this->getService();
$info['site_login_logo'] = $service_info[ 'site_login_logo' ];
$info['site_login_bg_img'] = $service_info[ 'site_login_bg_img' ];

View File

@ -124,7 +124,8 @@ class StorageConfigService extends BaseAdminService
{
$config['default'] = $storage_type;
}else if ($config['default'] == $storage_type) {
$config['default'] = '';
throw new AdminException('UPLOAD_STORAGE_TYPE_ALL_CLOSE');
// $config['default'] = '';
}
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
{

View File

@ -37,7 +37,7 @@ class UserService extends BaseAdminService
public function __construct()
{
parent::__construct();
$this->model = new SysUser();
$this->model = new SysUser();
}
/**
@ -50,7 +50,7 @@ class UserService extends BaseAdminService
AuthService::isSuperAdmin();
$super_admin_uid = Cache::get('super_admin_uid');
$field = 'uid,username,head_img,real_name,last_ip,last_time,login_count,status';
$field = 'uid,username,mobile,head_img,real_name,last_ip,last_time,login_count,status';
$search_model = $this->model->withSearch([ 'username', 'real_name', 'last_time' ], $where)->field($field)->append([ 'status_name' ])->order('uid desc');
return $this->pageQuery($search_model, function ($item) use ($super_admin_uid) {
$item['site_num'] = (new SysUserRole())->where([['uid', '=', $item['uid']], ['site_id', '<>', request()->defaultSiteId() ] ])->count();
@ -71,7 +71,7 @@ class UserService extends BaseAdminService
$where = array(
['uid', '=', $uid],
);
$field = 'uid, username, head_img, real_name, last_ip, last_time, create_time, login_count, delete_time, update_time';
$field = 'uid, username, head_img, mobile, real_name, last_ip, last_time, create_time, login_count, delete_time, update_time';
$info = $this->model->where($where)->field($field)->findOrEmpty()->toArray();
if (!empty($info)) {
@ -96,11 +96,14 @@ class UserService extends BaseAdminService
*/
public function add(array $data){
if ($this->checkUsername($data['username'])) throw new CommonException('USERNAME_REPEAT');
//手机号 唯一校验 后续调整为使用validate
if ($this->checkUserMobile($data['mobile'])) throw new CommonException('MOBILE_REPEAT');
Db::startTrans();
try {
$user_data = [
'username' => $data['username'],
'mobile' => $data['mobile'],
'head_img' => $data['head_img'],
'status' => $data['status'],
'real_name' => $data['real_name'],
@ -180,6 +183,29 @@ class UserService extends BaseAdminService
else return false;
}
/**
* 检测用户名是否重复
* @param $username
* @return bool
* @throws DbException
*/
public function checkUserMobile($mobile,$uid=0)
{
if (empty($mobile)){
return true;
}
$where[] = ['mobile', '=', $mobile];
if ($uid != 0){
$where[] = ['uid', '<>', $uid];
}
$count = $this->model->where($where)->count();
if($count > 0)
{
return true;
}
else return false;
}
/**
* 用户模型对象
* @param int $uid
@ -211,6 +237,10 @@ class UserService extends BaseAdminService
if(isset($data['head_img'])){
$user_data['head_img'] = $data['head_img'];
}
if(isset($data['mobile']) && !empty($data['mobile'])){//手机号 唯一校验 后续调整为使用validate
if ($this->checkUserMobile($data['mobile'],$uid)) throw new CommonException('MOBILE_REPEAT');
$user_data['mobile'] = $data['mobile'];
}
if(isset($data['real_name'])){
$user_data['real_name'] = $data['real_name'];
}
@ -294,8 +324,8 @@ class UserService extends BaseAdminService
$all_uid = array_column($this->getUserAll($where), 'uid');
$all_role_uid = (new SysUserRole())->distinct(true)->order('id desc')->select()->column('uid');
$data = $this->model->distinct(true)->hasWhere('userrole', function ($query) {
$query->where([['is_admin', '=', 1]])->whereOr([['site_id', '=', 0]]);
})->withSearch(['username', 'realname', 'create_time'], $where)
$query->where([['is_admin', '=', 1]])->whereOr([['site_id', '=', 0]]);
})->withSearch(['username', 'realname', 'create_time'], $where)
->field($field)
->order('SysUser.uid desc')
->select()

View File

@ -93,7 +93,7 @@ class CoreAppCloudService extends CoreCloudBaseService
// uni
$uni_dir = $package_dir . 'uni-app';
dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]);
dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist', '.git' ]);
$this->handleUniapp($uni_dir);
// 替换env文件
$this->weappEnvReplace($uni_dir . DIRECTORY_SEPARATOR . '.env.production');

View File

@ -137,18 +137,18 @@ class CoreCloudBuildService extends BaseCoreService
// 拷贝手机端文件
$wap_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%wap%' ] ])->field('id')->findOrEmpty();
if ($wap_is_compile->isEmpty()) {
dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]);
dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist', '.git' ]);
$this->handleUniapp($package_dir . 'uni-app');
}
// 拷贝admin端文件
$admin_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%admin%' ] ])->field('id')->findOrEmpty();
if ($admin_is_compile->isEmpty()) {
dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea' ]);
dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea', '.git' ]);
}
// 拷贝web端文件
$web_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%web%' ] ])->field('id')->findOrEmpty();
if ($web_is_compile->isEmpty()) {
dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt' ]);
dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt', '.git' ]);
}
$this->handleCustomPort($package_dir);

View File

@ -115,7 +115,7 @@ class CoreExportService extends BaseCoreService
$data_list = [];
foreach ($data_array as $v)
{
$data_list = empty($data_list) ? $v : array_merge($data_list, $v);
$data_list = array_merge($data_list, $v );
}
return $data_list;
}

View File

@ -85,7 +85,7 @@ class CoreWeappCloudService extends CoreCloudBaseService
// 如果不存在编译版小程序
if ($compile_addon->isEmpty()) {
dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]);
dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist', '.git']);
$this->handleUniapp($uni_dir);
// 替换env文件
$this->weappEnvReplace($uni_dir . DIRECTORY_SEPARATOR . '.env.production');

View File

@ -0,0 +1 @@
ALTER TABLE `verify` CHANGE `value` `value` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '核销内容';

View File

@ -0,0 +1,14 @@
ALTER TABLE activity_exchange_code
CHANGE COLUMN activity_type activity_type VARCHAR(20) NOT NULL DEFAULT '' COMMENT '例seckill-秒杀活动';
ALTER TABLE activity_exchange_code
ADD COLUMN type_item_id INT(11) NOT NULL DEFAULT 0 COMMENT '规格id';
ALTER TABLE member
ADD COLUMN wxapp_openid VARCHAR(255) NOT NULL DEFAULT '' COMMENT '微信移动应用openid';
ALTER TABLE member
MODIFY wxapp_openid VARCHAR(255) NOT NULL DEFAULT '' COMMENT '微信移动应用openid' AFTER weapp_openid;
ALTER TABLE sys_user
ADD COLUMN mobile VARCHAR(20) NOT NULL DEFAULT '' COMMENT '手机号';

View File

@ -18,7 +18,8 @@ $data = [
//wokrerman的启动停止和重启
'workerman' => 'app\command\workerman\Workerman',
//重置管理员密码
'reset:password' => 'app\command\Resetpassword'
'reset:password' => 'app\command\Resetpassword',
'refresh:area' => 'app\command\refreshAreaCommand',
],
];
return (new DictLoader("Console"))->load($data);

View File

@ -1,6 +1,6 @@
<?php
return [
'version' => '1.1.6',
'code' => '202509130001'
'version' => '1.1.7',
'code' => '202510150001'
];

View File

@ -41,7 +41,7 @@ class Poster extends BasePoster
$bg_type = $poster_data[ 'global' ][ 'bgType' ];
$instance = PosterInstance::extension('imagick')->config([
'path' => realpath($dir) . DIRECTORY_SEPARATOR . $file_path,
'dpi' => [480,480]
'dpi' => [120,120]
]);
$bg_width = $poster_data[ 'global' ][ 'width' ];
$bg_height = $poster_data[ 'global' ][ 'height' ];

View File

@ -48,6 +48,7 @@ class BaseNiucloudClient
* @var string
*/
protected string $baseUri = 'https://api.niucloud.com/openapi/';
// protected string $baseUri = 'http://niucloud-admin.cn/openapi/';//调试放开
/**
*

View File

@ -1 +0,0 @@
import{d as l,r as d,o as i,c as p,a as t,b as u,e as m,w as x,u as v,f,E as h,p as b,g,h as I,i as w,t as S}from"./index-981069db.js";/* empty css */import{_ as B}from"./_plugin-vue_export-helper-c27b6911.js";const k=""+new URL("error-ab7e4004.png",import.meta.url).href,o=e=>(b("data-v-4f4088b5"),e=e(),g(),e),y={class:"error"},C={class:"flex items-center"},E=o(()=>t("div",null,[t("img",{class:"w-[240px]",src:k})],-1)),N={class:"text-left ml-[100px]"},R=o(()=>t("div",{class:"error-text text-[28px] font-bold"},"404错误",-1)),U=o(()=>t("div",{class:"text-[#222] text-[20px] mt-[15px]"},"哎呀,出错了!您访问的页面不存在...",-1)),V=o(()=>t("div",{class:"text-[#c4c2c2] text-[12px] mt-[5px]"},"尝试检查URL的错误然后点击浏览器刷新按钮。",-1)),L={class:"mt-[40px]"},$=l({__name:"404",setup(e){let s=null;const a=d(5),n=f();return s=setInterval(()=>{a.value===0?(clearInterval(s),n.go(-1)):a.value--},1e3),i(()=>{s&&clearInterval(s)}),(r,c)=>{const _=h;return I(),p("div",y,[t("div",C,[u(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[m(_,{class:"bottom",onClick:c[0]||(c[0]=D=>v(n).go(-1))},{default:x(()=>[w(S(a.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-4f4088b5"]]);export{z as default};

View File

@ -1 +0,0 @@
import{dz as f}from"./index-981069db.js";export{f as default};

View File

@ -1 +0,0 @@
import z from"./VerifySlide-93a39dd8.js";import g from"./VerifyPoints-504a8b73.js";import{Q as k,r as o,l as w,bb as T,Z as V,_ as B,h as p,c as u,a as c,i as N,C as y,x as d,s as C,bc as j,v}from"./index-981069db.js";import{_ as O}from"./_plugin-vue_export-helper-c27b6911.js";import"./index-764f42d4.js";const P={name:"Vue2Verify",components:{VerifySlide:z,VerifyPoints:g},props:{captchaType:{type:String,required:!0},figure:{type:Number},arith:{type:Number},mode:{type:String,default:"pop"},vSpace:{type:Number},explain:{type:String},imgSize:{type:Object,default(){return{width:"310px",height:"155px"}}},blockSize:{type:Object},barSize:{type:Object}},setup(m){const{captchaType:i,figure:e,arith:t,mode:n,vSpace:h,explain:f,imgSize:Q,blockSize:R,barSize:W}=k(m),a=o(!1),r=o(void 0),s=o(void 0),l=o({}),S=w(()=>n.value=="pop"?a.value:!0),b=()=>{l.value.refresh&&l.value.refresh()},x=()=>{a.value=!1,b()},_=()=>{n.value=="pop"&&(a.value=!0)};return T(()=>{switch(i.value){case"blockPuzzle":r.value="2",s.value="VerifySlide";break;case"clickWord":r.value="",s.value="VerifyPoints";break}}),{clickShow:a,verifyType:r,componentType:s,instance:l,showBox:S,closeBox:x,show:_}}},D={key:0,class:"verifybox-top"},E=c("i",{class:"iconfont icon-close"},null,-1),q=[E];function I(m,i,e,t,n,h){return V((p(),u("div",{class:v(e.mode=="pop"?"mask":"")},[c("div",{class:v(e.mode=="pop"?"verifybox":""),style:d({"max-width":parseInt(e.imgSize.width)+30+"px"})},[e.mode=="pop"?(p(),u("div",D,[N(" 请完成安全验证 "),c("span",{class:"verifybox-close",onClick:i[0]||(i[0]=(...f)=>t.closeBox&&t.closeBox(...f))},q)])):y("",!0),c("div",{class:"verifybox-bottom",style:d({padding:e.mode=="pop"?"15px":"0"})},[t.componentType?(p(),C(j(t.componentType),{key:0,captchaType:e.captchaType,type:t.verifyType,figure:e.figure,arith:e.arith,mode:e.mode,vSpace:e.vSpace,explain:e.explain,imgSize:e.imgSize,blockSize:e.blockSize,barSize:e.barSize,ref:"instance"},null,8,["captchaType","type","figure","arith","mode","vSpace","explain","imgSize","blockSize","barSize"])):y("",!0)],4)],6)],2)),[[B,t.showBox]])}const J=O(P,[["render",I]]);export{J as default};

View File

@ -1 +0,0 @@
import{r as F,a as V,b as K,c as G}from"./index-764f42d4.js";import{Q,bd as X,r as s,n as m,a_ as Y,h as H,c as I,a as l,x as A,Z,_ as U,F as $,W as ee,t as L,ay as te}from"./index-981069db.js";import{_ as ae}from"./_plugin-vue_export-helper-c27b6911.js";const ie={name:"VerifyPoints",props:{mode:{type:String,default:"fixed"},captchaType:{type:String},vSpace:{type:Number,default:5},imgSize:{type:Object,default(){return{width:"310px",height:"155px"}}},barSize:{type:Object,default(){return{width:"310px",height:"40px"}}}},setup(N,f){const{mode:_,captchaType:e,vSpace:R,imgSize:q,barSize:c}=Q(N),{proxy:n}=X(),h=s(""),z=s(3),p=m([]),a=m([]),o=s(1),O=s(""),w=m([]),v=s(""),u=m({imgHeight:0,imgWidth:0,barHeight:0,barWidth:0}),y=m([]),d=s(""),b=s(void 0),x=s(void 0),j=s(!0),C=s(!0),J=()=>{p.splice(0,p.length),a.splice(0,a.length),o.value=1,B(),te(()=>{const{imgHeight:i,imgWidth:t,barHeight:g,barWidth:r}=F(n);u.imgHeight=i,u.imgWidth=t,u.barHeight=g,u.barWidth=r,n.$parent.$emit("ready",n)})};Y(()=>{J(),n.$el.onselectstart=function(){return!1}});const S=s(null),D=i=>{if(a.push(k(S,i)),o.value==z.value){o.value=T(k(S,i));const t=M(a,u);a.length=0,a.push(...t),setTimeout(()=>{const g=h.value?V(v.value+"---"+JSON.stringify(a),h.value):v.value+"---"+JSON.stringify(a),r={captchaType:e.value,captcha_code:h.value?V(JSON.stringify(a),h.value):JSON.stringify(a),captcha_key:v.value};K(r).then(P=>{P.code==1?(b.value="#4cae4c",x.value="#5cb85c",d.value="验证成功",C.value=!1,_.value=="pop"&&setTimeout(()=>{n.$parent.clickShow=!1,W()},1500),n.$parent.$emit("success",{captchaVerification:g})):(n.$parent.$emit("error",n),b.value="#d9534f",x.value="#d9534f",d.value="验证失败",setTimeout(()=>{W()},700))})},400)}o.value<z.value&&(o.value=T(k(S,i)))},k=function(i,t){const g=t.offsetX,r=t.offsetY;return{x:g,y:r}},T=function(i){return y.push(Object.assign({},i)),o.value+1},W=function(){y.splice(0,y.length),b.value="#000",x.value="#ddd",C.value=!0,p.splice(0,p.length),a.splice(0,a.length),o.value=1,B(),d.value="验证失败",j.value=!0};function B(){const i={captchaType:e.value};G(i).then(t=>{t.code==1?(O.value=t.data.originalImageBase64,v.value=t.data.token,h.value=t.data.secretKey,w.value=t.data.wordList,d.value="请依次点击【"+w.value.join(",")+"】"):d.value=t.msg})}const M=function(i,t){return i.map(r=>{const P=Math.round(310*r.x/parseInt(t.imgWidth)),E=Math.round(155*r.y/parseInt(t.imgHeight));return{x:P,y:E}})};return{secretKey:h,checkNum:z,fontPos:p,checkPosArr:a,num:o,pointBackImgBase:O,pointTextList:w,backToken:v,setSize:u,tempPoints:y,text:d,barAreaColor:b,barAreaBorderColor:x,showRefresh:j,bindingClick:C,init:J,canvas:S,canvasClick:D,getMousePos:k,createPoint:T,refresh:W,getPictrue:B,pointTransfrom:M}}},ne={style:{position:"relative"}},se={class:"verify-img-out"},oe=l("i",{class:"iconfont icon-refresh"},null,-1),re=[oe],ce=["src"],le={class:"verify-msg"};function he(N,f,_,e,R,q){return H(),I("div",ne,[l("div",se,[l("div",{class:"verify-img-panel",style:A({width:e.setSize.imgWidth,height:e.setSize.imgHeight,"background-size":e.setSize.imgWidth+" "+e.setSize.imgHeight,"margin-bottom":_.vSpace+"px"})},[Z(l("div",{class:"verify-refresh",style:{"z-index":"3"},onClick:f[0]||(f[0]=(...c)=>e.refresh&&e.refresh(...c))},re,512),[[U,e.showRefresh]]),l("img",{src:"data:image/png;base64,"+e.pointBackImgBase,ref:"canvas",alt:"",style:{width:"100%",height:"100%",display:"block"},onClick:f[1]||(f[1]=c=>e.bindingClick?e.canvasClick(c):void 0)},null,8,ce),(H(!0),I($,null,ee(e.tempPoints,(c,n)=>(H(),I("div",{key:n,class:"point-area",style:A({"background-color":"#1abd6c",color:"#fff","z-index":9999,width:"20px",height:"20px","text-align":"center","line-height":"20px","border-radius":"50%",position:"absolute",top:parseInt(c.y-10)+"px",left:parseInt(c.x-10)+"px"})},L(n+1),5))),128))],4)]),l("div",{class:"verify-bar-area",style:A({width:e.setSize.imgWidth,color:this.barAreaColor,"border-color":this.barAreaBorderColor,"line-height":this.barSize.height})},[l("span",le,L(e.text),1)],4)])}const fe=ae(ie,[["render",he]]);export{fe as default};

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{d as V,y as B,f as N,r as x,a_ as S,h as T,c as j,e as o,w as s,a as t,t as n,u as e,q as a,i as h,B as q,aI as I,aJ as R,E as $,a$ as D,b0 as F,b1 as J,K,b2 as M,a9 as P}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as Q}from"./aliapp-7285103d.js";const U={class:"main-container"},z={class:"flex justify-between items-center"},G={class:"text-page-title"},H={class:"p-[20px]"},L={class:"panel-title !text-sm"},O={class:"text-[14px] font-[700]"},W={class:"text-[#999]"},X={class:"mt-[20px] mb-[40px] h-[32px]"},Y={class:"text-[14px] font-[700]"},Z={class:"text-[#999]"},tt={class:"mt-[20px] mb-[40px] h-[32px]"},et={class:"text-[14px] font-[700]"},st={class:"text-[#999]"},at=t("div",{class:"mt-[20px] mb-[40px] h-[32px]"},null,-1),ot={class:"text-[14px] font-[700]"},nt={class:"text-[#999]"},lt={class:"flex justify-center"},ct={class:"w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]"},pt={class:"mt-[22px] text-center"},it={class:"text-[12px]"},wt=V({__name:"access",setup(_t){const f=B(),d=N(),v=f.meta.title,_=x("/channel/aliapp"),p=x("");S(async()=>{const c=await Q();p.value=c.data.qr_code});const b=c=>{window.open(c,"_blank")},w=c=>{d.push({path:_.value})};return(c,l)=>{const g=I,y=R,m=$,i=D,C=F,u=J,E=K,k=M,A=P;return T(),j("div",U,[o(A,{class:"card !border-none",shadow:"never"},{default:s(()=>[t("div",z,[t("span",G,n(e(v)),1)]),o(y,{modelValue:_.value,"onUpdate:modelValue":l[0]||(l[0]=r=>_.value=r),class:"my-[20px]",onTabChange:w},{default:s(()=>[o(g,{label:e(a)("weappAccessFlow"),name:"/channel/aliapp"},null,8,["label"])]),_:1},8,["modelValue"]),t("div",H,[t("h3",L,n(e(a)("weappInlet")),1),o(k,null,{default:s(()=>[o(u,{span:20},{default:s(()=>[o(C,{active:4,direction:"vertical"},{default:s(()=>[o(i,null,{title:s(()=>[t("p",O,n(e(a)("weappAttestation")),1)]),description:s(()=>[t("span",W,n(e(a)("weappAttest")),1),t("div",X,[o(m,{type:"primary",onClick:l[1]||(l[1]=r=>b("https://open.alipay.com/develop/manage"))},{default:s(()=>[h(n(e(a)("clickAccess")),1)]),_:1})])]),_:1}),o(i,null,{title:s(()=>[t("p",Y,n(e(a)("weappSetting")),1)]),description:s(()=>[t("span",Z,n(e(a)("emplace")),1),t("div",tt,[o(m,{type:"primary",plain:"",onClick:l[2]||(l[2]=r=>e(d).push("/channel/aliapp/config"))},{default:s(()=>[h(n(e(a)("weappSettingBtn")),1)]),_:1})])]),_:1}),o(i,null,{title:s(()=>[t("p",et,n(e(a)("uploadVersion")),1)]),description:s(()=>[t("span",st,n(e(a)("releaseCourse")),1),at]),_:1}),o(i,null,{title:s(()=>[t("p",ot,n(e(a)("completeAccess")),1)]),description:s(()=>[t("span",nt,n(e(a)("releaseCourse")),1)]),_:1})]),_:1})]),_:1}),o(u,{span:4},{default:s(()=>[t("div",lt,[o(E,{class:"w-[180px] h-[180px]",src:p.value?e(q)(p.value):""},{error:s(()=>[t("div",ct,[t("span",null,n(p.value?e(a)("fileErr"):e(a)("emptyQrCode")),1)])]),_:1},8,["src"])]),t("div",pt,[t("p",it,n(e(a)("clickAccess2")),1)])]),_:1})]),_:1})])]),_:1})])}}});export{wt as default};

View File

@ -1 +0,0 @@
import{d as B,y as T,f as $,r as c,a_ as q,b6 as I,o as M,h as R,c as W,e,w as t,a as s,t as o,u as n,q as a,i as u,aI as A,aJ as L,E as U,a$ as j,b0 as D,b1 as F,b2 as G,a9 as J}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as P}from"./wechat-5d2c00db.js";const z={class:"main-container"},H={class:"flex justify-between items-center"},K={class:"text-page-title"},O={class:"p-[20px]"},Q={class:"panel-title !text-sm"},X={class:"text-[14px] font-[700]"},Y={class:"text-[#999]"},Z={class:"mt-[20px] mb-[40px] h-[32px]"},tt={class:"text-[14px] font-[700]"},et={class:"mt-[20px] mb-[40px] h-[32px]"},nt={class:"text-[14px] font-[700]"},st={class:"mt-[20px] mb-[40px] h-[32px]"},dt=B({__name:"access",setup(at){const f=T(),_=$(),x=f.meta.title,r=c("/channel/app"),b=c(""),g=c({}),y=c({}),h=async()=>{await P().then(({data:l})=>{g.value=l,b.value=l.qr_code})};q(async()=>{await h(),await I().then(({data:l})=>{y.value=l}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&h()})}),M(()=>{document.removeEventListener("visibilitychange",()=>{})});const w=l=>{window.open(l,"_blank")},C=l=>{_.push({path:r.value})};return(l,i)=>{const v=A,E=L,d=U,m=j,k=D,V=F,S=G,N=J;return R(),W("div",z,[e(N,{class:"card !border-none",shadow:"never"},{default:t(()=>[s("div",H,[s("span",K,o(n(x)),1)]),e(E,{modelValue:r.value,"onUpdate:modelValue":i[0]||(i[0]=p=>r.value=p),class:"my-[20px]",onTabChange:C},{default:t(()=>[e(v,{label:n(a)("accessFlow"),name:"/channel/app"},null,8,["label"]),e(v,{label:n(a)("versionManage"),name:"/channel/app/version"},null,8,["label"])]),_:1},8,["modelValue"]),s("div",O,[s("h3",Q,o(n(a)("appInlet")),1),e(S,null,{default:t(()=>[e(V,{span:20},{default:t(()=>[e(k,{class:"!mt-[10px]",active:3,direction:"vertical"},{default:t(()=>[e(m,null,{title:t(()=>[s("p",X,o(n(a)("uniappApp")),1)]),description:t(()=>[s("span",Y,o(n(a)("appAttestation1")),1),s("div",Z,[e(d,{type:"primary",onClick:i[1]||(i[1]=p=>w("https://dcloud.io/"))},{default:t(()=>[u(o(n(a)("toCreate")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",tt,o(n(a)("appSetting")),1)]),description:t(()=>[s("div",et,[e(d,{type:"primary",onClick:i[2]||(i[2]=p=>n(_).push("/channel/app/config"))},{default:t(()=>[u(o(n(a)("settingInfo")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",nt,o(n(a)("versionManage")),1)]),description:t(()=>[s("div",st,[e(d,{type:"primary",plain:"",onClick:i[3]||(i[3]=p=>n(_).push("/channel/app/version"))},{default:t(()=>[u(o(n(a)("releaseVersion")),1)]),_:1})])]),_:1})]),_:1})]),_:1})]),_:1})])]),_:1})])}}});export{dt as default};

View File

@ -1 +0,0 @@
import{d as W,y as T,f as j,r as m,a_ as F,b6 as I,o as U,h as w,c as b,e as n,w as s,a,t as o,u as e,q as t,i as r,F as C,B as z,aI as L,aJ as M,E as D,a$ as G,b0 as J,b1 as K,K as P,b2 as Q,a9 as H}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as O}from"./weapp-7a9a2b27.js";import{a as X}from"./wxoplatform-f13faa3d.js";const Y={class:"main-container"},Z={class:"flex justify-between items-center"},ee={class:"text-page-title"},te={class:"p-[20px]"},se={class:"panel-title !text-sm"},ae={class:"text-[14px] font-[700]"},ne={class:"text-[#999]"},oe={class:"mt-[20px] mb-[40px] h-[32px]"},le={class:"text-[14px] font-[700]"},pe={class:"text-[#999]"},ie={class:"mt-[20px] mb-[40px] h-[32px]"},ce={class:"text-[14px] font-[700]"},re={class:"text-[#999]"},_e={class:"mt-[20px] mb-[40px] h-[32px]"},de={class:"text-[14px] font-[700]"},ue={class:"text-[#999]"},me=a("div",{class:"mt-[20px] mb-[40px] h-[32px]"},null,-1),he={class:"flex justify-center"},fe={class:"w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]"},xe={class:"mt-[22px] text-center"},ve={class:"text-[12px]"},$e=W({__name:"access",setup(we){const k=T(),_=j(),E=k.meta.title,h=m("/channel/weapp"),d=m(""),f=m({}),x=m({}),g=async()=>{await O().then(({data:p})=>{f.value=p,d.value=p.qr_code})};F(async()=>{await g(),await I().then(({data:p})=>{x.value=p}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&g()})}),U(()=>{document.removeEventListener("visibilitychange",()=>{})});const A=p=>{window.open(p,"_blank")},B=p=>{_.push({path:h.value})},S=()=>{X().then(({data:p})=>{window.open(p)})};return(p,l)=>{const v=L,V=M,i=D,u=G,$=J,y=K,q=P,N=Q,R=H;return w(),b("div",Y,[n(R,{class:"card !border-none",shadow:"never"},{default:s(()=>[a("div",Z,[a("span",ee,o(e(E)),1)]),n(V,{modelValue:h.value,"onUpdate:modelValue":l[0]||(l[0]=c=>h.value=c),class:"mt-[20px]",onTabChange:B},{default:s(()=>[n(v,{label:e(t)("weappAccessFlow"),name:"/channel/weapp"},null,8,["label"]),n(v,{label:e(t)("subscribeMessage"),name:"/channel/weapp/message"},null,8,["label"]),n(v,{label:e(t)("weappRelease"),name:"/channel/weapp/code"},null,8,["label"])]),_:1},8,["modelValue"]),a("div",te,[a("h3",se,o(e(t)("weappInlet")),1),n(N,null,{default:s(()=>[n(y,{span:20},{default:s(()=>[n($,{class:"!mt-[10px]",active:4,direction:"vertical"},{default:s(()=>[n(u,null,{title:s(()=>[a("p",ae,o(e(t)("weappAttestation")),1)]),description:s(()=>[a("span",ne,o(e(t)("weappAttest")),1),a("div",oe,[n(i,{type:"primary",onClick:l[1]||(l[1]=c=>A("https://mp.weixin.qq.com/"))},{default:s(()=>[r(o(e(t)("clickAccess")),1)]),_:1})])]),_:1}),n(u,null,{title:s(()=>[a("p",le,o(e(t)("weappSetting")),1)]),description:s(()=>[a("span",pe,o(e(t)("emplace")),1),a("div",ie,[x.value.app_id&&x.value.app_secret?(w(),b(C,{key:0},[n(i,{type:"primary",onClick:l[2]||(l[2]=c=>e(_).push("/channel/weapp/config"))},{default:s(()=>[r(o(f.value.app_id?e(t)("seeConfig"):e(t)("weappSettingBtn")),1)]),_:1}),n(i,{type:"primary",plain:"",onClick:S},{default:s(()=>[r(o(f.value.is_authorization?e(t)("refreshAuth"):e(t)("authWeapp")),1)]),_:1})],64)):(w(),b(C,{key:1},[n(i,{type:"primary",onClick:l[3]||(l[3]=c=>e(_).push("/channel/weapp/config"))},{default:s(()=>[r(o(e(t)("weappSettingBtn")),1)]),_:1}),n(i,{type:"primary",plain:"",onClick:l[4]||(l[4]=c=>e(_).push("/channel/weapp/course"))},{default:s(()=>[r("配置教程")]),_:1})],64))])]),_:1}),n(u,null,{title:s(()=>[a("p",ce,o(e(t)("uploadVersion")),1)]),description:s(()=>[a("span",re,o(e(t)("releaseCourse")),1),a("div",_e,[n(i,{type:"primary",plain:"",onClick:l[5]||(l[5]=c=>e(_).push("/channel/weapp/code"))},{default:s(()=>[r(o(e(t)("weappRelease")),1)]),_:1})])]),_:1}),n(u,null,{title:s(()=>[a("p",de,o(e(t)("completeAccess")),1)]),description:s(()=>[a("span",ue,o(e(t)("releaseCourse")),1),me]),_:1})]),_:1})]),_:1}),n(y,{span:4},{default:s(()=>[a("div",he,[n(q,{class:"w-[180px] h-[180px]",src:d.value?e(z)(d.value):""},{error:s(()=>[a("div",fe,[a("span",null,o(d.value?e(t)("fileErr"):e(t)("emptyQrCode")),1)])]),_:1},8,["src"])]),a("div",xe,[a("p",ve,o(e(t)("clickAccess2")),1)])]),_:1})]),_:1})])]),_:1})])}}});export{$e as default};

View File

@ -1 +0,0 @@
import{d as W,y as $,f as j,r as u,a_ as F,b6 as I,o as R,h as w,c as y,e as a,w as s,a as n,t as o,u as e,q as t,i as r,F as U,s as z,B as L,aI as M,aJ as D,E as G,a$ as J,b0 as K,b1 as P,K as Q,b2 as H,a9 as O}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as X}from"./wechat-5d2c00db.js";import{a as Y}from"./wxoplatform-f13faa3d.js";const Z={class:"main-container"},ee={class:"flex justify-between items-center"},te={class:"text-page-title"},ae={class:"p-[20px]"},se={class:"panel-title !text-sm"},ne={class:"text-[14px] font-[700]"},oe={class:"text-[#999]"},le={class:"mt-[20px] mb-[40px] h-[32px]"},ce={class:"text-[14px] font-[700]"},ie={class:"text-[#999]"},pe={class:"mt-[20px] mb-[40px] h-[32px]"},re={class:"text-[14px] font-[700]"},_e={class:"text-[#999]"},de={class:"mt-[20px] mb-[40px] h-[32px]"},me={class:"flex justify-center"},ue={class:"w-[100%] h-[100%] flex items-center justify-center bg-[#f5f7fa]"},he={class:"mt-[22px] text-center"},fe={class:"text-[12px]"},Be=W({__name:"access",setup(ve){const C=$(),_=j(),k=C.meta.title,h=u("/channel/wechat"),d=u(""),f=u({}),v=u({}),b=async()=>{await X().then(({data:l})=>{f.value=l,d.value=l.qr_code})};F(async()=>{await b(),await I().then(({data:l})=>{v.value=l}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&b()})}),R(()=>{document.removeEventListener("visibilitychange",()=>{})});const E=l=>{window.open(l,"_blank")},A=l=>{_.push({path:h.value})},S=()=>{Y().then(({data:l})=>{window.open(l)})};return(l,c)=>{const m=M,B=D,i=G,x=J,V=K,g=P,q=Q,N=H,T=O;return w(),y("div",Z,[a(T,{class:"card !border-none",shadow:"never"},{default:s(()=>[n("div",ee,[n("span",te,o(e(k)),1)]),a(B,{modelValue:h.value,"onUpdate:modelValue":c[0]||(c[0]=p=>h.value=p),class:"my-[20px]",onTabChange:A},{default:s(()=>[a(m,{label:e(t)("wechatAccessFlow"),name:"/channel/wechat"},null,8,["label"]),a(m,{label:e(t)("customMenu"),name:"/channel/wechat/menu"},null,8,["label"]),a(m,{label:e(t)("wechatTemplate"),name:"/channel/wechat/message"},null,8,["label"]),a(m,{label:e(t)("reply"),name:"/channel/wechat/reply"},null,8,["label"])]),_:1},8,["modelValue"]),n("div",ae,[n("h3",se,o(e(t)("wechatInlet")),1),a(N,null,{default:s(()=>[a(g,{span:20},{default:s(()=>[a(V,{class:"!mt-[10px]",active:3,direction:"vertical"},{default:s(()=>[a(x,null,{title:s(()=>[n("p",ne,o(e(t)("wechatAttestation")),1)]),description:s(()=>[n("span",oe,o(e(t)("wechatAttestation1")),1),n("div",le,[a(i,{type:"primary",onClick:c[1]||(c[1]=p=>E("https://mp.weixin.qq.com/"))},{default:s(()=>[r(o(e(t)("clickAccess")),1)]),_:1})])]),_:1}),a(x,null,{title:s(()=>[n("p",ce,o(e(t)("wechatSetting")),1)]),description:s(()=>[n("span",ie,o(e(t)("wechatSetting1")),1),n("div",pe,[v.value.app_id&&v.value.app_secret?(w(),y(U,{key:0},[a(i,{type:"primary",onClick:c[2]||(c[2]=p=>e(_).push("/channel/wechat/config"))},{default:s(()=>[r(o(f.value.app_id?e(t)("seeConfig"):e(t)("clickSetting")),1)]),_:1}),a(i,{type:"primary",plain:"",onClick:S},{default:s(()=>[r(o(f.value.is_authorization?e(t)("refreshAuth"):e(t)("authWechat")),1)]),_:1})],64)):(w(),z(i,{key:1,type:"primary",onClick:c[3]||(c[3]=p=>e(_).push("/channel/wechat/config"))},{default:s(()=>[r(o(e(t)("clickSetting")),1)]),_:1}))])]),_:1}),a(x,null,{title:s(()=>[n("p",re,o(e(t)("wechatAccess")),1)]),description:s(()=>[n("span",_e,o(e(t)("wechatAccess")),1),n("div",de,[a(i,{type:"primary",plain:"",onClick:c[4]||(c[4]=p=>e(_).push("/channel/wechat/course"))},{default:s(()=>[r(o(e(t)("releaseCourse")),1)]),_:1})])]),_:1})]),_:1})]),_:1}),a(g,{span:4},{default:s(()=>[n("div",me,[a(q,{class:"w-[180px] h-[180px]",src:d.value?e(L)(d.value):""},{error:s(()=>[n("div",ue,[n("span",null,o(d.value?e(t)("fileErr"):e(t)("emptyQrCode")),1)])]),_:1},8,["src"])]),n("div",he,[n("p",fe,o(e(t)("clickAccess2")),1)])]),_:1})]),_:1})])]),_:1})])}}});export{Be as default};

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{_ as o}from"./add-member.vue_vue_type_script_setup_true_lang-a6a364bd.js";import"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import"./member-3d15b900.js";export{o as default};

View File

@ -1 +0,0 @@
import{d as I,r as m,n as L,l as R,q as o,h as N,s as M,w as d,a as Z,e as s,i as k,t as C,u as t,Z as j,bZ as z,L as A,M as O,N as T,E as K,V as S,a3 as G}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{p as J,z as Q,A as W}from"./member-3d15b900.js";const X={class:"dialog-footer"},me=I({__name:"add-member",emits:["complete"],setup(Y,{expose:$,emit:x}){const p=m(!1),i=m(!1),b=m(!1);let f="",c="";const w=m(!0),v=m(!0),g=m(!0),_={member_id:"",nickname:"",member_no:"",init_member_no:"",mobile:"",password:"",password_copy:""},r=L({..._}),y=m(),P=R(()=>({member_no:[{required:!0,message:o("memberNoPlaceholder"),trigger:"blur"},{validator:B,trigger:"blur"}],mobile:[{required:!0,message:o("mobilePlaceholder"),trigger:"blur"},{validator:D,trigger:"blur"}],password:[{required:!0,message:o("passwordPlaceholder"),trigger:"blur"}],password_copy:[{required:!0,message:o("passwordPlaceholder"),trigger:"blur"},{validator:E,trigger:"blur"}]})),D=(n,e,a)=>{e&&!/^1[3-9]\d{9}$/.test(e)?a(new Error(o("mobileHint"))):a()},E=(n,e,a)=>{e!=r.password?a(o("doubleCipherHint")):a()},B=(n,e,a)=>{e&&!/^[0-9a-zA-Z]*$/g.test(e)?a(new Error(o("memberNoHint"))):a()},U=async()=>{await Q().then(n=>{c=n.data}).catch(()=>{})},q=async n=>{if(i.value||!n)return;const e=W;await n.validate(async a=>{if(a){if(i.value=!0,b.value)return;b.value=!0,e(r).then(V=>{i.value=!1,b.value=!1,p.value=!1,x("complete")}).catch(()=>{i.value=!1,b.value=!1})}})};return $({showDialog:p,setFormData:async(n=null)=>{if(i.value=!0,Object.assign(r,_),f=o("addMember"),n){f=o("updateMember");const e=await(await J(n.member_id)).data;e&&Object.keys(r).forEach(a=>{e[a]!=null&&(r[a]=e[a])})}else await U(),r.member_no=c,r.init_member_no=c;i.value=!1}}),(n,e)=>{const a=A,u=O,V=T,h=K,F=S,H=G;return N(),M(F,{modelValue:p.value,"onUpdate:modelValue":e[14]||(e[14]=l=>p.value=l),title:t(f),width:"500px","destroy-on-close":!0},{footer:d(()=>[Z("span",X,[s(h,{onClick:e[12]||(e[12]=l=>p.value=!1)},{default:d(()=>[k(C(t(o)("cancel")),1)]),_:1}),s(h,{type:"primary",loading:i.value,onClick:e[13]||(e[13]=l=>q(y.value))},{default:d(()=>[k(C(t(o)("confirm")),1)]),_:1},8,["loading"])])]),default:d(()=>[j((N(),M(V,{model:r,"label-width":"90px",ref_key:"formRef",ref:y,rules:t(P),class:"page-form"},{default:d(()=>[s(u,{label:t(o)("memberNo"),prop:"member_no"},{default:d(()=>[s(a,{modelValue:r.member_no,"onUpdate:modelValue":e[0]||(e[0]=l=>r.member_no=l),modelModifiers:{trim:!0},clearable:"",maxlength:"20",placeholder:t(o)("memberNoPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),s(u,{label:t(o)("mobile"),prop:"mobile"},{default:d(()=>[s(a,{modelValue:r.mobile,"onUpdate:modelValue":e[1]||(e[1]=l=>r.mobile=l),modelModifiers:{trim:!0},clearable:"",placeholder:t(o)("mobilePlaceholder"),maxlength:"11",onKeyup:e[2]||(e[2]=l=>t(z)(l)),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),s(u,{label:t(o)("nickname")},{default:d(()=>[s(a,{modelValue:r.nickname,"onUpdate:modelValue":e[3]||(e[3]=l=>r.nickname=l),modelModifiers:{trim:!0},clearable:"",placeholder:t(o)("nickNamePlaceholder"),class:"input-width",maxlength:"10","show-word-limit":"",readonly:w.value,onClick:e[4]||(e[4]=l=>w.value=!1),onBlur:e[5]||(e[5]=l=>w.value=!0)},null,8,["modelValue","placeholder","readonly"])]),_:1},8,["label"]),s(u,{label:t(o)("password"),prop:"password"},{default:d(()=>[s(a,{modelValue:r.password,"onUpdate:modelValue":e[6]||(e[6]=l=>r.password=l),modelModifiers:{trim:!0},type:"password",placeholder:t(o)("passwordPlaceholder"),clearable:"",class:"input-width","show-password":!0,readonly:v.value,onClick:e[7]||(e[7]=l=>v.value=!1),onBlur:e[8]||(e[8]=l=>v.value=!0)},null,8,["modelValue","placeholder","readonly"])]),_:1},8,["label"]),s(u,{label:t(o)("passwordCopy"),prop:"password_copy"},{default:d(()=>[s(a,{modelValue:r.password_copy,"onUpdate:modelValue":e[9]||(e[9]=l=>r.password_copy=l),modelModifiers:{trim:!0},type:"password",placeholder:t(o)("passwordPlaceholder"),clearable:"",class:"input-width","show-password":!0,readonly:g.value,onClick:e[10]||(e[10]=l=>g.value=!1),onBlur:e[11]||(e[11]=l=>g.value=!0)},null,8,["modelValue","placeholder","readonly"])]),_:1},8,["label"])]),_:1},8,["model","rules"])),[[H,i.value]])]),_:1},8,["modelValue","title"])}}});export{me as _};

View File

@ -1 +0,0 @@
import{_ as o}from"./add-table.vue_vue_type_script_setup_true_lang-7b648f44.js";import"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./tools-7c26f9aa.js";export{o as default};

View File

@ -1 +0,0 @@
import{d as L,f as N,r as c,n as k,l as E,h as p,s as _,w as o,a as b,Z as x,u as t,t as f,q as n,e as d,i as B,ak as z,L as q,E as F,al as P,V as U,a3 as G}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{k as I,l as M}from"./tools-7c26f9aa.js";const le=L({__name:"add-table",setup(R,{expose:h}){const g=N(),m=c(!1),s=c(""),e=k({loading:!0,data:[],searchParam:{table_name:"",table_content:""}}),v=E(()=>e.data.filter(a=>!s.value||a.Name.toLowerCase().includes(s.value.toLowerCase())||a.Comment.toLowerCase().includes(s.value.toLowerCase()))),u=()=>{e.loading=!0,I().then(a=>{e.loading=!1,e.data=a.data}).catch(()=>{e.loading=!1})};u();const w=a=>{const l=a.Name;e.loading=!0,M({table_name:l}).then(i=>{e.loading=!1,m.value=!1,g.push({path:"/tools/code/edit",query:{id:i.data.id}})}).catch(()=>{e.loading=!1})};return h({showDialog:m,setFormData:async(a=null)=>{u()}}),(a,l)=>{const i=z,C=q,V=F,D=P,y=U,T=G;return p(),_(y,{modelValue:m.value,"onUpdate:modelValue":l[1]||(l[1]=r=>m.value=r),title:t(n)("addCode"),width:"800px","destroy-on-close":!0},{default:o(()=>[b("div",null,[x((p(),_(D,{data:t(v),size:"large",height:"400"},{empty:o(()=>[b("span",null,f(e.loading?"":t(n)("emptyData")),1)]),default:o(()=>[d(i,{prop:"Name",label:t(n)("tableName"),"min-width":"150"},null,8,["label"]),d(i,{prop:"Comment",label:t(n)("tableComment"),"min-width":"120"},null,8,["label"]),d(i,{align:"right","min-width":"150"},{header:o(()=>[d(C,{modelValue:s.value,"onUpdate:modelValue":l[0]||(l[0]=r=>s.value=r),modelModifiers:{trim:!0},size:"small",placeholder:t(n)("searchPlaceholder")},null,8,["modelValue","placeholder"])]),default:o(r=>[d(V,{size:"small",type:"primary",onClick:Z=>w(r.row)},{default:o(()=>[B(f(t(n)("addBtn")),1)]),_:2},1032,["onClick"])]),_:1})]),_:1},8,["data"])),[[T,e.loading]])])]),_:1},8,["modelValue","title"])}}});export{le as _};

View File

@ -1 +0,0 @@
import{_ as e}from"./add-theme.vue_vue_type_script_setup_true_lang-4685e294.js";const o=Object.freeze(Object.defineProperty({__proto__:null,default:e},Symbol.toStringTag,{value:"Module"}));export{o as _};

View File

@ -1 +0,0 @@
import{d as U,r as d,n as h,l as B,h as N,s as R,w as n,a as q,e as o,i as v,u as _,a6 as F,L as O,M as $,bJ as j,N as A,E as I,V as S}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{u as T}from"./diy-d896d899.js";const z={class:"dialog-footer"},X=U({__name:"add-theme",emits:["confirm"],setup(J,{expose:g,emit:V}){const y=T(),s=d(!1),i=d(!1),b={title:"",label:"",value:"",tip:""};let f=[];const m=d(""),l=h({...b}),k=r=>{f=r.key,m.value="";for(const e in l)l[e]="";r.data&&Object.keys(r.data).length&&(m.value="edit",Object.keys(l).forEach((e,t)=>{l[e]=r.data[e]?r.data[e]:""})),s.value=!0},p=d(),x=B(()=>({title:[{required:!0,message:"请输入颜色名称",trigger:"blur"}],value:[{required:!0,validator:(r,e,t)=>{e?t():t("请输入颜色value值")},trigger:["blur","change"]}],label:[{required:!0,message:"请输入颜色key值",trigger:"blur"},{validator:(r,e,t)=>{const u=/^[a-zA-Z0-9-]+$/;f.indexOf(e)!=-1&&t("新增颜色key值与已存在颜色key值命名重复请修改命名"),u.test(e)?t():t("颜色key值只能输入字母、数字和连字符")},trigger:"blur"}]})),w=async r=>{var e;i.value||await((e=p.value)==null?void 0:e.validate(async t=>{i.value||(i.value=!0,t&&(i.value=!1,V("confirm",F(l)),s.value=!1))}))};return g({dialogThemeVisible:s,open:k}),(r,e)=>{const t=O,u=$,E=j,C=A,c=I,D=S;return N(),R(D,{modelValue:s.value,"onUpdate:modelValue":e[6]||(e[6]=a=>s.value=a),title:"新增颜色",width:"550px","align-center":""},{footer:n(()=>[q("div",z,[o(c,{onClick:e[4]||(e[4]=a=>s.value=!1)},{default:n(()=>[v("取消")]),_:1}),o(c,{type:"primary",onClick:e[5]||(e[5]=a=>w(p.value))},{default:n(()=>[v("保存")]),_:1})])]),default:n(()=>[o(C,{model:l,"label-width":"120px",ref_key:"formRef",ref:p,rules:_(x)},{default:n(()=>[o(u,{label:"名字",prop:"title"},{default:n(()=>[o(t,{modelValue:l.title,"onUpdate:modelValue":e[0]||(e[0]=a=>l.title=a),class:"!w-[250px]",maxlength:"7",placeholder:"请输入颜色名称"},null,8,["modelValue"])]),_:1}),o(u,{label:"颜色key值",prop:"label"},{default:n(()=>[o(t,{modelValue:l.label,"onUpdate:modelValue":e[1]||(e[1]=a=>l.label=a),class:"!w-[250px]",maxlength:"20",disabled:m.value=="edit",placeholder:"请输入颜色key值"},null,8,["modelValue","disabled"])]),_:1}),o(u,{label:"颜色value值",prop:"value"},{default:n(()=>[o(E,{modelValue:l.value,"onUpdate:modelValue":e[2]||(e[2]=a=>l.value=a),"show-alpha":"",predefine:_(y).predefineColors},null,8,["modelValue","predefine"])]),_:1}),o(u,{label:"颜色提示"},{default:n(()=>[o(t,{modelValue:l.tip,"onUpdate:modelValue":e[3]||(e[3]=a=>l.tip=a),class:"!w-[250px]",placeholder:"请输入颜色提示"},null,8,["modelValue"])]),_:1})]),_:1},8,["model","rules"])]),_:1},8,["modelValue"])}}});export{X as _};

View File

@ -1 +0,0 @@
import{P as t}from"./index-981069db.js";function d(n){return t.get("addon/local",n)}function o(n){return t.post(`addon/install/${n.addon}`,n)}function a(n){return t.post(`addon/cloudinstall/${n.addon}`,n)}function s(n){return t.post(`addon/uninstall/${n.addon}`,n,{showSuccessMessage:!0})}function l(n){return t.get(`addon/install/check/${n}`)}function u(){return t.get("addon/installtask")}function i(n){return t.get(`addon/cloudinstall/${n}`)}function r(n){return t.get(`addon/uninstall/check/${n}`)}function c(n){return t.put(`addon/install/cancel/${n}`,{},{showErrorMessage:!1})}function g(){return t.get("addon/list/install")}function f(){return t.get("home/site/group/app_list")}function p(){return t.get("addon/init")}function A(){return t.get("app/index")}function h(){return t.get("index/adv_list")}export{g as a,A as b,h as c,p as d,d as e,u as f,f as g,a as h,o as i,i as j,r as k,c as l,l as p,s as u};

View File

@ -1 +0,0 @@
import{d as F,y as w,r as b,n as C,h as f,c as y,Z as B,s as D,w as r,e as o,a as l,t as n,u as a,q as i,i as k,cg as I,a6 as N,ch as U,b8 as L,M as R,a9 as S,N as T,E as j,a3 as q}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css */import A from"./index-8c50f34e.js";import"./el-form-item-4ed993c7.js";/* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-17b86af9.js";/* empty css *//* empty css */import"./attachment-9e0d5f86.js";import"./index.vue_vue_type_script_setup_true_lang-20418369.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-3d9b7185.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-51212ca7.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./sortable.esm-be94e56d.js";const M={class:"main-container"},O={class:"text-[16px] text-[#1D1F3A] font-bold mb-4"},Z={class:"panel-title !text-[14px] bg-[#F4F5F7] p-3 border-[#E6E6E6] border-solid border-b-[1px]"},$={class:"form-tip"},z={class:"box-card mt-[20px] !border-none"},G={class:"panel-title !text-[14px] bg-[#F4F5F7] p-3 border-[#E6E6E6] border-solid border-b-[1px]"},H={class:"form-tip"},J={class:"fixed-footer-wrap"},K={class:"fixed-footer"},Nt=F({__name:"adminlogin",setup(P){const g=w().meta.title,m=b(!0),_=b(),e=C({is_captcha:0,is_site_captcha:0,bg:"",site_bg:""});(async()=>{const p=await(await I()).data;Object.keys(e).forEach(t=>{e[t]=p[t]}),m.value=!1})();const v=async p=>{m.value||!p||await p.validate(t=>{if(t){const d=N(e);U(d).then(()=>{m.value=!1}).catch(()=>{m.value=!1})}})};return(p,t)=>{const d=L,c=R,u=A,h=S,x=T,V=j,E=q;return f(),y("div",M,[B((f(),D(x,{class:"page-form",model:e,"label-width":"150px",ref_key:"ruleFormRef",ref:_},{default:r(()=>[o(h,{class:"box-card !border-none",shadow:"never"},{default:r(()=>[l("h3",O,n(a(g)),1),l("h3",Z,n(a(i)("admin")),1),o(c,{label:a(i)("isCaptcha")},{default:r(()=>[o(d,{modelValue:e.is_captcha,"onUpdate:modelValue":t[0]||(t[0]=s=>e.is_captcha=s),"active-value":1,"inactive-value":0},null,8,["modelValue"])]),_:1},8,["label"]),o(c,{label:a(i)("bgImg")},{default:r(()=>[o(u,{modelValue:e.bg,"onUpdate:modelValue":t[1]||(t[1]=s=>e.bg=s)},null,8,["modelValue"]),l("div",$,n(a(i)("adminBgImgTip")),1)]),_:1},8,["label"]),l("div",z,[l("h3",G,n(a(i)("site")),1),o(c,{label:a(i)("isCaptcha")},{default:r(()=>[o(d,{modelValue:e.is_site_captcha,"onUpdate:modelValue":t[2]||(t[2]=s=>e.is_site_captcha=s),"active-value":1,"inactive-value":0},null,8,["modelValue"])]),_:1},8,["label"]),o(c,{label:a(i)("bgImg")},{default:r(()=>[o(u,{modelValue:e.site_bg,"onUpdate:modelValue":t[3]||(t[3]=s=>e.site_bg=s)},null,8,["modelValue"]),l("div",H,n(a(i)("siteBgImgTip")),1)]),_:1},8,["label"])])]),_:1})]),_:1},8,["model"])),[[E,m.value]]),l("div",J,[l("div",K,[o(V,{type:"primary",onClick:t[4]||(t[4]=s=>v(_.value))},{default:r(()=>[k(n(a(i)("save")),1)]),_:1})])])])}}});export{Nt as default};

View File

@ -1 +0,0 @@
import{d as v,y,n as k,f as x,h as m,c as E,e as a,w as o,a as i,t as r,u as t,Z as C,s as B,q as n,i as p,ci as N,ak as T,E as D,al as L,a9 as A,a3 as V}from"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */const j={class:"main-container"},R={class:"flex justify-between items-center"},$={class:"text-page-title"},q={class:"mt-[20px]"},X=v({__name:"agreement",setup(z){const _=y().meta.title,e=k({loading:!0,data:[]});(()=>{e.loading=!0,e.data=[],N().then(l=>{Object.keys(l.data).forEach(d=>e.data.push(l.data[d])),e.loading=!1}).catch(()=>{e.loading=!1})})();const u=x(),g=l=>{u.push(`/setting/agreement/edit?key=${l.agreement_key}`)};return(l,d)=>{const s=T,h=D,f=L,b=A,w=V;return m(),E("div",j,[a(b,{class:"box-card !border-none",shadow:"never"},{default:o(()=>[i("div",R,[i("span",$,r(t(_)),1)]),i("div",q,[C((m(),B(f,{data:e.data,size:"large"},{empty:o(()=>[i("span",null,r(e.loading?"":t(n)("emptyData")),1)]),default:o(()=>[a(s,{prop:"type_name",label:t(n)("typeName"),"min-width":"100","show-overflow-tooltip":!0},null,8,["label"]),a(s,{prop:"title",label:t(n)("title"),"min-width":"100","show-overflow-tooltip":!0},null,8,["label"]),a(s,{label:t(n)("updateTime"),"min-width":"180",align:"center"},{default:o(({row:c})=>[p(r(c.update_time||""),1)]),_:1},8,["label"]),a(s,{label:t(n)("operation"),align:"right",fixed:"right",width:"100"},{default:o(({row:c})=>[a(h,{type:"primary",link:"",onClick:Z=>g(c)},{default:o(()=>[p(r(t(n)("config")),1)]),_:2},1032,["onClick"])]),_:1},8,["label"])]),_:1},8,["data"])),[[w,e.loading]])])]),_:1})])}}});export{X as default};

View File

@ -1 +0,0 @@
import{d as q,y as M,f as P,r as y,cj as S,n as T,l as $,q as r,h,c as j,e as a,w as s,u as n,b4 as I,Z as U,s as A,a as w,i as k,t as x,ck as L,cl as O,b5 as H,a9 as Z,L as z,M as G,N as J,E as K,a3 as Q}from"./index-981069db.js";/* empty css *//* empty css *//* empty css */import{_ as W}from"./index.vue_vue_type_script_setup_true_lang-852e456f.js";import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-17b86af9.js";/* empty css *//* empty css */import"./attachment-9e0d5f86.js";import"./index.vue_vue_type_script_setup_true_lang-20418369.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-3d9b7185.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-51212ca7.js";import"./_plugin-vue_export-helper-c27b6911.js";const X={class:"main-container"},Y={class:"fixed-footer-wrap"},ee={class:"fixed-footer"},Se=q({__name:"agreement_edit",setup(te){const d=M(),V=P(),_=d.query.key||"",i=y(!1),E=S(),B=d.meta.title,f={agreement_key:"",content:"",title:"",agreement_key_name:""},t=T({...f});i.value=!0,_&&(async(m="")=>{Object.assign(t,f);const e=await(await L(m)).data;Object.keys(t).forEach(o=>{e[o]!=null&&(t[o]=e[o])}),i.value=!1})(_);const g=y(),D=$(()=>({title:[{required:!0,message:r("titlePlaceholder"),trigger:"blur"}],content:[{required:!0,trigger:["blur","change"],validator:(m,e,o)=>{if(e==="")o(new Error(r("contentPlaceholder")));else{if(e.length<5||e.length>1e5)return o(new Error(r("contentMaxTips"))),!1;o()}}}]})),C=async m=>{i.value||!m||await m.validate(async e=>{if(e){i.value=!0;const o=t;o.key=t.agreement_key,O(o).then(c=>{i.value=!1,p()}).catch(()=>{i.value=!1})}})},p=()=>{E.removeTab(d.path),V.push({path:"/setting/agreement"})};return(m,e)=>{const o=H,c=Z,v=z,u=G,F=W,N=J,b=K,R=Q;return h(),j("div",X,[a(c,{class:"card !border-none",shadow:"never"},{default:s(()=>[a(o,{content:n(B),icon:n(I),onBack:e[0]||(e[0]=l=>p())},null,8,["content","icon"])]),_:1}),U((h(),A(c,{class:"box-card mt-[15px] !border-none",shadow:"never"},{default:s(()=>[a(N,{model:t,"label-width":"90px",ref_key:"formRef",ref:g,rules:n(D),class:"page-form"},{default:s(()=>[a(u,{label:n(r)("type")},{default:s(()=>[a(v,{modelValue:t.agreement_key_name,"onUpdate:modelValue":e[1]||(e[1]=l=>t.agreement_key_name=l),modelModifiers:{trim:!0},readonly:"",class:"input-width"},null,8,["modelValue"])]),_:1},8,["label"]),a(u,{label:n(r)("title"),prop:"title"},{default:s(()=>[a(v,{modelValue:t.title,"onUpdate:modelValue":e[2]||(e[2]=l=>t.title=l),modelModifiers:{trim:!0},clearable:"",placeholder:n(r)("titlePlaceholder"),class:"input-width",maxlength:"20"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(u,{label:n(r)("content"),prop:"content"},{default:s(()=>[a(F,{modelValue:t.content,"onUpdate:modelValue":e[3]||(e[3]=l=>t.content=l)},null,8,["modelValue"])]),_:1},8,["label"])]),_:1},8,["model","rules"])]),_:1})),[[R,i.value]]),w("div",Y,[w("div",ee,[a(b,{type:"primary",onClick:e[4]||(e[4]=l=>C(g.value))},{default:s(()=>[k(x(n(r)("save")),1)]),_:1}),a(b,{onClick:e[5]||(e[5]=l=>p())},{default:s(()=>[k(x(n(r)("cancel")),1)]),_:1})])])])}}});export{Se as default};

View File

@ -1 +0,0 @@
import{P as t}from"./index-981069db.js";function e(){return t.get("aliapp/config")}function p(a){return t.put("aliapp/config",a,{showSuccessMessage:!0})}function n(){return t.get("aliapp/static")}export{n as a,e as g,p as s};

View File

@ -1 +0,0 @@
import{P as n}from"./index-981069db.js";function t(){return n.get("channel/app/config")}function r(e){return n.put("channel/app/config",e,{showSuccessMessage:!0})}function a(e){return n.get("channel/app/version",{params:e})}function o(e){return n.get(`channel/app/version/${e}`)}function u(){return n.get("channel/app/platfrom")}function i(e){return n.post("channel/app/version",e,{showSuccessMessage:!0})}function c(e){return n.put(`channel/app/version/${e.id}`,e,{showSuccessMessage:!0})}function p(e){return n.delete(`channel/app/version/${e.id}`)}function g(e){return n.get(`channel/app/build/log/${e}`)}function f(e){return n.put(`channel/app/version/${e}/release`,{},{showSuccessMessage:!0})}function l(e){return n.post("channel/app/generate_sing_cert",e,{showSuccessMessage:!0})}export{a,g as b,u as c,p as d,c as e,i as f,t as g,o as h,l as i,f as r,r as s};

View File

@ -1 +0,0 @@
import{_ as o}from"./app-version-edit.vue_vue_type_style_index_0_lang-a2ff20e5.js";import"./index-981069db.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-c7976b56.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import"./app-0e99a48e.js";import"./generate-sing-cert.vue_vue_type_script_setup_true_lang-6173a0d3.js";export{o as default};

View File

@ -1 +0,0 @@
import{d as I,f as V,j as M,r as y,n as N,Z as R,h as l,c as x,a as e,t as s,u as a,q as o,e as u,w as c,F as j,W as D,B as T,s as $,i as q,C as k,cb as b,H as w,E as z,K as H,ba as K,cc as O,ab as P,a3 as U,p as W,g as Z}from"./index-981069db.js";/* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css */import{_ as G}from"./apply_empty-cdca3e85.js";import{a as J}from"./addon-73fe6379.js";import{_ as Q}from"./_plugin-vue_export-helper-c27b6911.js";const X=""+new URL("app_store_default-c0531792.png",import.meta.url).href,h=_=>(W("data-v-8a156fb4"),_=_(),Z(),_),Y={class:"box-border pt-[68px] px-[76px] overview-top"},ee={key:0},te={class:"flex justify-between items-center"},se={class:"font-[600] text-[26px] text-[#222] leading-[37px]"},ae={class:"font-[500] text-[14px] text-[#222] leading-[20px] mt-[12px]"},oe=h(()=>e("div",{class:"mr-[9px] text-[#3F3F3F] iconfont iconxiazai01"},null,-1)),ne={class:"font-[600] text-[14px] text-[#222] leading-[20px]"},pe={class:"flex flex-wrap mt-[40px]"},ce=["onClick"],ie={class:"bg-[#F7FAFB] py-[18px] px-[24px] flex items-center app-item-head"},re=h(()=>e("div",{class:"image-slot"},[e("img",{class:"w-[40px] h-[40px] rounded-[8px]",src:X})],-1)),le={class:"py-[18px] px-[24px]"},_e={class:"font-[600] leading-[1] text-[14px] text-[#222]"},de={class:"text-[13px] text-[#6D7278] leading-[18px] mt-[6px] truncate"},xe=h(()=>e("div",{class:"w-[230px] mx-auto"},[e("img",{src:G,class:"max-w-full",alt:""})],-1)),ue={class:"flex items-center"},me=I({__name:"app_manage",setup(_){const v=V(),m=M(),n=y(!0),d=N({appList:[]}),f=y({});(()=>{n.value=!0,J().then(p=>{Object.values(p.data).forEach((t,i)=>{t.type=="app"&&d.appList.push(t)}),m.routers.forEach((t,i)=>{t.children&&t.children.length?(t.name=b(t.children),f.value[t.meta.app]=b(t.children)):f.value[t.meta.app]=t.name}),n.value=!1}).catch(()=>{n.value=!1})})();const L=p=>{w.set({key:"menuAppStorage",data:p.key}),w.set({key:"plugMenuTypeStorage",data:""});const t=m.appMenuList;t.push(p.key),m.setAppMenuList(t);const i=f.value[p.key];v.push({name:i})},g=()=>{v.push("/app_manage/app_store")};return(p,t)=>{const i=z,F=H,E=K,S=O,C=P,A=U;return R((l(),x("div",Y,[d.appList&&!n.value?(l(),x("div",ee,[e("div",te,[e("div",null,[e("div",se,s(a(o)("app")),1),e("div",ae,s(a(o)("versionInfo"))+" "+s(a(o)("currentVersion")),1)]),u(i,{onClick:g,class:"px-[15px]"},{default:c(()=>[oe,e("span",ne,s(a(o)("appStore")),1)]),_:1})]),e("div",pe,[(l(!0),x(j,null,D(d.appList,(r,B)=>(l(),x("div",{key:B,class:"app-item w-[280px] box-border !bg-[#fff] rounded-[6px] cursor-pointer mr-[20px] mb-[20px] overflow-hidden",onClick:he=>L(r)},[e("div",ie,[u(F,{class:"w-[44px] h-[44px] rounded-[8px]",src:a(T)(r.icon),fit:"contain"},{error:c(()=>[re]),_:2},1032,["src"])]),e("div",le,[e("div",_e,s(r.title),1),u(E,{class:"box-item",effect:"light",content:r.desc,placement:"bottom-start"},{default:c(()=>[e("div",de,s(r.desc),1)]),_:2},1032,["content"])])],8,ce))),128)),!d.appList.length&&!n.value?(l(),$(C,{key:0,class:"mx-auto overview-empty"},{image:c(()=>[xe]),description:c(()=>[e("p",ue,[e("span",null,s(a(o)("descriptionLeft")),1),u(S,{type:"primary",onClick:g,class:"mx-[5px]"},{default:c(()=>[q(s(a(o)("link")),1)]),_:1}),e("span",null,s(a(o)("descriptionRight")),1)])]),_:1})):k("",!0)])])):k("",!0)])),[[A,n.value]])}}});const Be=Q(me,[["__scopeId","data-v-8a156fb4"]]);export{Be as default};

View File

@ -1 +0,0 @@
import{d as f,y as h,r as y,h as m,c as s,e,w as o,a as i,t as b,u as p,F as v,W as x,q as g,aI as V,aJ as w,a9 as E}from"./index-981069db.js";/* empty css *//* empty css */import k from"./attachment-9e0d5f86.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-20418369.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-3d9b7185.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-51212ca7.js";import"./_plugin-vue_export-helper-c27b6911.js";const B={class:"main-container attachment-container"},C={class:"flex justify-between items-center mb-[20px]"},N={class:"text-page-title"},it=f({__name:"attachment",setup(T){const l=h().meta.title,a=["image","video","icon"],n=y(a[0]);return(j,r)=>{const c=V,_=w,d=E;return m(),s("div",B,[e(d,{class:"box-card !border-none full-container",shadow:"never"},{default:o(()=>[i("div",C,[i("span",N,b(p(l)),1)]),e(_,{modelValue:n.value,"onUpdate:modelValue":r[0]||(r[0]=t=>n.value=t),"tab-position":"top"},{default:o(()=>[(m(),s(v,null,x(a,(t,u)=>e(c,{label:p(g)(t),name:t,key:u},{default:o(()=>[e(k,{scene:"attachment",type:t},null,8,["type"])]),_:2},1032,["label","name"])),64))]),_:1},8,["modelValue"])]),_:1})])}}});export{it as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
@charset "UTF-8";[data-v-ab587b59] .terminal .t-log-box span{white-space:pre-wrap}.table-head-bg[data-v-ab587b59]{background-color:var(--el-table-header-bg-color)}[data-v-ab587b59] .number-of-steps .el-step__line{margin:0 25px;background:#dddddd}[data-v-ab587b59] .number-of-steps .el-step__head{margin-top:10px}[data-v-ab587b59] .number-of-steps .is-success{color:var(--el-color-primary);border-color:var(--el-color-primary)}[data-v-ab587b59] .number-of-steps .is-success .el-step__icon{background:var(--el-color-primary);color:#fff}[data-v-ab587b59] .number-of-steps .is-success .el-step__icon i{color:#fff}[data-v-ab587b59] .number-of-steps .is-success .el-step__line{margin:0 25px;background:var(--el-color-primary)}[data-v-ab587b59] .number-of-steps .is-finish{color:var(--el-color-primary);border-color:var(--el-color-primary)}[data-v-ab587b59] .number-of-steps .is-finish .el-step__icon{background:var(--el-color-primary)!important;color:#fff!important}[data-v-ab587b59] .number-of-steps .is-finish .el-step__icon i{color:#fff}[data-v-ab587b59] .number-of-steps .is-finish .el-step__line{margin:0 25px;background:var(--el-color-primary)}[data-v-ab587b59] .number-of-steps .is-process{color:var(--el-color-primary);font-weight:inherit}[data-v-ab587b59] .number-of-steps .is-process .el-step__icon{padding:10px;border:1px solid var(--el-color-primary);background:var(--el-color-primary)!important;color:#fff!important}[data-v-ab587b59] .number-of-steps .is-wait{color:#333}[data-v-ab587b59] .el-result__icon{color:unset!important}[data-v-ab587b59] .el-result__title p{font-size:25px;color:#1d1f3a;font-weight:500}[data-v-ab587b59] .el-result__subtitle p{font-size:15px;color:#4f516d;font-weight:500;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical}.multi-hidden[data-v-ab587b59]{word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{d as b,r as d,n as w,I as m,l as g,R as c,h as E,s as F,w as i,e as n,a,Z as N,i as R,_ as j,aG as B,L as C,M as I,N as O}from"./index-981069db.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css */const k={class:"flex items-center"},D=a("span",{class:"ml-[10px] el-form-item__label"},"消费折扣",-1),M={class:"w-[120px]"},U=a("div",{class:"text-sm text-gray-400 mb-[5px]"},"会员购买产品默认折扣,需要商品设置参与会员折扣有效",-1),q=b({__name:"benefits-discount",props:{modelValue:{type:Object,default:()=>({})}},emits:["update:modelValue"],setup(p,{expose:_,emit:f}){const v=p,e=d({is_use:0,discount:""}),r=d(null),x=w({discount:[{validator:(l,t,s)=>{e.value.is_use&&(m.empty(e.value.discount)&&s("请输入折扣"),m.decimal(e.value.discount,1)||s("折扣格式错误"),(parseFloat(e.value.discount)<0||parseFloat(e.value.discount)>9.9)&&s("折扣只能输入0~9.9之间的值"),e.value.discount<0&&s("折扣不能小于0")),s()}}]}),o=g({get(){return v.modelValue},set(l){f("update:modelValue",l)}});return c(()=>o.value,(l,t)=>{(!t||!Object.keys(t).length)&&Object.keys(l).length&&(e.value=o.value)},{immediate:!0}),c(()=>e.value,()=>{o.value=e.value},{deep:!0}),_({verify:async()=>{var t;let l=!0;return await((t=r.value)==null?void 0:t.validate(s=>{l=s})),l}}),(l,t)=>{const s=B,V=C,h=I,y=O;return E(),F(y,{ref_key:"formRef",ref:r,model:e.value,rules:x},{default:i(()=>[n(h,{label:"",prop:"discount",class:"!mb-[10px]"},{default:i(()=>[a("div",null,[a("div",k,[n(s,{modelValue:e.value.is_use,"onUpdate:modelValue":t[0]||(t[0]=u=>e.value.is_use=u),"true-label":1,"false-label":0,label:"",size:"large"},null,8,["modelValue"]),D,N(a("div",M,[n(V,{modelValue:e.value.discount,"onUpdate:modelValue":t[1]||(t[1]=u=>e.value.discount=u),modelModifiers:{trim:!0},clearable:""},{append:i(()=>[R("折")]),_:1},8,["modelValue"])],512),[[j,e.value.is_use]])]),U])]),_:1})]),_:1},8,["model","rules"])}}});export{q as default};

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