This commit is contained in:
全栈小学生 2025-09-13 10:24:40 +08:00
parent 804537dc10
commit 5b0dfeee91
35 changed files with 1186 additions and 70 deletions

68
admin/src/app/api/app.ts Normal file
View File

@ -0,0 +1,68 @@
import request from '@/utils/request'
/**
* app配置
* @returns
*/
export function getAppConfig() {
return request.get('channel/app/config')
}
/**
* app配置
* @param params
* @returns
*/
export function setAppConfig(params: Record<string, any>) {
return request.put('channel/app/config', params, { showSuccessMessage: true })
}
export function getVersionList(params: Record<string, any>) {
return request.get('channel/app/version', { params })
}
export function getVersionInfo(id: number) {
return request.get(`channel/app/version/${id}`)
}
export function getAppPlatform() {
return request.get(`channel/app/platfrom`)
}
/**
*
* @param params
* @returns
*/
export function addVersion(params: Record<string, any>) {
return request.post('channel/app/version', params, { showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editVersion(params: Record<string, any>) {
return request.put(`channel/app/version/${ params.id }`, params, { showSuccessMessage: true })
}
/**
*
* @param siteId
*/
export function deleteVersion(params: Record<string, any>) {
return request.delete(`channel/app/version/${ params.id }`)
}
export function getBuildLog(key: string) {
return request.get(`channel/app/build/log/${ key }`)
}
export function releaseVersion(id: number) {
return request.put(`channel/app/version/${ id }/release`, {}, { showSuccessMessage: true })
}
export function generateSingCert(params: Record<string, any>) {
return request.post(`channel/app/generate_sing_cert`, params, { showSuccessMessage: true });
}

View File

@ -0,0 +1,13 @@
{
"accessFlow": "接入流程",
"versionManage": "版本管理",
"title": "APP端管理",
"appInlet": "App接入流程",
"uniappApp": "uni-app应用开通",
"appAttestation1": "点击进入Dcloud官网开发者后台,创建或选择应用并维护好应用平台信息",
"clickAccess": "点击接入",
"appSetting": "App端配置",
"settingInfo": "点击配置",
"releaseVersion": "发布版本",
"toCreate": "去创建"
}

View File

@ -0,0 +1,17 @@
{
"wechatAppInfo": "微信应用信息",
"wechatAppid": "微信移动应用AppID",
"wechatAppidTips": "用于app端 微信登录 微信支付 微信分享",
"wechatAppsecret": "微信移动应用AppSecret",
"appidPlaceholder": "请输入AppID",
"appSecretPlaceholder": "请输入AppSecret",
"appInfo": "应用信息",
"uniAppId": "uniapp应用id",
"uniAppIdTips": "uniapp应用id需在Dcloud开发者中心创建",
"toCreate": "前往Dcloud官网",
"appName": "应用名称",
"applicationId": "安卓应用包名",
"applicationIdTips": "安卓应用的包名是Android系统中用于唯一标识应用的字符串采用反向域名格式如com.example.myapp。每个应用在系统中拥有唯一的包名用于区分不同应用",
"androidAppKey": "安卓离线打包Key",
"androidAppKeyTips": "安卓离线打包Key在Dcloud开发者中心 - 应用管理 - 点击应用 - 各平台信息 创建以及查看离线AppKey"
}

View File

@ -0,0 +1,49 @@
{
"accessFlow": "接入流程",
"versionManage": "版本管理",
"versionCode":"版本号",
"versionCodePlaceholder":"请输入版本号",
"versionCodeTips": "应用版本号必须是整数取值范围1~2147483647;必须高于上一版本设置的值",
"versionName":"版本名称",
"versionNamePlaceholder":"请输入版本名称",
"versionDesc":"",
"versionDescPlaceholder":"请输入",
"icon":"应用图标",
"iconPlaceholder":"请输入应用图标",
"push":"消息推送图标",
"pushPlaceholder":"请输入消息推送图标",
"splash":"应用启动页图标",
"splashPlaceholder":"请输入应用启动页的图标",
"platform":"客户端",
"packagePath":"安装包路径",
"packagePathPlaceholder":"请输入安装包路径",
"status":"状态",
"statusPlaceholder":"请输入状态",
"addAppVersion":"添加版本",
"updateAppVersion":"编辑版本",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间",
"isForcedUpgrade": "强制升级",
"versionDesc": "更新内容",
"isForcedUpgradeTitle": "是否强制升级",
"releaseTime": "发布时间",
"release": "发布",
"resourceFile": "上传资源文件",
"androidResourceFileTips": "只能上传apk文件",
"iosResourceFileTips": "只能上传wgt文件",
"index": "序号",
"next": "下一步",
"prev": "上一步",
"certType": "证书类型",
"certFile": "证书文件",
"certAlias": "证书别名",
"certKeyPassword": "证书密码",
"certStorePassword": "证书库密码",
"publicCertTips": "niucloud提供的公共测试证书证书的描述信息都是测试数据任何人都可以使用仅适合应用开发期间体验测试使用",
"privateCertTips": "Android平台打包发布apk应用需要使用数字证书.keystore文件进行签名用于表明开发者身份。",
"download": "下载",
"failReason": "失败原因",
"appVersionReleaseTips": "发布后无法再对该版本进行修改,确定要发布该版本吗?",
"appVersionDeleteTips": "确定要删除该版本吗?",
"upgradeType": "升级方式"
}

View File

@ -7,5 +7,6 @@
"validTimeTips": "过期后将重新获取定位信息",
"validTimePlaceholder": "请输入定位有效期",
"validTimeFormatTips": "格式输入错误",
"validTimeNotZeroTips": "定位有效期不能小于5分钟"
}
"validTimeNotZeroTips": "定位有效期不能小于5分钟",
"aMapKey": "高德地图KEY"
}

View File

@ -6,7 +6,7 @@
<template v-if="Object.keys(marketingList).length">
<template v-for="(item, index) in marketingList" :key="index + 'b'">
<div class="flex justify-between items-center">
<div class="flex justify-between items-center" v-if="item.list.length > 0">
<span class="text-page-title">{{ item.title }}</span>
</div>

View File

@ -3,9 +3,9 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<!-- <div class="flex justify-between items-center">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div> -->
</div>
<div class="flex justify-between items-center mt-[20px]">
<el-form :inline="true" :model="roleTableData.searchParam" ref="searchFormRef">

View File

@ -6,9 +6,7 @@
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="mt-[20px]">
<el-tab-pane :label="t('管理员')" name="userList">
<div class="flex justify-between items-center mt-[20px]">
<div class="flex justify-between items-center mt-[20px]">
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef">
<el-form-item :label="t('accountNumber')" prop="search">
<el-input v-model.trim="userTableData.searchParam.search" class="input-width" :placeholder="t('accountNumberPlaceholder')" />
@ -84,11 +82,14 @@
@size-change="loadUserList()" @current-change="loadUserList" />
</div>
</div>
<!-- <el-tabs v-model="activeName" class="mt-[20px]">
<el-tab-pane :label="t('管理员')" name="userList">
</el-tab-pane>
<el-tab-pane :label="t('管理员角色')" name="userRole">
<userRole></userRole>
</el-tab-pane>
</el-tabs>
</el-tabs> -->
<edit-user ref="editUserDialog" @complete="loadUserList()" />
</el-card>
</div>

View File

@ -0,0 +1,130 @@
<template>
<!--微信公众号-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('accessFlow')" name="/channel/app" />
<el-tab-pane :label="t('versionManage')" name="/channel/app/version" />
</el-tabs>
<div class="p-[20px]">
<h3 class="panel-title !text-sm">{{ t("appInlet") }}</h3>
<el-row>
<el-col :span="20">
<el-steps class="!mt-[10px]" :active="3" direction="vertical">
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("uniappApp") }}
</p>
</template>
<template #description>
<span class="text-[#999]">{{ t("appAttestation1") }}</span>
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="linkEvent('https://dcloud.io/')">{{ t("toCreate") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("appSetting") }}
</p>
</template>
<template #description>
<!-- <span class="text-[#999]">{{ t("wechatSetting1") }}</span>-->
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" @click="router.push('/channel/app/config')">{{ t("settingInfo") }}</el-button>
</div>
</template>
</el-step>
<el-step>
<template #title>
<p class="text-[14px] font-[700]">
{{ t("versionManage") }}
</p>
</template>
<template #description>
<!-- <span class="text-[#999]">{{ t("wechatAccess") }}</span>-->
<div class="mt-[20px] mb-[40px] h-[32px]">
<el-button type="primary" plain @click="router.push('/channel/app/version')">{{ t("releaseVersion") }}</el-button>
</div>
</template>
</el-step>
</el-steps>
</el-col>
</el-row>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { getWechatConfig } from '@/app/api/wechat'
import { getAuthorizationUrl } from '@/app/api/wxoplatform'
import { getWxoplatform } from '@/app/api/sys'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/app')
const qrcode = ref('')
const wechatConfig = ref({})
const oplatformConfig = ref({})
const onShowGetWechatConfig = async () => {
await getWechatConfig().then(({ data }) => {
wechatConfig.value = data
qrcode.value = data.qr_code
})
}
onMounted(async () => {
await onShowGetWechatConfig()
await getWxoplatform().then(({ data }) => {
oplatformConfig.value = data
})
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
onShowGetWechatConfig()
}
})
})
onUnmounted(() => {
document.removeEventListener('visibilitychange', () => {
})
})
const linkEvent = (url: string) => {
window.open(url, '_blank')
}
const handleClick = (val: any) => {
router.push({ path: activeName.value })
}
const authBindWechat = () => {
getAuthorizationUrl().then(({ data }) => {
window.open(data)
})
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,285 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateAppVersion') : t('addAppVersion')" width="60%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<div v-show="step == 1" class="h-[400px]">
<el-form-item :label="t('versionName')" prop="version_name">
<el-input v-model="formData.version_name" clearable :placeholder="t('versionNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('versionCode')" prop="version_code">
<el-input v-model="formData.version_code" clearable :placeholder="t('versionCodePlaceholder')" class="input-width" />
<div class="form-tip">{{ t('versionCodeTips') }}</div>
</el-form-item>
<el-form-item :label="t('versionDesc')" prop="version_desc">
<el-input v-model="formData.version_desc" type="textarea" rows="6" clearable :placeholder="t('versionDescPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('platform')" prop="platform">
<el-radio-group v-model="formData.platform">
<el-radio :label="key" size="large" v-for="(item, key) in appPlatform">{{ item }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('isForcedUpgrade')" prop="is_forced_upgrade">
<el-switch v-model="formData.is_forced_upgrade" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
</div>
<div v-show="step == 2" class="h-[400px]">
<el-scrollbar>
<el-form-item :label="t('upgradeType')">
<el-radio-group v-model="formData.upgrade_type">
<el-radio label="app" size="large">APP整包升级</el-radio>
<el-radio label="hot" size="large">wgt资源包升级</el-radio>
<el-radio label="market" size="large">应用市场升级</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('resourceFile')" v-show="formData.upgrade_type == 'app'">
<el-radio-group v-model="formData.package_type">
<el-radio label="file" size="large">上传资源包</el-radio>
<el-radio label="cloud" size="large">云打包</el-radio>
</el-radio-group>
</el-form-item>
<div v-show="formData.package_type == 'file' && formData.upgrade_type != 'market'">
<el-form-item label="" prop="package_path">
<div class="input-width" >
<upload-file v-model="formData.package_path" :accept="accept" api="sys/document/app_package"></upload-file>
</div>
<div class="form-tip" v-if="formData.upgrade_type == 'app'">{{ t('androidResourceFileTips') }}</div>
<div class="form-tip" v-if="formData.upgrade_type == 'hot'">{{ t('iosResourceFileTips') }}</div>
</el-form-item>
</div>
<div v-show="formData.upgrade_type == 'market'">
<el-form-item label="应用市场链接" prop="package_path">
<el-input v-model="formData.package_path" clearable class="input-width" />
</el-form-item>
</div>
<div v-show="formData.package_type == 'cloud'">
<el-form-item :label="t('icon')">
<div class="input-width" >
<upload-file v-model="formData.build.icon" accept=".zip" api="sys/document/applet"></upload-file>
</div>
<div class="form-tip !leading-[1.5]">应用图标和启动界面图片 icon.png为应用的图标 push.png为推送消息的图标 splash.png为应用启动页的图标 将icon.pngpush.pngsplash.png放置到drawabledrawable-ldpidrawable-mdpidrawable-hdpidrawable-xhdpidrawable-xxhdpi文件夹下压缩成压缩包上传
具体详情可查看 <span class="text-primary cursor-pointer" @click="windowOpen('https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android.html')">uniapp App离线打包</span>配置应用图标和启动界面片段</div>
<div class="form-tip !leading-[1.5]">只支持上传.zip 在drawable的根目录进行压缩</div>
</el-form-item>
<el-form-item :label="t('certType')">
<el-radio-group v-model="formData.cert.type">
<el-radio label="public" size="large">公共证书</el-radio>
<el-radio label="private" size="large">自有证书</el-radio>
</el-radio-group>
<div class="form-tip">{{ t('publicCertTips') }}</div>
<div class="form-tip !leading-[1.5]">{{ t('privateCertTips') }}<span class="text-primary cursor-pointer" @click="windowOpen('https://ask.dcloud.net.cn/article/35777')">Android平台签名证书说明</span></div>
<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">
<div class="input-width" >
<upload-file v-model="formData.cert.file" accept="" api="sys/document/android_cert"></upload-file>
</div>
</el-form-item>
<el-form-item :label="t('certAlias')" prop="cert.key_alias">
<el-input v-model="formData.cert.key_alias" clearable :placeholder="t('versionDescPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('certKeyPassword')" prop="cert.key_password">
<el-input v-model="formData.cert.key_password" clearable :placeholder="t('versionDescPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('certStorePassword')" prop="cert.store_password">
<el-input v-model="formData.cert.store_password" clearable :placeholder="t('versionDescPlaceholder')" class="input-width" />
</el-form-item>
</div>
</div>
</el-scrollbar>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<view v-show="step == 1">
<el-button type="primary" class="ml-3" @click="step = 2">{{
t('next')
}}</el-button>
</view>
<view v-show="step == 2">
<el-button type="primary" class="ml-3" @click="step = 1">{{
t('prev')
}}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
</view>
</span>
</template>
</el-dialog>
<generate-sing-cert ref="generateSingCertRef"/>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addVersion, editVersion, getVersionInfo, getAppPlatform } from '@/app/api/app'
import GenerateSingCert from '@/app/views/channel/app/components/generate-sing-cert.vue'
const showDialog = ref(false)
const loading = ref(false)
const appPlatform = ref({})
const step = ref(1)
const generateSingCertRef = ref(null)
const getAppPlatformFn = async () => {
await getAppPlatform().then(({ data }) => {
appPlatform.value = data
initialFormData.platform = Object.keys(data)[0]
})
}
getAppPlatformFn()
const accept = computed(() => {
if (formData.upgrade_type == 'app') return '.apk'
if (formData.upgrade_type == 'hot') return '.wgt'
return ''
})
/**
* 表单数据
*/
const initialFormData = {
id: '',
version_code: '',
version_name: '',
version_desc: '',
platform: '',
is_forced_upgrade: 0,
package_path: '',
package_type: 'file',
upgrade_type: 'app',
build: {
icon: '',
},
cert: {
type: 'public',
key_alias: '',
key_password: '',
store_password: ''
}
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
watch(() => formData.upgrade_type, () => {
if (formData.upgrade_type == 'app' || formData.upgrade_type == 'hot') {
formData.package_type = 'file'
}
formData.package_path = ''
formData.cert.type = 'public'
})
//
const formRules = computed(() => {
return {
version_code: [
{ required: true, message: t('versionCodePlaceholder'), trigger: 'blur' },
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (isNaN(value) || !/^\d{0,10}$/.test(value)) {
callback(new Error(t('versionCodeTips')))
} else if (value < 0) {
callback(new Error(t('versionCodeTips')))
} else {
callback()
}
}
}
],
version_name: [
{ required: true, message: t('versionNamePlaceholder'), trigger: 'blur' }
],
package_path: [
{ required: formData.upgrade_type != 'market' && formData.package_type == 'file', message: '请上传资源文件', trigger: 'blur' },
{ required: formData.upgrade_type == 'market', message: '请输入应用市场链接', trigger: 'blur' }
],
'build.icon': [
{ required: formData.package_type == 'cloud', message: '请上传图标文件', trigger: 'blur' },
],
'cert.cert_file': [
{ required: formData.package_type == 'cloud' && formData.cert.type == 'private', message: '请上传证书文件', trigger: 'blur' }
],
'cert.key_alias': [
{ required: formData.package_type == 'cloud' && formData.cert.type == 'private', message: '请输入证书别名', trigger: 'blur' }
],
'cert.key_password': [
{ required: formData.package_type == 'cloud' && formData.cert.type == 'private', message: '请上传证书密码', trigger: 'blur' }
],
'cert.store_password': [
{ required: formData.package_type == 'cloud' && formData.cert.type == 'private', message: '请上传证书库密码', trigger: 'blur' }
]
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
const save = formData.id ? editVersion : addVersion
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
save(formData).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(() => {
loading.value = false
})
}
})
}
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getVersionInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
loading.value = false
}
watch(() => showDialog.value, () => {
step.value = 1
})
const windowOpen = (url: string) => {
window.open(url)
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

View File

@ -0,0 +1,156 @@
<template>
<el-dialog v-model="showDialog" title="生成Android证书" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item label="证书别名" prop="key_alias">
<el-input v-model="formData.key_alias" clearable placeholder="" class="input-width" />
<div class="form-tip">只支持字母从证书文件中读取证书时需要别名</div>
</el-form-item>
<el-form-item label="证书密码" prop="key_password">
<el-input v-model="formData.key_password" clearable placeholder="" class="input-width" />
<div class="form-tip">只支持字母或数字密码至少 6 设置好后请牢记密码</div>
</el-form-item>
<el-form-item label="证书库密码" prop="store_password">
<el-input v-model="formData.store_password" clearable placeholder="" class="input-width" />
</el-form-item>
<el-form-item label="有效期" prop="limit">
<div class="flex items-center">
<el-input v-model="formData.limit" clearable placeholder="" class="w-[100px]" />
<div class="form-tip ml-2"></div>
</div>
<div class="form-tip"> 1 - 100 年之间</div>
</el-form-item>
<div class="text-primary cursor-pointer pl-[120px] my-[10px]" @click="moreInfo = !moreInfo">
{{ moreInfo ? '点击收起' : '点击展开填写更多信息 '}}
</div>
<view v-show="moreInfo">
<el-form-item label="域名">
<el-input v-model="formData.cn" clearable placeholder="" class="input-width" />
</el-form-item>
<el-form-item label="组织名称">
<el-input v-model="formData.o" clearable placeholder="" class="input-width" />
<div class="form-tip">如公司名称或者其他名称</div>
</el-form-item>
<el-form-item label="部门">
<el-input v-model="formData.ou" clearable placeholder="" class="input-width" />
<div class="form-tip">部门名称 IT 研发部等</div>
</el-form-item>
<el-form-item label="国家地区">
<el-input v-model="formData.c" clearable placeholder="" class="input-width" />
<div class="form-tip">输入国家/地区代号两个字母中国为CN</div>
</el-form-item>
<el-form-item label="省份">
<el-input v-model="formData.st" clearable placeholder="" class="input-width" />
<div class="form-tip">所在省份名称如Beijing</div>
</el-form-item>
<el-form-item label="城市">
<el-input v-model="formData.l" clearable placeholder="" class="input-width" />
<div class="form-tip">所在城市名称如Beijing</div>
</el-form-item>
</view>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">生成</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import type { FormInstance } from 'element-plus'
import { generateSingCert } from '@/app/api/app'
import { img } from '@/utils/common'
const showDialog = ref(false)
const moreInfo = ref(false)
const loading = ref(false)
const initialFormData = {
key_alias: '',
key_password: '',
store_password: '',
limit: 30,
cn: '',
o: '',
ou: '',
c: '',
st: '',
l: ''
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
key_alias: [
{ required: true, message: '请输入证书别名', trigger: 'blur' }
],
key_password: [
{ required: true, message: '请输入证书密码', trigger: 'blur' }
],
store_password: [
{ required: true, message: '请输入证书库密码', trigger: 'blur' }
],
limit: [
{ required: true, message: '请输入有效期', trigger: 'blur' },
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (isNaN(value) || !/^\d{0,10}$/.test(value)) {
callback(new Error('有效期必须是数字'))
} else if (value < 0) {
callback(new Error('有效期必须为 1 - 100 之间的数字'))
} else if (value > 100) {
callback(new Error('有效期必须为 1 - 100 之间的数字'))
} else {
callback()
}
}
}
],
organization_name: [
{ required: true, message: '请输入所有者', trigger: 'blur' }
]
}
})
const confirm = async (formEl: FormInstance | undefined) => {
if (formEl) {
await formEl.validate()
loading.value = true
generateSingCert(formData).then(res => {
loading.value = false
showDialog.value = false
window.open(img(res.data), '_blank')
})
}
}
const open = async (row: any = null) => {
Object.assign(formData, initialFormData)
showDialog.value = true
}
defineExpose({
open
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,129 @@
<template>
<!--小程序配置-->
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="170px" ref="formRef" :rules="formRules" v-loading="loading">
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('appInfo') }}</h3>
<el-form-item :label="t('uniAppId')" prop="uni_app_id">
<el-input v-model.trim="formData.uni_app_id" placeholder="" class="input-width" clearable/>
<div class="form-tip flex items-center">
{{ t('uniAppIdTips') }}
<el-button link type="primary" @click="windowOpen('https://www.dcloud.io/')">{{ t('toCreate') }}</el-button>
</div>
</el-form-item>
<el-form-item :label="t('appName')" prop="app_name">
<el-input v-model.trim="formData.app_name" placeholder="" class="input-width" clearable/>
</el-form-item>
<el-form-item :label="t('androidAppKey')" prop="android_app_key">
<el-input v-model.trim="formData.android_app_key" placeholder="" class="input-width" clearable/>
<div class="form-tip">
{{ t('androidAppKeyTips') }}
<span class="text-primary cursor-pointer" @click="windowOpen('https://nativesupport.dcloud.net.cn/AppDocs/usesdk/appkey.html')">查看详情</span>
</div>
</el-form-item>
<el-form-item :label="t('applicationId')" prop="application_id">
<el-input v-model.trim="formData.application_id" placeholder="" class="input-width" clearable/>
<div class="form-tip">
{{ t('applicationIdTips') }}
</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<h3 class="panel-title !text-sm">{{ t('wechatAppInfo') }}</h3>
<el-form-item :label="t('wechatAppid')" prop="app_id">
<el-input v-model.trim="formData.wechat_app_id" :placeholder="t('appidPlaceholder')" class="input-width" clearable/>
<div class="form-tip">
{{ t('wechatAppidTips') }}
</div>
</el-form-item>
<el-form-item :label="t('wechatAppsecret')" prop="app_secret">
<el-input v-model.trim="formData.wechat_app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
</el-form-item>
</el-card>
</el-form>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, watch, computed } from 'vue'
import { t } from '@/lang'
import { getAppConfig, setAppConfig } from '@/app/api/app'
import { FormInstance } from "element-plus"
import { useRoute, useRouter } from "vue-router"
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const loading = ref(true)
const formData = reactive<Record<string, any>>({
uni_app_id: '',
app_name: '',
android_app_key: '',
application_id: '',
wechat_app_id: '',
wechat_app_secret: ''
})
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
}
})
/**
* 获取app配置
*/
getAppConfig().then(res => {
Object.assign(formData, res.data)
loading.value = false
})
/**
* 保存
*/
const save = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
setAppConfig(formData).then(() => {
loading.value = false
}).catch(() => {
loading.value = false
})
}
})
}
const windowOpen = (url: string) => {
window.open(url)
}
const back = () => {
router.push('/channel/app')
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,237 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span>
</div>
<el-tabs v-model="activeName" class="my-[20px]" @tab-change="handleClick">
<el-tab-pane :label="t('accessFlow')" name="/channel/app" />
<el-tab-pane :label="t('versionManage')" name="/channel/app/version" />
</el-tabs>
<el-alert type="info">
<template #default>
<div class="flex items-center">
<div>
<p>使用云打包提交成功后请先不要离开该页面稍待几分钟等待打包结果的返回</p>
</div>
</div>
</template>
</el-alert>
<div class="mt-[20px]">
<el-button type="primary" @click="addEvent">{{ t('addAppVersion') }}</el-button>
</div>
<div class="mt-[10px]">
<el-table :data="appVersionTable.data" size="large" v-loading="appVersionTable.loading">
<template #empty>
<span>{{ !appVersionTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column type="index" width="90" :label="t('index')" />
<el-table-column prop="version_code" :label="t('versionCode')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="version_name" :label="t('versionName')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="version_desc" :label="t('versionDesc')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="platform_name" :label="t('platform')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="status_name" :label="t('status')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="status" :label="t('isForcedUpgradeTitle')" min-width="120" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
{{ row.is_forced_upgrade ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column prop="package_path" :label="t('packagePath')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('releaseTime')" min-width="120" :show-overflow-tooltip="true">
<template #default="{ row }">
<text v-if="row.release_time != 0">
{{ row.release_time }}
</text>
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="200px">
<template #default="{ row }">
<el-button type="primary" link v-if="row.release_time == 0" @click="editEvent(row)">{{ t('edit') }}</el-button>
<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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="appVersionTable.page" v-model:page-size="appVersionTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="appVersionTable.total"
@size-change="loadAppVersionList()" @current-change="loadAppVersionList" />
</div>
</div>
<edit ref="editAppVersionDialog" @complete="loadAppVersionList" />
</el-card>
<el-dialog v-model="failReasonDialogVisible" :title="t('failReason')" width="60%">
<el-scrollbar class="h-[60vh] w-full whitespace-pre-wrap p-[20px]">
<div v-html="failReason"></div>
</el-scrollbar>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { getVersionList, getBuildLog, deleteVersion, releaseVersion } from '@/app/api/app'
import Edit from '@/app/views/channel/app/components/app-version-edit.vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/app/version')
const appVersionTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
platfrom: ''
}
})
const handleClick = (val: any) => {
router.push({ path: activeName.value })
}
const searchFormRef = ref<FormInstance>()
/**
* 获取app版本管理列表
*/
const loadAppVersionList = (page: number = 1) => {
appVersionTable.loading = true
appVersionTable.page = page
getVersionList({
page: appVersionTable.page,
limit: appVersionTable.limit,
...appVersionTable.searchParam
}).then(res => {
appVersionTable.loading = false
appVersionTable.data = res.data.data
appVersionTable.total = res.data.total
if (page == 1 && appVersionTable.data.length && appVersionTable.data[0].status == 'creating') getAppBuildLogFn(appVersionTable.data[0].task_key)
}).catch(() => {
appVersionTable.loading = false
})
}
loadAppVersionList()
const editAppVersionDialog: Record<string, any> | null = ref(null)
/**
* 添加app版本管理
*/
const addEvent = () => {
editAppVersionDialog.value.setFormData()
editAppVersionDialog.value.showDialog = true
}
/**
* 编辑app版本管理
* @param data
*/
const editEvent = (data: any) => {
editAppVersionDialog.value.setFormData(data)
editAppVersionDialog.value.showDialog = true
}
/**
* 删除app版本管理
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('appVersionDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteVersion({ id }).then(() => {
loadAppVersionList()
}).catch(() => {
})
})
}
const releaseEvent = (data: any) => {
ElMessageBox.confirm(t('appVersionReleaseTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
releaseVersion(data.id).then(() => {
loadAppVersionList()
}).catch(() => {
})
})
}
const getAppBuildLogFn = (key: string) => {
getBuildLog(key).then(res => {
if (res.data) {
if (res.data.status == '') {
setTimeout(() => {
getAppBuildLogFn(key)
}, 2000)
} else {
loadAppVersionList()
}
}
})
}
const failReason = ref('')
const failReasonDialogVisible = ref(false)
const handleFailReason = (data: any) => {
failReason.value = data.fail_reason
failReasonDialogVisible.value = true
}
const downloadEvent = (data: any) => {
window.open(img(data.package_path), '_blank')
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadAppVersionList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

View File

@ -250,10 +250,6 @@ getWeappConfig().then(res => {
loading.value = false
})
getWeappConfig().then(res => {
Object.assign(res.data)
})
/**
* 复制
*/

View File

@ -185,7 +185,7 @@
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="-100" class="ml-[10px] diy-nav-slider" />
</el-form-item>
<el-form-item :label="t('marginBottom')" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] diy-nav-slider" />
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] diy-nav-slider" :min="-100" />
</el-form-item>
<el-form-item :label="t('marginBoth')" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] diy-nav-slider" />

View File

@ -256,7 +256,7 @@ const editEvent = (data: any) => {
// 使
const setUse = (id: any) => {
setUseDiyPage({ id }).then(() => {
loadDiyPageList()
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page)
})
}
const repeat = ref(false)
@ -275,7 +275,7 @@ const copyEvent = (id: any) => {
copyDiy({ id }).then((res: any) => {
if (res.code == 1) {
loadDiyPageList()
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page)
}
repeat.value = false
}).catch(err => {
@ -294,7 +294,7 @@ const deleteEvent = (id: number) => {
}
).then(() => {
deleteDiyPage(id).then(() => {
loadDiyPageList()
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page)
}).catch(() => {
})
})
@ -358,7 +358,7 @@ const shareEvent = async (formEl: FormInstance | undefined) => {
id: shareFormId.value,
share: JSON.stringify(shareFormData)
}).then(() => {
loadDiyPageList()
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page)
shareDialogVisible.value = false
}).catch(() => {
})

View File

@ -159,10 +159,10 @@
<spread-popup ref="spreadPopupRef" />
<!-- 表单提交成功页弹出框 -->
<form-submit-popup ref="formSubmitPopupRef" @complete="loadDiyFormList" />
<form-submit-popup ref="formSubmitPopupRef" @complete="loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)" />
<!-- 表单填写设置弹出框 -->
<form-write-popup ref="formWritePopupRef" @complete="loadDiyFormList" />
<form-write-popup ref="formWritePopupRef" @complete="loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)" />
<records-detail ref="recordsDetailDialog"/>
@ -352,7 +352,7 @@ const copyEvent = (id: any) => {
copyForm({ form_id: id }).then((res: any) => {
if (res.code == 1) {
loadDiyFormList()
loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)
}
repeat.value = false
}).catch(() => {
@ -371,7 +371,7 @@ const deleteEvent = (form_id: number) => {
}
).then(() => {
deleteDiyForm({ form_ids: [form_id] }).then(() => {
loadDiyFormList()
loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)
}).catch(() => {
})
})
@ -438,7 +438,7 @@ const batchDeleteForms = () => {
deleteDiyForm({
form_ids
}).then(() => {
loadDiyFormList()
loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)
repeat.value = false
}).catch(() => {
repeat.value = false
@ -497,7 +497,7 @@ const shareEvent = async (formEl: FormInstance | undefined) => {
form_id: shareFormId.value,
share: JSON.stringify(shareFormData)
}).then(() => {
loadDiyFormList()
loadDiyFormList(getTablePageStorage(diyFormTableData.searchParam).page)
shareDialogVisible.value = false
}).catch(() => {
})

View File

@ -307,22 +307,18 @@ const newVersion = ref<NewVersion>({
//
const appList = ref<any>([])
const getAppIndexFn = () => {
loading.value = true
getAppIndex().then((res) => {
console.log(res)
appList.value = res.data
loading.value = false
})
}
getAppIndexFn()
const bannerlistr = ref<any>([])
const getAdvListFn = () => {
getAdvList().then((res) => {
console.log(res.data)
bannerlistr.value = res.data
})
}
getAdvListFn()
const getInfoFn = () => {
if (copyright.value.copyright_desc) {
dialogVisible.value = true
@ -349,9 +345,8 @@ const getStatInfoFn = async() => {
setTimeout(() => {
drawChart()
}, 20)
loading.value = false
}
getStatInfoFn()
// 线
const drawChart = () => {
@ -494,6 +489,25 @@ onMounted(() => {
showQuickStart.value = localStorage.getItem('showQuickStart') !== 'false'
showNiuCloud.value = localStorage.getItem('showNiuCloud') !== 'false'
showBanner.value = localStorage.getItem('showBanner') !== 'false'
//
const initData = async () => {
loading.value = true;
try {
await Promise.all([
getStatInfoFn(),
getAdvListFn(),
getAppIndexFn()
]);
loading.value = false;
} catch (error) {
console.error('初始化失败', error);
loading.value = false;
}
};
//
initData();
})
const closeModule = (module:any) => {

View File

@ -121,7 +121,7 @@ const formRules = computed(() => {
if (!value) return callback()
//
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
const reg = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
if (!reg.test(value)) {
callback(new Error('请输入正确的身份证号'))
} else {

View File

@ -147,7 +147,7 @@ const deleteEvent = (id: number) => {
}
).then(() => {
deleteMemberLevel(id).then(() => {
loadMemberLevelList()
loadMemberLevelList(getTablePageStorage(memberLevelTableData.searchParam).page);
}).catch(() => {
})
})

View File

@ -225,7 +225,7 @@ const modifyPosterStatusFn = (id:any, status:any) => {
modifyPosterStatus({
id, status
}).then((res) => {
loadPosterPageList()
loadPosterPageList(getTablePageStorage(posterTableData.searchParam).page)
isRepeat.value = false
})
}
@ -237,7 +237,7 @@ const modifyPosterDefaultFn = (id:any) => {
modifyPosterDefault({
id
}).then((res) => {
loadPosterPageList()
loadPosterPageList(getTablePageStorage(posterTableData.searchParam).page)
isRepeat.value = false
})
}
@ -254,7 +254,7 @@ const deleteEvent = (id: number) => {
if (isRepeat.value) return
isRepeat.value = true
deletePoster(id).then(() => {
loadPosterPageList()
loadPosterPageList(getTablePageStorage(posterTableData.searchParam).page)
isRepeat.value = false
}).catch(() => {
isRepeat.value = false

View File

@ -129,7 +129,7 @@ const modifyPrinterStatusEvent = (printer_id: any, status: any) => {
printer_id,
status
}).then((res) => {
loadPrinterList()
loadPrinterList(getTablePageStorage(printerTable.searchParam).page)
isRepeat.value = false
})
}
@ -163,7 +163,7 @@ const deleteEvent = (id: number) => {
if (repeat.value) return
repeat.value = true
deletePrinter(id).then(() => {
loadPrinterList()
loadPrinterList(getTablePageStorage(printerTable.searchParam).page)
repeat.value = false
}).catch(() => {
repeat.value = false
@ -214,7 +214,7 @@ const refreshTokenEvent = (printer_id: any) => {
if (repeat.value) return
repeat.value = true
refreshPrinterToken(printer_id).then((res: any) => {
loadPrinterList()
loadPrinterList(getTablePageStorage(printerTable.searchParam).page)
repeat.value = false
}).catch(() => {
repeat.value = false

View File

@ -148,7 +148,7 @@ const deleteEvent = (id: number) => {
}
).then(() => {
deletePrinterTemplate(id).then(() => {
loadPrinterTemplateList()
loadPrinterTemplateList(getTablePageStorage(printerTemplateTable.searchParam).page)
})
})
}

View File

@ -22,15 +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>
</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>
</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>
</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>
</el-form-item>
</div>
</el-card>

View File

@ -10,7 +10,11 @@
<el-form-item :label="t('mapKey')" prop="key">
<el-input v-model.trim="formData.key" class="input-width" clearable />
<span class="ml-2 cursor-pointer tutorial-btn" @click="tutorialFn">{{ t('clickTutorial') }}</span>
<span class="ml-2 cursor-pointer secret-btn" @click="secretFn">{{ t('clickSecretKey') }}</span>
<span class="ml-2 cursor-pointer secret-btn" @click="secretFn('https://lbs.qq.com/dev/console/key/manage')">{{ t('clickSecretKey') }}</span>
</el-form-item>
<el-form-item :label="t('aMapKey')" prop="key">
<el-input v-model.trim="formData.amap_key" class="input-width" clearable />
<span class="ml-2 cursor-pointer secret-btn" @click="secretFn('https://lbs.amap.com/')">{{ t('clickSecretKey') }}</span>
</el-form-item>
<el-form-item :label="t('isOpen')" prop="is_open">
<el-switch v-model="formData.is_open" :active-value="1" :inactive-value="0" />
@ -42,6 +46,7 @@ const loading = ref(true)
const formRef = ref<FormInstance>()
const formData = reactive({
key: '',
amap_key: '',
is_open: 0,
valid_time: 0
})
@ -107,8 +112,8 @@ const tutorialFn = () => {
/**
* 点击访问腾讯地图
*/
const secretFn = () => {
window.open('https://lbs.qq.com/dev/console/key/manage')
const secretFn = (url: string) => {
window.open(url)
}
</script>

View File

@ -328,7 +328,7 @@ const deleteEvent = (id: number) => {
}
).then(() => {
deleteGenerateTable(id).then(() => {
loadGenerateTableList()
loadGenerateTableList(getTablePageStorage(codeTableData.searchParam).page)
}).catch(() => {
})
})
@ -378,7 +378,7 @@ const generateCreateFn = (id: any, generate_type: any) => {
codeTableData.loading = false
window.open(img(res.data.file), '_blank')
} else {
loadGenerateTableList()
loadGenerateTableList(getTablePageStorage(codeTableData.searchParam).page)
}
}).catch(() => {
codeTableData.loading = false

View File

@ -365,7 +365,10 @@ const getAttachmentList = debounce((page: number = 1) => {
attachment.data[i].image_list.push(img(res.data.data[i].thumb))
}
}
}).catch(() => {
}).catch((err) => {
if (prop.type == 'image' && err.response.status == 500) {
showElMessage({ message: 'php脚本内存不足请加大php配置中memory_limit的数值, <a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3249216" target="blank">点击查看相关手册</a>', type: 'error', dangerouslyUseHTMLString: true })
}
attachment.loading = false
})
})

View File

@ -23,6 +23,10 @@ const prop = defineProps({
api: {
type: String,
default: 'sys/document/document'
},
accept: {
type: String,
default: '.doc,.docx,.xml,.txt,.pem,.zip,.rar,.7z,.crt,.key,.xls,.xlsx'
}
})
@ -37,23 +41,27 @@ const value = computed({
}
})
const upload: Record<string, any> = {
action: `${import.meta.env.VITE_APP_BASE_URL}/${prop.api}`,
showFileList: false,
headers: {},
accept: '.doc,.docx,.xml,.txt,.pem,.zip,.rar,.7z,.crt,.key,.xls,.xlsx',
onSuccess: (response: any, uploadFile: UploadFile) => {
if (response.code != undefined && response.code != 1) {
ElMessage({ message: response.msg, type: 'error' })
return
}
value.value = response.data.url
ElMessage({ message: t('upload.success'), type: 'success' })
}
}
upload.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
upload.headers[import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY] = storage.get('siteId') || 0
const upload = computed(() => {
const headers: Record<string, any> = {}
headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
headers[import.meta.env.VITE_REQUEST_HEADER_SITEID_KEY] = storage.get('siteId') || 0
const baseURL = import.meta.env.VITE_APP_BASE_URL.substr(-1) == '/' ? import.meta.env.VITE_APP_BASE_URL : `${import.meta.env.VITE_APP_BASE_URL}/`
return {
action: `${baseURL}${prop.api}`,
showFileList: false,
accept: prop.accept,
headers,
onSuccess: (response: any, uploadFile: UploadFile) => {
if (response.code != undefined && response.code != 1) {
ElMessage({ message: response.msg, type: 'error' })
return
}
value.value = response.data.url
ElMessage({ message: t('upload.success'), type: 'success' })
}
}
})
</script>
<style lang="scss">

View File

@ -32,7 +32,7 @@
<!-- 面包屑导航 -->
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index" :to="route.path" class="inter">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

@ -23,7 +23,7 @@
<!-- 面包屑导航 -->
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index" :to="route.path" class="inter">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

@ -15,7 +15,7 @@
<!-- 面包屑导航 -->
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index" :to="route.path" class="inter">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

@ -15,7 +15,7 @@
<!-- 面包屑导航 -->
<div class="flex items-center h-full pl-[10px]">
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index" :to="route.path" class="inter">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

@ -16,7 +16,7 @@
<div class="flex items-center h-full pl-[10px]">
<el-breadcrumb separator="/">
<!-- :to="route.path" class="inter" 这种修改方式导致部分跳转不对需要重新调整菜单才可以 -->
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :to="route.path" class="inter" :key="index">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

@ -16,7 +16,7 @@
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
<el-breadcrumb separator="/">
<!-- :to="route.path" class="inter" 这种修改方式导致部分跳转不对需要重新调整菜单才可以 -->
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index" :to="route.path" class="inter">{{route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>

View File

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