Compare commits

...

15 Commits

Author SHA1 Message Date
李玉
6b2e9b51d5
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-12-08 06:11:03 +00:00
李玉
3502b6e878
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-12-01 08:25:48 +00:00
李玉
cf761aea98
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-11-24 03:36:12 +00:00
wang
59aeae7f5a
!17 修复AdminApiRouteGenerator类路径变量未正确解析的问题
Merge pull request !17 from Codyyuan/fix-route-generator-bug
2025-11-22 08:12:29 +00:00
yuanhao
3c2609221b 修复AdminApiRouteGenerator类路径变量未正确解析的问题 2025-11-20 15:12:26 +08:00
李玉
cdd869f49c
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-11-18 02:17:48 +00:00
全栈小学生
cf293a1dec up 2025-11-14 11:39:40 +08:00
李玉
81bb4682d5
add upgrade.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-11-13 07:52:44 +00:00
李玉
2168a82f8b
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2025-11-13 06:56:37 +00:00
CQ
b4563d004b 同步niucloud 2025-11-13 09:54:45 +08:00
CQ
ef43d9e616 同步admin 2025-11-13 09:44:49 +08:00
CQ
16a8825962 同步uni-app 2025-11-13 09:42:44 +08:00
CQ
57d110237b fix 2025-10-31 11:38:10 +08:00
CQ
567eea9d1c feat 2025-10-31 10:40:23 +08:00
CQ
a5390d475b feat 2025-10-31 10:40:06 +08:00
627 changed files with 12015 additions and 1887 deletions

View File

@ -24,7 +24,7 @@ niucloud-admin-saas是一款快速开发通用管理后台框架整体功能
### NIUCLOUD 框架截图
![](https://niucloud-bucket.oss-cn-beijing.aliyuncs.com/gitee_saas/saas/saas_kj1.png)
![](https://niucloud-bucket.oss-cn-beijing.aliyuncs.com/gitee_saas/saas/saas_kj2.png)
![](https://niucloud-bucket.oss-cn-beijing.aliyuncs.com/gitee_saas/saas/saas_kj3.png)
![](https://niucloud-bucket.oss-cn-beijing.aliyuncs.com/gitee_saas/saas/31f58ff2ca4c1b8421b4ad622921dfed.png)
![](https://niucloud-bucket.oss-cn-beijing.aliyuncs.com/gitee_saas/saas/saas_kj4.png)

143
admin/DEVELOPMENT_GUIDE.md Normal file
View File

@ -0,0 +1,143 @@
# NiuCloud Admin 开发规范
## 技术栈区分
本项目采用前后端分离架构,包含两个主要前端部分:
1. **PC端后台管理系统**
- 框架: Vue 3 + TypeScript + Vite
- UI组件库: Element Plus
- 状态管理: Pinia
- 样式处理: SCSS + Tailwind CSS
2. **移动端应用**
- 框架: uni-app + Vue 3 + TypeScript
- UI组件库: uview-plus
- 状态管理: Pinia
- 样式处理: SCSS + Windi CSS
## 关键组件使用规范
### 消息提示组件
**重要注意事项:请根据开发平台选择正确的消息提示组件!**
#### PC端 (admin目录)
- **必须使用Element Plus的消息提示组件**而不是uni-app的方法
- 主要组件包括:`ElMessage``ElMessageBox``ElNotification`
- 导入方式:`import { ElMessage, ElMessageBox } from 'element-plus'`
- 使用示例:
```typescript
import { ElMessage } from 'element-plus'
// 成功消息
ElMessage.success('操作成功')
// 错误消息
ElMessage.error('操作失败')
// 确认对话框
ElMessageBox.confirm('确定要执行此操作吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 用户点击确认后的逻辑
}).catch(() => {
// 用户点击取消后的逻辑
})
```
#### 移动端 (uni-app目录)
- **使用uni-app提供的API**进行消息提示
- 主要方法包括:`uni.showToast``uni.showModal``uni.showLoading`
- 使用示例:
```typescript
// 成功提示
uni.showToast({
title: '操作成功',
icon: 'success',
duration: 2000
})
// 模态对话框
uni.showModal({
title: '提示',
content: '确定要执行此操作吗?',
success: (res) => {
if (res.confirm) {
// 用户点击确认后的逻辑
}
}
})
```
## API请求规范
### PC端API请求
- 使用`@/utils/request.ts`封装的请求工具
- 支持`showSuccessMessage``showErrorMessage`选项控制消息显示
- 示例:
```typescript
import request from '@/utils/request'
// GET请求
export function getOrderList(params: Record<string, any>) {
return request.get('order/list', params)
}
// POST请求带成功消息
export function createOrder(params: Record<string, any>) {
return request.post('order/create', params, { showSuccessMessage: true })
}
```
### 移动端API请求
- 使用uni-app的`uni.request`或封装的请求工具
- 示例:
```typescript
// 发送请求
uni.request({
url: 'https://example.com/api/order/list',
method: 'GET',
data: {
page: 1,
limit: 10
},
success: (res) => {
// 处理成功响应
},
fail: (err) => {
// 处理请求失败
}
})
```
## 代码风格规范
1. **文件命名**
- 组件文件PascalCase`OrderList.vue`
- 普通文件kebab-case 或 camelCase`api-service.ts``commonUtils.ts`
2. **TypeScript规范**
- 为函数参数、返回值和重要变量添加明确的类型注解
- 使用接口 (interface) 定义复杂数据结构
- 避免 `any` 类型的滥用
3. **Vue组件规范**
- 使用 Vue 3 Composition API 和 `<script setup lang="ts">` 语法
- 组件样式建议使用 scoped 属性或 CSS Modules
## 国际化规范
- PC端使用Vue I18n进行国际化语言文件位于`src/lang`目录
- 移动端同样使用Vue I18n语言文件位于`src/app/locale`目录
- 使用`t('key')`函数获取翻译文本
## 其他重要规范
- 严格遵循RESTful API设计规范
- 统一处理API响应数据和错误情况
- 代码提交前确保通过TypeScript类型检查
- 组件开发遵循高内聚低耦合原则
- 优先复用现有组件和工具函数

View File

@ -9,12 +9,18 @@
"version": "1.0.0",
"dependencies": {
"@element-plus/icons-vue": "2.0.10",
"@fullcalendar/core": "^6.1.19",
"@fullcalendar/daygrid": "^6.1.19",
"@fullcalendar/interaction": "^6.1.19",
"@fullcalendar/vue3": "^6.1.19",
"@heroicons/vue": "^2.2.0",
"@highlightjs/vue-plugin": "2.1.0",
"@types/lodash-es": "4.17.6",
"@vueuse/core": "9.12.0",
"axios": "1.4.0",
"crypto-js": "4.1.1",
"css-color-function": "1.3.3",
"date-fns": "^4.1.0",
"day": "^0.0.2",
"echarts": "5.4.1",
"element-plus": "^2.7.4",
@ -963,6 +969,47 @@
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.1.6.tgz",
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A=="
},
"node_modules/@fullcalendar/core": {
"version": "6.1.19",
"resolved": "https://registry.npmmirror.com/@fullcalendar/core/-/core-6.1.19.tgz",
"integrity": "sha512-z0aVlO5e4Wah6p6mouM0UEqtRf1MZZPt4mwzEyU6kusaNL+dlWQgAasF2cK23hwT4cmxkEmr4inULXgpyeExdQ==",
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.19",
"resolved": "https://registry.npmmirror.com/@fullcalendar/daygrid/-/daygrid-6.1.19.tgz",
"integrity": "sha512-IAAfnMICnVWPjpT4zi87i3FEw0xxSza0avqY/HedKEz+l5MTBYvCDPOWDATpzXoLut3aACsjktIyw9thvIcRYQ==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.19"
}
},
"node_modules/@fullcalendar/interaction": {
"version": "6.1.19",
"resolved": "https://registry.npmmirror.com/@fullcalendar/interaction/-/interaction-6.1.19.tgz",
"integrity": "sha512-GOciy79xe8JMVp+1evAU3ytdwN/7tv35t5i1vFkifiuWcQMLC/JnLg/RA2s4sYmQwoYhTw/p4GLcP0gO5B3X5w==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.19"
}
},
"node_modules/@fullcalendar/vue3": {
"version": "6.1.19",
"resolved": "https://registry.npmmirror.com/@fullcalendar/vue3/-/vue3-6.1.19.tgz",
"integrity": "sha512-j5eUSxx0xIy3ADljo0f5B9PhjqXnCQ+7nUMPfsslc2eGVjp4F74YvY3dyd6OBbg13IvpsjowkjncGipYMQWmTA==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.19",
"vue": "^3.0.11"
}
},
"node_modules/@heroicons/vue": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/@heroicons/vue/-/vue-2.2.0.tgz",
"integrity": "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==",
"peerDependencies": {
"vue": ">= 3"
}
},
"node_modules/@highlightjs/vue-plugin": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/@highlightjs/vue-plugin/-/vue-plugin-2.1.0.tgz",
@ -2624,6 +2671,15 @@
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz",
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
},
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/day": {
"version": "0.0.2",
"resolved": "https://registry.npmmirror.com/day/-/day-0.0.2.tgz",
@ -5003,6 +5059,15 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",

View File

@ -10,12 +10,18 @@
},
"dependencies": {
"@element-plus/icons-vue": "2.0.10",
"@fullcalendar/core": "^6.1.19",
"@fullcalendar/daygrid": "^6.1.19",
"@fullcalendar/interaction": "^6.1.19",
"@fullcalendar/vue3": "^6.1.19",
"@heroicons/vue": "^2.2.0",
"@highlightjs/vue-plugin": "2.1.0",
"@types/lodash-es": "4.17.6",
"@vueuse/core": "9.12.0",
"axios": "1.4.0",
"crypto-js": "4.1.1",
"css-color-function": "1.3.3",
"date-fns": "^4.1.0",
"day": "^0.0.2",
"echarts": "5.4.1",
"element-plus": "^2.7.4",

View File

@ -18,7 +18,7 @@ export function getMemberList(params: Record<string, any>) {
* @returns
*/
export function getMemberInfo(id: number) {
return request.get(`member/member/${id}`);
return request.get(`member/member/${ id }`);
}
/**
@ -61,7 +61,7 @@ export function getRegisterChannelType(params: Record<string, any>) {
* @param member_id
*/
export function deleteMember(member_id: number) {
return request.delete(`member/member/${member_id}`, { showSuccessMessage: true })
return request.delete(`member/member/${ member_id }`, { showSuccessMessage: true })
}
/***************************************************** 会员标签 ****************************************************/
@ -81,7 +81,7 @@ export function getMemberLabelList(params: Record<string, any>) {
* @returns
*/
export function getMemberLabelInfo(label_id: number) {
return request.get(`member/label/${label_id}`);
return request.get(`member/label/${ label_id }`);
}
/**
@ -98,7 +98,7 @@ export function addMemberLabel(params: Record<string, any>) {
* @param params
*/
export function updateMemberLabel(params: Record<string, any>) {
return request.put(`member/label/${params.label_id}`, params, { showSuccessMessage: true })
return request.put(`member/label/${ params.label_id }`, params, { showSuccessMessage: true })
}
/**
@ -107,7 +107,7 @@ export function updateMemberLabel(params: Record<string, any>) {
* @returns
*/
export function deleteMemberLabel(label_id: number) {
return request.delete(`member/label/${label_id}`, { showSuccessMessage: true })
return request.delete(`member/label/${ label_id }`, { showSuccessMessage: true })
}
/**
@ -122,7 +122,7 @@ export function getMemberLabelAll() {
* @param params
*/
export function editMemberDetail(params: Record<string, any>) {
return request.put(`member/member/modify/${params.member_id}/${params.field}`, params, { showSuccessMessage: true })
return request.put(`member/member/modify/${ params.member_id }/${ params.field }`, params, { showSuccessMessage: true })
}
/**
@ -143,7 +143,7 @@ export function memberBatchModify(params: Record<string, any>) {
* @param change_type
*/
export function getChangeTypeList(change_type: string) {
return request.get(`member/account/change_type/${change_type}`)
return request.get(`member/account/change_type/${ change_type }`)
}
/**
@ -321,7 +321,7 @@ export function getBalanceStatus() {
*
*/
export function getAccountType(params: Record<string, any>) {
return request.get(`member/account/change_type/${params.account_type}`)
return request.get(`member/account/change_type/${ params.account_type }`)
}
@ -357,7 +357,7 @@ export function getCashOutList(params: Record<string, any>) {
* @param id
*/
export function getCashOutDetail(id: number) {
return request.get(`member/cash_out/${id}`, {})
return request.get(`member/cash_out/${ id }`, {})
}
/**
@ -365,14 +365,18 @@ export function getCashOutDetail(id: number) {
* @param params
*/
export function memberAudit(params: Record<string, any>) {
return request.put(`member/cash_out/audit/${params.id}/${params.action}`, params, { showSuccessMessage: true })
return request.put(`member/cash_out/audit/${ params.id }/${ params.action }`, params, { showSuccessMessage: true })
}
/**
*
* @param params
*/
export function memberCancel(params: Record<string, any>) {
return request.put(`member/cash_out/cancel/${params.id}`, params, { showSuccessMessage: true,showErrorMessage: true })
return request.put(`member/cash_out/cancel/${ params.id }`, params, {
showSuccessMessage: true,
showErrorMessage: true
})
}
@ -381,7 +385,7 @@ export function memberCancel(params: Record<string, any>) {
* @param params
*/
export function memberTransfer(params: Record<string, any>) {
return request.put(`member/cash_out/transfer/${params.id}`, params, { showSuccessMessage: true })
return request.put(`member/cash_out/transfer/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -389,14 +393,15 @@ export function memberTransfer(params: Record<string, any>) {
* @param params
*/
export function memberRemark(params: Record<string, any>) {
return request.put(`member/cash_out/remark/${params.id}`, params, { showSuccessMessage: true })
return request.put(`member/cash_out/remark/${ params.id }`, params, { showSuccessMessage: true })
}
/**
*
* @param id
*/
export function memberCheck(id: number) {
return request.put(`member/cash_out/check/${id}`, {}, { showSuccessMessage: true })
return request.put(`member/cash_out/check/${ id }`, {}, { showSuccessMessage: true })
}
/**
@ -404,7 +409,7 @@ export function memberCheck(id: number) {
* @param params
*/
export function editMemberStatus(params: Record<string, any>) {
return request.put(`member/setstatus/${params.status}`, params, { showSuccessMessage: true })
return request.put(`member/setstatus/${ params.status }`, params, { showSuccessMessage: true })
}
/**
@ -453,6 +458,7 @@ export function getGrowthRuleDict() {
export function getPointRuleDict() {
return request.get(`member/dict/point_rule`)
}
/***************************************************** 会员等级 ****************************************************/
/**
@ -470,7 +476,7 @@ export function getMemberLevelPageList(params: Record<string, any>) {
* @returns
*/
export function getMemberLevelInfo(level_id: number) {
return request.get(`member/level/${level_id}`);
return request.get(`member/level/${ level_id }`);
}
/**
@ -487,7 +493,7 @@ export function addMemberLevel(params: Record<string, any>) {
* @param params
*/
export function updateMemberLevel(params: Record<string, any>) {
return request.put(`member/level/${params.level_id}`, params, { showSuccessMessage: true })
return request.put(`member/level/${ params.level_id }`, params, { showSuccessMessage: true })
}
/**
@ -496,7 +502,7 @@ export function updateMemberLevel(params: Record<string, any>) {
* @returns
*/
export function deleteMemberLevel(level_id: number) {
return request.delete(`member/level/${level_id}`, { showSuccessMessage: true })
return request.delete(`member/level/${ level_id }`, { showSuccessMessage: true })
}
/**
@ -512,14 +518,14 @@ export function getMemberLevelAll() {
*
*/
export function getMemberBenefitsContent() {
return request.get(`member/benefits/content`);
return request.post(`member/benefits/content`);
}
/**
*
*/
export function getMemberGiftsContent(params: Record<string, any>) {
return request.get(`member/gifts/content`, { params });
return request.post(`member/gifts/content`, params);
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

View File

@ -516,7 +516,7 @@ const open = (addonKey: string = '', callback = null) => {
active.value = 'upgrade'
if (callback) callback()
} else {
if (addonKey && frameworkVersion.value != newFrameworkVersion.value) {
if (addonKey && addonKey.indexOf('niucloud-admin') == -1 && frameworkVersion.value != newFrameworkVersion.value) {
ElMessage({ message: '存在新版本框架,请先升级框架', type: 'error' })
if (callback) callback()
return

View File

@ -29,5 +29,8 @@
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
"cleartextModeTips": "明文模式下,不使用消息体加解密功能,安全系数较低",
"compatibleModeTips": "兼容模式下,明文、密文将共存,方便开发者调试和维护",
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高"
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高",
"wechatBaseUri": "借权域名",
"wechatBaseUriPlaceholder": "",
"wechatBaseUriTips": "默认留空填写后将替换https://open.weixin.gg.com/获取授权!"
}

View File

@ -61,7 +61,7 @@ const getMarketingList = async () => {
// marketingList.value = res.data
loading.value = false
}
getMarketingList()
// getMarketingList()
const toLink = (item: any) => {
if (item.url) {

View File

@ -36,6 +36,11 @@
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
</el-form-item>
<el-form-item :label="t('wechatBaseUri')" prop="base_uri" v-if="!formData.is_authorization">
<el-input v-model.trim="formData.base_uri" :placeholder="t('wechatBaseUriPlaceholder')" class="input-width" clearable />
<div class="form-tip">{{ t('wechatBaseUriTips') }}</div>
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[15px]" shadow="never">
@ -140,7 +145,8 @@ const formData = reactive<Record<string, any>>({
token: '',
encoding_aes_key: '',
encryption_type: 'not_encrypt',
is_authorization: 0
is_authorization: 0,
base_uri: ''
})
const formRef = ref<FormInstance>()

View File

@ -77,6 +77,9 @@
<el-switch v-model="diyStore.global.copyright.isShow" />
<div class="text-sm text-gray-400">{{ t('此处控制当前页面版权信息是否显示') }}</div>
</el-form-item>
<el-form-item :label="t('文字颜色')" class="display-block">
<el-color-picker v-model="diyStore.global.copyright.textColor" show-alpha />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">

View File

@ -455,7 +455,7 @@ initPage({
diyStore.components.push(com)
}
}
console.log( component.value )
loadDiyTemplatePages(data.type)
//

View File

@ -1,47 +1,129 @@
<template>
<!--应用市场-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-page-title">{{ t("localAppText") }}</span>
<div class="main-container bg-body min-h-[70vh]" v-loading="loading">
<el-card class="box-card !border-none" shadow="never" v-if="!loading">
<div class="flex items-center mb-4">
<div class="flex items-center flex-1">
<h2 class="text-lg font-semibold mr-[20px]">应用列表</h2>
<button class="text-gray-500 text-sm mr-[20px]" @click="activeNameTabFn('installed')" :class="{'!text-primary': activeName == 'installed'}">已安装</button>
<button class="text-gray-500 text-sm mr-[20px]" @click="activeNameTabFn('uninstalled')" :class="{'!text-primary': activeName == 'uninstalled'}">未安装</button>
<button class="text-gray-500 text-sm mr-[20px]" @click="activeNameTabFn('all')" :class="{'!text-primary': activeName == 'all'}">已购买</button>
<button class="text-gray-500 text-sm relative" @click="activeNameTabFn('recentlyUpdated')" :class="{'!text-primary': activeName == 'recentlyUpdated'}">
可更新
<div v-if="localList.recentlyUpdated.length" class="w-[8px] h-[8px] bg-[red] rounded-[8px] z-1 absolute top-[-2px] right-[-2px]"></div>
</button>
</div>
<i class="iconfont cursor-pointer" @click="switchShowType" :class="showType == 'card' ? 'iconliebiao' : 'iconliebiaoqiehuan'"></i>
</div>
<el-tabs v-model="activeName" class="mt-[10px]">
<el-tab-pane :label="t('installLabel')" name="installed"></el-tab-pane>
<el-tab-pane :label="t('uninstalledLabel')" name="uninstalled"></el-tab-pane>
<el-tab-pane :label="t('buyLabel')" name="all"></el-tab-pane>
<el-tab-pane :label="t('recentlyUpdated')" name="recentlyUpdated">
<template #label>
<span class="custom-tabs-label">
<span>{{ t('recentlyUpdated') }}</span>
<span v-if="localList['recentlyUpdated'].length > 0" class="w-[15px] h-[15px] bg-[#DA203E] absolute text-[#fff] text-[11px] flex items-center justify-center rounded-full top-[3px] right-[-12px]">{{ localList['recentlyUpdated'].length }}</span>
</span>
</template>
</el-tab-pane>
</el-tabs>
<div class="flex justify-between my-[10px]">
<div class="flex items-center search-form">
<el-input class="!w-[192px] !h-[32px] rounded-[4px]" :placeholder="t('search')" v-model.trim="search_name" @keyup.enter="query">
<template #suffix>
<el-icon class="el-input__icon cursor-pointer" size="14px" @click="query">
<search />
</el-icon>
</template>
</el-input>
<el-select v-model="search_type" placeholder="请选择类型" class="!w-[192px] !h-[32px] rounded-[4px] ml-[20px] " >
<el-option :label="t('全部')" value="" />
<el-option v-for="(label, value) in typeList" :key="value" :label="label" :value="value"></el-option>
</el-select>
<el-button type="primary" @click="query" class="ml-[20px]">{{ t("搜索") }}</el-button>
<!-- 系统版本栏 -->
<div class="flex items-center justify-between bg-body p-4 rounded-md border rounded border-solid border-[var(--el-color-info-light-8)]">
<div class="flex">
<div class="flex items-center">
<div class="w-[40px] h-[40px] bg-purple-100 rounded flex items-center justify-center mr-2 relative">
<img class="max-w-full max-h-full" src="@/app/assets/images/app_store/system_version.png" alt="" />
<div v-if="frameworkVersion != frameworkNewVersion" class="w-[8px] h-[8px] bg-[red] rounded-[8px] z-1 absolute top-[-2px] right-[-2px]"></div>
</div>
<div>
<el-button type="primary" v-show="activeName === 'recentlyUpdated'" @click="batchUpgrade" :loading="upgradeRef?.loading" :disabled="authLoading">{{ t("batchUpgrade") }}</el-button>
<!-- <el-button type="primary" @click="handleCloudBuild" :loading="cloudBuildRef?.loading" :disabled="authLoading">{{ t("cloudBuild") }}</el-button> -->
<p class="text-sm font-bold">系统版本:
<span v-if="frameworkVersion">V{{frameworkVersion}} ({{frameworkVersionCode}})</span>
</p>
<p class="text-xs text-gray-500">最新版本: V{{ frameworkNewVersion }}</p>
</div>
<el-button class="ml-[25px]" @click="updateInformationFn({key: 'niucloud-admin'})"><el-icon class="mr-[5px]"><DocumentCopy /></el-icon>更新记录</el-button>
</div>
<div class="border-r mx-[25px] border-solid border-[var(--el-color-info-light-8)] hidden xl:inline-block"></div>
<div class="items-center hidden xl:flex">
<div class="flex items-center mr-4">
<div class="w-[40px] h-[40px] bg-green-100 rounded flex items-center justify-center mr-2">
<img class="max-w-full max-h-full" src="@/app/assets/images/app_store/app_manage.png" alt="" />
</div>
<div>
<p class="text-sm font-bold">应用管理</p>
<p class="text-xs text-gray-500">
<span class="mr-[15px] text-success">已安装: {{ localList.installed.length }}</span>
<span class="mr-[15px] text-warning">可更新: {{ localList.recentlyUpdated.length }}</span>
<span class="mr-[15px] text-primary">未安装: {{ localList.uninstalled.length }}</span>
<span class="mr-[15px] text-error">已购买: {{ localList.all.length }}</span>
</p>
</div>
</div>
</div>
</div>
<div class="flex items-center flex-1 w-0 justify-end">
<el-button @click="oneClickRepair"><i class="iconfont iconyijianxiufu mr-[5px]" ></i>一键修复</el-button>
<el-button type="primary" v-show="activeName == 'uninstalled'" @click="batchInstall"><i class="iconfont iconanzhuang1 mr-[5px]"></i>安装<span v-if="batchUpgradeApp.length">({{ batchUpgradeApp.length }})</span></el-button>
<el-button type="primary" v-show="activeName == 'recentlyUpdated' || (frameworkVersion != frameworkNewVersion && activeName != 'uninstalled')" @click="batchUpgrade">
<i class="iconfont iconyijianshengji mr-[5px]"></i>一键升级<span v-if="batchUpgradeApp.length">({{ batchUpgradeApp.length }})</span>
</el-button>
<el-checkbox label="全选" :model-value="localList[activeName].length && localList[activeName].length == batchUpgradeApp.length" @change="appKeyAllSelect" v-show="activeName == 'uninstalled' || activeName == 'recentlyUpdated'" value="Value A" class="ml-[12px]"/>
</div>
</div>
</el-card>
<div class="flex mb-4 flex-wrap" v-show="showType == 'card'" v-if="localList[activeName].length && !loading">
<div class="rounded-md border p-[16px] pr-[20px] app-card mb-[20px] ml-[20px] cursor-pointer"
@click="appKeySingleSelect($event, row.key)"
:class="{'border-primary': batchUpgradeApp.includes(row.key)}" v-for="row in localList[activeName]" :key="row.key">
<div class="flex justify-between mb-2">
<div class="flex items-center flex-1 w-0">
<div class="w-[48px] h-[48px] bg-purple-100 rounded flex items-center justify-center mr-2 relative">
<div class="w-full h-full overflow-hidden rounded">
<el-image class="w-full h-full overflow-hidden rounded" :src="row.icon" fit="contain">
<template #error>
<div class="flex items-center w-full h-full">
<img class="max-w-full max-h-full" src="@/app/assets/images/icon-addon-one.png" alt="" />
</div>
</template>
</el-image>
<img src="@/app/assets/images/app_store/app_type_addon.png" alt="" class="absolute z-1 right-0 bottom-0" v-if="row.type == 'addon'">
<img src="@/app/assets/images/app_store/app_type_app.png" alt="" class="absolute z-1 right-0 bottom-0" v-else>
</div>
<div class="w-[8px] h-[8px] bg-[red] rounded-[8px] z-1 absolute top-[-2px] right-[-2px]" v-if="row.install_info && Object.keys(row.install_info)?.length && row.install_info.version != row.version"></div>
</div>
<div class="flex-1 w-0">
<p class="text-sm font-medium truncate" :title="row.title">{{ row.title }}</p>
<p class="text-xs text-gray-500 truncate" :title="row.key">{{ row.key }}</p>
</div>
</div>
<el-checkbox @click.stop :model-value="batchUpgradeApp.includes(row.key)" :value="row.key" @change="appKeySingleSelect($event, row.key)" class="!w-[14px] !h-[14px]" v-if="activeName == 'recentlyUpdated' || activeName == 'uninstalled'"></el-checkbox>
</div>
<div class="flex justify-between">
<div class="text-base">
<span>版本: </span>
<span>{{ row.install_info && Object.keys(row.install_info)?.length ? row.install_info.version : row.version }}</span>
<template v-if="row.install_info && Object.keys(row.install_info)?.length && row.install_info.version != row.version">
<i class="iconfont iconyoujiantou text-warning mx-[2px]"></i>
<span class="text-warning">{{ row.version }}</span>
</template>
</div>
<el-button type="primary" link @click.stop="updateInformationFn(row)">更新记录</el-button>
</div>
<div class="flex mt-[20px]">
<template v-if="!row.is_download">
<el-button type="primary" class="flex-1" :loading="downloading == row.key" :disabled="downloading != ''" @click.stop="downEvent(row)"><i class="iconfont iconanzhuang1 mr-[5px]"></i>立即下载</el-button>
</template>
<template v-else-if="!row.install_info || Object.keys(row.install_info).length == 0">
<el-button type="primary" class="flex-1" @click.stop="installAddonFn(row.key)"><i class="iconfont iconanzhuang1 mr-[5px]"></i>立即安装</el-button>
<el-button plain @click.stop="deleteAddonFn(row.key)">删除</el-button>
</template>
<template v-else>
<el-button type="warning" class="flex-1" @click.stop="upgradeAddonFn(row.key)" v-if="row.install_info.version != row.version">
<i class="iconfont icongengxin mr-[5px]"></i>立即更新
</el-button>
<el-button class="flex-1" :disabled="true" v-else>
<el-icon class="mr-[5px]"><Check /></el-icon>已是最新
</el-button>
<el-button plain @click.stop="uninstallAddonFn(row.key)">卸载</el-button>
</template>
</div>
<div class="relative">
<el-table v-if="localList[activeName].length && !loading" :tree-props="{ children: 'children' }" :default-expand-all="true" :data="info[activeName]" row-key="key" size="large" @selection-change="handleSelectionChange">
</div>
</div>
<div class="relative px-[20px] pb-[20px]" v-show="showType == 'list'">
<el-table v-if="localList[activeName].length && !loading" ref="tableRef" :tree-props="{ children: 'children' }" :default-expand-all="true" :data="info[activeName]" row-key="key" size="large">
<el-table-column width="24">
<template #default="{ row }">
<div class="tree-child-cell" :class="{ 'is-tree-parent': row.children?.length, 'is-tree-child': typeof row.support_app === 'string' && row.support_app !== '' && visibleRowKeys.has(row.support_app)}">
@ -49,7 +131,11 @@
</div>
</template>
</el-table-column>
<el-table-column type="selection" v-if="activeName === 'recentlyUpdated'" />
<el-table-column v-if="activeName === 'recentlyUpdated' || activeName === 'uninstalled'" width="60px">
<template #default="{ row }">
<el-checkbox @click.stop :model-value="batchUpgradeApp.includes(row.key)" :value="row.key" @change="appKeySingleSelect($event, row.key)"></el-checkbox>
</template>
</el-table-column>
<el-table-column :label="t('appName')" align="left" width="500">
<template #default="{ row }">
<div class="flex items-center cursor-pointer relative left-[-10px]">
@ -139,6 +225,8 @@
</el-table>
<div class="h-[100px]" v-loading="loading" v-if="loading"></div>
</div>
</div>
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading && activeName == 'installed' && !authLoading">
<template #image>
<div class="w-[230px] mx-auto">
@ -195,7 +283,7 @@
</p>
</template>
</el-empty>
<el-empty class="mx-auto overview-empty" v-if="!localList.recentlyUpdated.length && !loading && authinfo && activeName == 'recentlyUpdated' && !authLoading">
<el-empty class="mx-auto overview-empty" v-if="!localList.recentlyUpdated.length && !loading && activeName == 'recentlyUpdated'">
<template #image>
<div class="w-[230px] mx-auto">
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="" />
@ -205,7 +293,6 @@
<p class="flex items-center">{{ t("recentlyUpdatedEmpty") }}</p>
</template>
</el-empty>
</div>
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
@ -265,9 +352,10 @@
<div v-show="installStep == 0" v-loading="!installCheckResult.dir">
<!-- <el-scrollbar max-height="50vh"> -->
<div class="min-h-[150px]">
<div class="my-3" v-if="installCheckResult.dir">
<el-scrollbar style="height: calc(50vh); overflow: auto">
<div class="mt-3" v-if="installCheckResult.dir">
<p class="pt-[20px] pl-[20px]">{{ t("dirPermission") }}</p>
<div v-if="!installCheckResult.is_pass" class="mt-[10px] mx-[20px] text-[14px] cursor-pointer text-primary flex items-center justify-between bg-[#EFF6FF] rounded-[4px] p-[10px]" @click="cloudBuildCheckDirFn">
<div v-if="!installCheckResult.file_permission_is_pass" class="mt-[10px] mx-[20px] text-[14px] cursor-pointer text-primary flex items-center justify-between bg-[#EFF6FF] rounded-[4px] p-[10px]" @click="cloudBuildCheckDirFn">
<div class="flex items-center">
<el-icon :size="17"><QuestionFilled /></el-icon>
<span class="ml-[5px] leading-[20px]">编译权限错误查看解决方案</span></div>
@ -285,7 +373,6 @@
<span>{{ t("status") }}</span>
</el-col>
</el-row>
<el-scrollbar style="height: calc(300px); overflow: auto">
<el-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
<el-col :span="18">
<span>{{ item.dir }}</span>
@ -326,10 +413,18 @@
</span>
</el-col>
</el-row>
</div>
</div>
<div class="my-3" v-if="installCheckResult.addon_check && installCheckResult.addon_check.length">
<p class="pl-[20px]">插件验证</p>
<div class="px-[20px] pt-[10px] text-[14px]">
<el-alert class="!mb-[10px]" v-for="item in installCheckResult.addon_check" type="error" :closable="false">
<div v-html="item.msg"></div>
</el-alert>
</div>
</div>
</el-scrollbar>
</div>
</div>
</div>
<!-- </el-scrollbar> -->
<div class="flex justify-end">
<el-tooltip effect="dark" placement="top">
@ -465,7 +560,6 @@
</template>
</el-dialog>
<!-- 更新信息 -->
</el-card>
</div>
<upgrade-log :upgradeKey="upgradeKey" ref="upgradeLogRef" />
<upgrade ref="upgradeRef" @complete="localListFn" @cloudbuild="handleCloudBuild" />
@ -473,7 +567,7 @@
</template>
<script lang="ts" setup>
import { ref, reactive, watch, h ,computed } from 'vue'
import { ref, reactive, watch, h, computed, nextTick } from 'vue'
import { t } from '@/lang'
import {
getAddonLocal,
@ -488,7 +582,7 @@ import {
getAddonInit
} from '@/app/api/addon'
import { deleteAddonDevelop } from '@/app/api/tools'
import { downloadVersion, getAuthInfo, setAuthInfo } from '@/app/api/module'
import { downloadVersion, getAuthInfo, setAuthInfo, getFrameworkNewVersion } from '@/app/api/module'
import { getVersions } from '@/app/api/auth'
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
import 'vue-web-terminal/lib/theme/dark.css'
@ -500,10 +594,12 @@ import useUserStore from '@/stores/modules/user'
import Upgrade from '@/app/components/upgrade/index.vue'
import CloudBuild from '@/app/components/cloud-build/index.vue'
import UpgradeLog from '@/app/components/upgrade-log/index.vue'
import {deepClone} from "@/utils/common";
const tableRef = ref(null)
const router = useRouter()
const route = useRoute()
const terminalId = ref(Date.now());
const terminalId = ref(Date.now())
const activeName = ref(storage.get('storeActiveName') || 'installed')
const upgradeRef = ref(null)
const cloudBuildRef = ref(null)
@ -514,10 +610,22 @@ const userStore = useUserStore()
const unloadHintDialog = ref(false)
const terminalRef = ref(null)
const frameworkVersion = ref('')
const frameworkVersionCode = ref('')
const upgradeLogRef = ref<any>(null)
const showType = ref(storage.get('storeShowType') || 'card')
const frameworkNewVersion = ref('')
getVersions().then((res) => {
frameworkVersion.value = res.data.version.version
frameworkVersionCode.value = res.data.version.code
})
getFrameworkNewVersion().then(({ data }) => {
frameworkNewVersion.value = data.last_version
})
const switchShowType = () => {
showType.value = showType.value == 'card' ? 'list' : 'card'
storage.set({key: 'storeShowType', data: showType.value})
}
const typeList = ref({})
const getAddonInitFn = () => {
@ -534,6 +642,12 @@ const downEventHintFn = () => {
const activeNameTabFn = (data: any) => {
activeName.value = data
storage.set({ key: 'storeActiveName', data })
if ((data == 'uninstalled' || data == 'recentlyUpdated') && localList.value[activeName.value].length) {
batchUpgradeApp.value = localList.value[activeName.value].map(item => item.key)
} else {
batchUpgradeApp.value = []
}
}
if (route.query.id) {
activeNameTabFn(route.query.id)
@ -603,26 +717,7 @@ const buildInfo = (list: any[]) => {
return result
}
// const query = () => {
// if (search_name.value == '' || search_name.value == null) {
// info.value.installed = buildInfo(localList.value.installed)
// info.value.uninstalled = buildInfo(localList.value.uninstalled)
// info.value.all = buildInfo(localList.value.all)
// info.value.recentlyUpdated = buildInfo(localList.value.recentlyUpdated)
// return false
// }
// const filteredInstalled = localList.value.installed.filter((el: any) => el.title.indexOf(search_name.value) != -1)
// const filteredUninstalled = localList.value.uninstalled.filter((el: any) => el.title.indexOf(search_name.value) != -1)
// const filteredAll = localList.value.all.filter((el: any) => el.title.indexOf(search_name.value) != -1)
// const filteredRecentlyUpdated = localList.value.recentlyUpdated.filter((el: any) => el.title.indexOf(search_name.value) != -1)
// //
// info.value.installed = buildInfo(filteredInstalled)
// info.value.uninstalled = buildInfo(filteredUninstalled)
// info.value.all = buildInfo(filteredAll)
// info.value.recentlyUpdated = buildInfo(filteredRecentlyUpdated)
// }
const query = () => {
const name = search_name.value
const type = search_type.value
@ -689,6 +784,7 @@ const localListFn = () => {
appLink.value[item.meta.app] = item.name
}
})
activeNameTabFn(activeName.value)
loading.value = false
}).catch(() => {
loading.value = false
@ -909,6 +1005,7 @@ const handleCloudInstall = () => {
installStep.value = 1
terminalRef.value.execute('clear')
terminalRef.value.execute('开始安装插件')
if (res.data.length) installAfterTips.value = res.data
getInstallTask()
cloudInstalling.value = false
}).catch((res) => {
@ -1155,23 +1252,55 @@ const versionJudge = (row: any) => {
return false
}
let batchUpgradeApp = []
const handleSelectionChange = (e: any) => {
batchUpgradeApp = e.map(item => item.key)
const batchUpgradeApp = ref<String[]>([])
const appKeyAllSelect = () => {
if (localList.value[activeName.value].length) {
if (localList.value[activeName.value].length == batchUpgradeApp.value.length) {
batchUpgradeApp.value = []
} else {
batchUpgradeApp.value = localList.value[activeName.value].map(item => item.key)
}
}
}
const appKeySingleSelect = (event: any, key: string) => {
if (activeName.value != 'recentlyUpdated' && activeName.value != 'uninstalled') return
if (batchUpgradeApp.value.includes(key)) {
batchUpgradeApp.value.splice(batchUpgradeApp.value.indexOf(key), 1)
} else {
batchUpgradeApp.value.push(key)
}
}
const batchUpgrade = () => {
if (!batchUpgradeApp.length) {
ElMessage({ message: '请先勾选要升级的插件', type: 'error', duration: 5000 })
const appKeys = deepClone(batchUpgradeApp.value)
if (frameworkVersion.value != frameworkNewVersion.value) {
appKeys.unshift('niucloud-admin')
}
if (!appKeys.length) {
ElMessage({ message: localList.recentlyUpdated.length ? '请先勾选要升级的插件' : '当前已是最新版', type: 'error', duration: 5000 })
return
}
upgradeAddonFn(appKeys.toString())
}
upgradeAddonFn(batchUpgradeApp.toString())
const batchInstall = () => {
const appKeys = batchUpgradeApp.value
if (!appKeys.length) {
ElMessage({ message: '请先勾选要安装的插件', type: 'error', duration: 5000 })
return
}
installAddonFn(appKeys.toString())
}
const visibleRowKeys = computed(() => {
return new Set((info.value[activeName.value] || []).map(row => row.key));
});
return new Set((info.value[activeName.value] || []).map(row => row.key))
})
const oneClickRepair = () => {
ElMessage({ message: '即将上线敬请期待', duration: 5000 })
}
</script>
<style lang="scss" scoped>
@ -1451,6 +1580,11 @@ html.dark .table-head-bg {
}
}
.app-card {
width: calc((100% - 120px) / 5);
min-width: 260px;
}
</style>
<style>

View File

@ -126,7 +126,9 @@ const prop = defineProps({
},
ignore: {
type: Array,
default: []
default: () => {
return [] // ['DIY_MAKE_PHONE_CALL']
}
}
})

View File

@ -82,6 +82,7 @@ getUrl().then((res: any) => {
// H5
const generateH5QRCode = () => {
console.log( params.value)
// URL
const queryStr = params.value
.map(item => `${encodeURIComponent(item.name)}=${encodeURIComponent(item.value)}`)

View File

@ -219,5 +219,10 @@
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
"promoteUrl": "推广链接",
"downLoadQRCode": "下载二维码",
"configureFailed": "配置失败"
"configureFailed": "配置失败",
"lefttitle": "左侧标题",
"righttitle": "右侧标题",
"leftDesc": "左侧简介",
"rightDesc": "右侧简介",
"descPlaceholder": "请输入简介内容"
}

View File

@ -17,10 +17,10 @@
<div v-if="systemStore.menuIsCollapse" class="text-left text-[14px] mt-[3px] w-[75px] using-hidden ml-[10px]">{{ item.meta.title || item.meta.short_title }}</div>
<div v-else class="text-center text-[12px] using-hidden mt-1">{{ item.meta.short_title || item.meta.title }}</div>
<div v-if="systemStore.menuIsCollapse && item.name=='app_store' && recentlyUpdated.length>0" class="text-[11px] bg-[#DA203E] px-[10px] rounded-[12px] text-[#fff] absolute right-[6px]">更新</div>
<div v-if="!systemStore.menuIsCollapse && item.name=='app_store' && recentlyUpdated.length>0" class="w-[7px] h-[7px] bg-[#DA203E] absolute flex items-center justify-center rounded-full top-[4px] right-[14px]"></div>
<div v-if="systemStore.menuIsCollapse && item.original_name=='tool' && isNewVersion" class="text-[11px] bg-[#DA203E] px-[10px] rounded-[12px] text-[#fff] absolute right-[6px]">更新</div>
<div v-if="!systemStore.menuIsCollapse && item.original_name=='tool' && isNewVersion" class="w-[7px] h-[7px] bg-[#DA203E] absolute flex items-center justify-center rounded-full top-[4px] right-[14px]"></div>
<div v-if="systemStore.menuIsCollapse && item.name=='app_store' && (recentlyUpdated.length>0 || isNewVersion)" class="text-[11px] bg-[#DA203E] px-[10px] rounded-[12px] text-[#fff] absolute right-[6px]">更新</div>
<div v-if="!systemStore.menuIsCollapse && item.name=='app_store' && (recentlyUpdated.length>0 || isNewVersion)" class="w-[7px] h-[7px] bg-[#DA203E] absolute flex items-center justify-center rounded-full top-[4px] right-[14px]"></div>
<!-- <div v-if="systemStore.menuIsCollapse && item.original_name=='tool' && isNewVersion" class="text-[11px] bg-[#DA203E] px-[10px] rounded-[12px] text-[#fff] absolute right-[6px]">更新</div>
<div v-if="!systemStore.menuIsCollapse && item.original_name=='tool' && isNewVersion" class="w-[7px] h-[7px] bg-[#DA203E] absolute flex items-center justify-center rounded-full top-[4px] right-[14px]"></div> -->
</div>
</template>

View File

@ -87,6 +87,7 @@ const useDiyStore = defineStore('diy', {
copyright: {
control: true, // 是否允许展示编辑
isShow: false, // 是否显示
textColor : "#ccc", // 文字颜色
},
// 弹框 count不弹出 -1首次弹出 1每次弹出 0
popWindow: {
@ -190,6 +191,7 @@ const useDiyStore = defineStore('diy', {
copyright: {
control: true, // 是否允许展示编辑
isShow: true, // 是否显示
textColor : "#ccc", // 文字颜色
},
// 弹框 count不弹出 -1首次弹出 1每次弹出 0

View File

@ -1,9 +1,9 @@
@font-face {
font-family: "iconfont";
/* Project id 3883393 */
src: url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.woff2?t=1755603992297') format('woff2'),
url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.woff?t=1755603992297') format('woff'),
url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.ttf?t=1755603992297') format('truetype');
src: url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.woff2?t=1762651161569') format('woff2'),
url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.woff?t=1762651161569') format('woff'),
url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.ttf?t=1762651161569') format('truetype');
}
.iconfont {
@ -14,6 +14,78 @@
-moz-osx-font-smoothing: grayscale;
}
.icona-zhulixiangqingpc30:before {
content: "\e914";
}
.icona-zuidijiapc30:before {
content: "\e915";
}
.icona-zhulipc30:before {
content: "\e916";
}
.icona-zhulijiapc30:before {
content: "\e917";
}
.icona-kanhoujiapc30:before {
content: "\e918";
}
.icona-jiagepc30:before {
content: "\e919";
}
.icona-zhuliwanfapc30:before {
content: "\e91a";
}
.icona-zhulipc301:before {
content: "\e91b";
}
.icona-zhulilunbopc30:before {
content: "\e91c";
}
.icona-canyuxinxipc30:before {
content: "\e91d";
}
.icona-zhulixiangqingpc301:before {
content: "\e91e";
}
.iconyoujiantou:before {
content: "\e913";
}
.iconanzhuang1:before {
content: "\e90d";
}
.icongengxin:before {
content: "\e90e";
}
.iconliebiao:before {
content: "\e90f";
}
.iconyijianshengji:before {
content: "\e910";
}
.iconliebiaoqiehuan:before {
content: "\e911";
}
.iconyijianxiufu:before {
content: "\e912";
}
.icona-bijiPC30:before {
content: "\e90b";
}

View File

@ -131,8 +131,9 @@ export function img(path: string): string {
if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '')
if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1)
if(path){
return isUrl(path) ? path : `${imgDomain}/${path}`
}
}
/**

View File

@ -55,14 +55,23 @@ class Request extends \think\Request
*/
public function paramFilter($param, bool $filter = true)
{
if (!$param || !$filter || !is_string($param)) return $param;
// 把数据过滤
if (!$param || !$filter || !is_string($param)) {
return $param;
}
// 过滤危险标签
$filter_rule = [
"/<(\\/?)(script|i?frame|style|html|body|title|link|metaf|alert|font|object|\\?|\\%)([^>]*?)>/isU",
"/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
"/<(\\/?)(script|iframe|frame|style|html|body|title|link|meta|alert|font|object|\\?|\\%)([^>]*?)>/isU",
"/(<[^>]*?)on[a-zA-Z]+\s*=[\s\"'][^\"']*?([\s\"'][^>]*?>)/isU",
"/\\b(select|join|where|drop|like|modify|rename|insert|update|table|database|alter|truncate|\'|\/\*|\.\.\/|\.\/|union|into|load_file|outfile)\\b/is"
];
return preg_replace($filter_rule, '', $param);
$replace = [
'', // 移除整个危险标签
'$1$2', // 仅移除 onxxx 属性,保留标签
''
];
return preg_replace($filter_rule, $replace, $param);
}
/**

View File

@ -42,7 +42,8 @@ class Config extends BaseAdminController
['token', ''],
['encoding_aes_key', ''],
['qr_code', ''],
['encryption_type', '']
['encryption_type', ''],
['base_uri', '']
]);
$this->validate($data, 'app\validate\channel\Wechat.set');
(new WechatConfigService())->setWechatConfig($data);

View File

@ -27,13 +27,13 @@ Route::group(function () {
Route::get('addon/:id', 'addon.Addon/info');
//安装插件
Route::post('addon/install/:addon', 'addon.Addon/install');
Route::post('addon/install/:addon', 'addon.Addon/install')->pattern(['addon' => '[\w|\,]+']);
//云安装插件
Route::post('addon/cloudinstall/:addon', 'addon.Addon/cloudInstall');
Route::post('addon/cloudinstall/:addon', 'addon.Addon/cloudInstall')->pattern(['addon' => '[\w|\,]+']);
// 云编译进度
Route::get('addon/cloudinstall/:addon', 'addon.Addon/cloudInstallLog');
Route::get('addon/cloudinstall/:addon', 'addon.Addon/cloudInstallLog')->pattern(['addon' => '[\w|\,]+']);
//插件安装检测安装环境
Route::get('addon/install/check/:addon', 'addon.Addon/installCheck');
Route::get('addon/install/check/:addon', 'addon.Addon/installCheck')->pattern(['addon' => '[\w|\,]+']);
// 获取安装任务
Route::get('addon/installtask', 'addon.Addon/getInstallTask');
//下载插件

View File

@ -149,9 +149,9 @@ Route::group('member', function() {
//全部会员等级
Route::get('level/all', 'member.MemberLevel/getAll');
// 获取会员权益内容
Route::get('benefits/content', 'member.Member/getMemberBenefitsContent');
Route::post('benefits/content', 'member.Member/getMemberBenefitsContent');
// 获取会员礼包内容
Route::get('gifts/content', 'member.Member/getMemberGiftsContent');
Route::post('gifts/content', 'member.Member/getMemberGiftsContent');
/***************************************************** 会员签到 ****************************************************/
//签到设置
Route::put('sign/config', 'member.MemberSign/setSign');

View File

@ -30,13 +30,13 @@ Route::group('', function () {
Route::post('upgrade/clear', 'addon.Upgrade/clearUpgradeTask');
// 升级环境检测
Route::get('upgrade/check/[:addon]', 'addon.Upgrade/upgradePreCheck')->pattern(['addon' => '[\w|\,]+']);
Route::get('upgrade/check/[:addon]', 'addon.Upgrade/upgradePreCheck')->pattern(['addon' => '[\w,-]+']);
// 升级
Route::post('upgrade/[:addon]', 'addon.Upgrade/upgrade')->pattern(['addon' => '[\w|\,]+']);
Route::post('upgrade/[:addon]', 'addon.Upgrade/upgrade')->pattern(['addon' => '[\w,-]+']);
// 获取升级内容
Route::get('upgrade/[:addon]', 'addon.Upgrade/getUpgradeContent')->pattern(['addon' => '[\w|\,]+']);
Route::get('upgrade/[:addon]', 'addon.Upgrade/getUpgradeContent')->pattern(['addon' => '[\w,-]+']);
Route::post('upgrade/operate/:operate', 'addon.Upgrade/operate');

View File

@ -26,6 +26,7 @@ class CommonActiveDict
const EXCHANGE = 'exchange';// 积分商城 积
const MANJIANSONG = 'manjiansong'; // 满减送 满减
const NEWCOMER_DISCOUNT = 'newcomer_discount'; // 新人专享 新
const FRIEND_HELP = 'friend_help'; // 好友助力 友
const PINTUAN = 'pintuan'; // 新人专享 新
const SECKILL = 'seckill'; // 秒杀 秒
const RELAY = 'relay'; // 接龙 接
@ -78,6 +79,11 @@ class CommonActiveDict
'active_name' => get_lang('common_active_short.relay_name'),
'bg_color' => '#0EB108'
],
self::FRIEND_HELP => [
'name' => get_lang('common_active_short.friend_help_short'),
'active_name' => get_lang('common_active_short.friend_help_name'),
'bg_color' => '#F20C8A'
],
];
return !empty($active) ? $data[$active] ?? [] : $data;
}

View File

@ -160,7 +160,8 @@ class PagesDict
],
"copyright" => [
'control' => true,
'isShow' => false
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",
@ -243,7 +244,8 @@ class PagesDict
],
"copyright" => [
'control' => true,
'isShow' => false
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",
@ -720,7 +722,8 @@ class PagesDict
],
"copyright" => [
'control' => true,
'isShow' => false
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",

View File

@ -87,7 +87,8 @@ class TemplateDict
],
"copyright" => [
'control' => true,
'isShow' => false
'isShow' => false,
'textColor' =>'#ccc'
],
"popWindow" => [
"imgUrl" => "",
@ -740,7 +741,8 @@ class TemplateDict
],
"copyright" => [
'control' => true,
'isShow' => false
'isShow' => false,
'textColor' =>'#ccc'
],
"popWindow" => [
"imgUrl" => "",

View File

@ -1688,21 +1688,7 @@ return [
'is_show' => '1',
]
]
],
[
'menu_name' => '系统更新',
'menu_key' => 'system_upgrade',
'menu_short_name' => '系统更新',
'menu_type' => '1',
'icon' => 'iconfont iconxitonggengxin1',
'api_url' => '',
'router_path' => 'tools/upgrade',
'view_path' => 'app/upgrade',
'methods' => '',
'sort' => '97',
'status' => '1',
'is_show' => '1',
],
]
],
],

View File

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

View File

@ -78,6 +78,7 @@ class FileDict
self::IMAGE,//图片上传
self::VIDEO,//视频上传
self::AUDIO,//视频上传
self::DOCUMENT,//文件上传
self::APPLET,//小程序包上传
self::EXCEL,//excel导入
self::APP_PACKAGE,//应用包

View File

@ -469,6 +469,8 @@ return [
'seckill_name' => '秒杀',
'relay_short' => '接',
'relay_name' => '接龙',
'friend_help_short' => '友',
'friend_help_name' => '好友助力',
],
//应用菜单下 特殊菜单定义
'dict_site_addon_menu' => [

View File

@ -69,8 +69,9 @@ class AuthService extends BaseAdminService
$method = strtolower(trim($request->method()));
$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');
// throw new AuthException('演示站禁止操作');
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();

View File

@ -212,7 +212,7 @@ use app\adminapi\middleware\AdminLog;";
{
if(!empty($this->addonName))
{
$dir = $this->outDir . DIRECTORY_SEPARATOR.'addon'.DIRECTORY_SEPARATOR.'.$this->addonName.'.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'adminapi'.DIRECTORY_SEPARATOR.'route'.DIRECTORY_SEPARATOR;
$dir = $this->outDir . DIRECTORY_SEPARATOR.'addon'.DIRECTORY_SEPARATOR.$this->addonName.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'adminapi'.DIRECTORY_SEPARATOR.'route'.DIRECTORY_SEPARATOR;
}else{
$dir = $this->outDir . 'niucloud'.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'adminapi'.DIRECTORY_SEPARATOR.'route'.DIRECTORY_SEPARATOR;
}

View File

@ -213,6 +213,9 @@ class AuthSiteService extends BaseAdminService
* @return true
*/
public function createSite(array $data) {
// throw new CommonException('演示站禁止操作');
if (!AuthService::isSuperAdmin()) {
$limit = (new UserCreateSiteLimit())->where([ ['uid', '=', $this->uid], ['group_id', '=', $data['group_id'] ] ])->findOrEmpty();
if ($limit->isEmpty()) throw new CommonException('NO_PERMISSION_TO_CREATE_SITE_GROUP');

View File

@ -863,6 +863,7 @@ class UpgradeService extends BaseAdminService
} else {
$addons = array_filter(explode(',', $addon));
foreach ($addons as $key) {
if ($key != AddonDict::FRAMEWORK_KEY) {
$info = ( new Addon() )->where([ [ 'key', '=', $key ] ])->field('version,type')->find();
$upgrade[ 'app_key' ] = $key;
$upgrade[ 'version' ] = $info['version'];
@ -873,6 +874,12 @@ class UpgradeService extends BaseAdminService
}
}
}
if (in_array(AddonDict::FRAMEWORK_KEY, $addons)) {
$upgrade[ 'app_key' ] = AddonDict::FRAMEWORK_KEY;
$upgrade[ 'version' ] = config('version.version');
array_unshift($apps, $upgrade);
}
}
foreach ($apps as $item) {
$upgrade_content = ( new CoreModuleService() )->getUpgradeContent($item)[ 'data' ] ?? [];

View File

@ -175,6 +175,7 @@ class WeappAuthService extends BaseApiService
// }
}
}
if (empty($member_info->wx_unionid) && !empty($unionid)) $member_info->wx_unionid = $unionid;
return $login_service->login($member_info, MemberLoginTypeDict::WEAPP);
}
}

View File

@ -143,6 +143,7 @@ class WechatAppService extends BaseApiService
if (!empty($avatar)) $member_info->headimg = $avatar;
if (!empty($nickname)) $member_info->nickname = $nickname;
}
if (empty($member_info->wx_unionid) && !empty($unionid)) $member_info->wx_unionid = $unionid;
return $login_service->login($member_info, MemberLoginTypeDict::WECHAT);
}
}

View File

@ -163,6 +163,7 @@ class WechatAuthService extends BaseApiService
if (!empty($avatar)) $member_info->headimg = $avatar;
if (!empty($nickname)) $member_info->nickname = $nickname;
}
if (empty($member_info->wx_unionid) && !empty($unionid)) $member_info->wx_unionid = $unionid;
return $login_service->login($member_info, MemberLoginTypeDict::WECHAT);
}
}

View File

@ -133,6 +133,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
return $build_log;
}
if ($last['percent'] == 100) {
$addon = isset($install_task['addon_list']) ? implode(',', $install_task['addon_list']) : $addon;
$build_log['data'][0] = $this->buildSuccess($addon, $build_log['data'][0], $install_task['timestamp']);
}
}

View File

@ -23,6 +23,7 @@ use think\db\exception\DbException;
use think\db\exception\PDOException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
/**
* 安装服务层
@ -63,11 +64,14 @@ class CoreAddonInstallService extends CoreAddonBaseService
private $install_task = null;
private $addon_list = [];
public function __construct($addon)
{
parent::__construct();
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $addon . DIRECTORY_SEPARATOR;
$this->addon_list = explode(',', $addon);
$this->addon = $this->addon_list[0];
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$this->cache_key = "install_{$addon}";
@ -93,30 +97,17 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function installCheck()
{
$from_admin_dir = $this->install_addon_path . 'admin' . DIRECTORY_SEPARATOR;
$from_web_dir = $this->install_addon_path . 'web' . DIRECTORY_SEPARATOR;
$from_wap_dir = $this->install_addon_path . 'uni-app' . DIRECTORY_SEPARATOR;
$from_resource_dir = $this->install_addon_path . 'resource' . DIRECTORY_SEPARATOR;
// 放入的文件
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR;
if (!is_dir($this->root_path . 'admin' . DIRECTORY_SEPARATOR)) throw new CommonException('ADMIN_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'web' . DIRECTORY_SEPARATOR)) throw new CommonException('WEB_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR)) throw new CommonException('UNIAPP_DIR_NOT_EXIST');
// 配置文件
$package_path = $this->install_addon_path . 'package' . DIRECTORY_SEPARATOR;
$package_file = [];
search_dir($package_path, $package_file);
$package_file = array_map(function ($file) use ($package_path) {
return str_replace($package_path . DIRECTORY_SEPARATOR, '', $file);
}, $package_file);
$data = [
// 目录检测
'dir' => [
@ -127,10 +118,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
]
];
if (is_dir($from_admin_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_admin_dir), 'status' => is_readable($from_admin_dir)];
if (is_dir($from_web_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_web_dir), 'status' => is_readable($from_web_dir)];
if (is_dir($from_wap_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_wap_dir), 'status' => is_readable($from_wap_dir)];
if (is_dir($from_resource_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_resource_dir), 'status' => is_readable($from_resource_dir)];
if (is_dir($this->addon_path)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $this->addon_path), 'status' => is_readable($this->addon_path)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_admin_dir), 'status' => is_dir($to_admin_dir) ? is_write($to_admin_dir) : mkdir($to_admin_dir, 0777, true)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_web_dir), 'status' => is_dir($to_web_dir) ? is_write($to_web_dir) : mkdir($to_web_dir, 0777, true)];
@ -138,7 +126,8 @@ class CoreAddonInstallService extends CoreAddonBaseService
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_resource_dir), 'status' => is_dir($to_resource_dir) ? is_write($to_resource_dir) : mkdir($to_resource_dir, 0777, true)];
// 校验niucloud/public下 wap web admin 目录及文件是否可读可写
$check_res = checkDirPermissions(public_path() . 'wap');
$check_res = checkDirPermissions($this->addon_path);
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'wap'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'admin'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'web'));
@ -153,13 +142,65 @@ class CoreAddonInstallService extends CoreAddonBaseService
}
}
$check_res = array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status')
);
// 检测插件
$framework_version = config('version.version');
$framework_version_arr = explode('.', $framework_version);
$data['addon_check'] = [];
foreach ($this->addon_list as $addon) {
$install_data = $this->getAddonConfig($addon);
if (empty($install_data)) {
$data['addon_check'][] = [
'msg' => "未找到插件{$addon}的info.json文件",
'status' => false
];
continue;
}
$core_addon_service = new CoreAddonService();
if (!empty($core_addon_service->getInfoByKey($addon))) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件已安装,不能重复安装',
'status' => false
];
continue;
}
if (isset($install_data['support_app']) && !empty($install_data['support_app']) &&
empty($core_addon_service->getInfoByKey($install_data['support_app'])) && !in_array($install_data['support_app'], $this->addon_list)) {
$support_app_data = $this->getAddonConfig($install_data['support_app']);
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的主应用'. (empty($support_app_data) ? $install_data['support_app'] : $support_app_data['title']) .'插件还未安装,请先安装主应用',
'status' => false
];
continue;
}
if (!isset($install_data['support_version']) || empty($install_data['support_version'])) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
continue;
}
$support_framework_arr = explode('.', $install_data['support_version']);
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
}
}
}
// 是否通过校验
$data['is_pass'] = !in_array(false, $check_res);
$data['is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
array_column($data['addon_check'], 'status')
));
$data['file_permission_is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
));
Cache::set($this->cache_key . '_install_check', $data['is_pass']);
return $data;
}
@ -170,60 +211,36 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function install(string $mode = 'local')
{
$core_addon_service = new CoreAddonService();
if (!empty($core_addon_service->getInfoByKey($this->addon))) throw new AddonException('REPEAT_INSTALL');
$install_data = $this->getAddonConfig($this->addon);
if (empty($install_data)) throw new AddonException('ADDON_INFO_FILE_NOT_EXIST');
$framework_version = config('version.version');
$framework_version_arr = explode('.', $framework_version);
// 检测框架版本是否支持
if (!isset($install_data['support_version']) || empty($install_data['support_version']))
throw new AddonException('您要安装的插件或应用的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
$support_framework_arr = explode('.', $install_data['support_version']);
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
throw new AddonException('您要安装的插件或应用的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
}
}
$check_res = Cache::get($this->cache_key . '_install_check');
if (!$check_res) throw new CommonException('INSTALL_CHECK_NOT_PASS');
if ($this->install_task) throw new CommonException('ADDON_INSTALLING');
$this->install_task = [ 'mode' => $mode, 'addon' => $this->addon, 'step' => [], 'timestamp' => time() ];
$this->install_task = [ 'mode' => $mode, 'addon' => $this->addon, 'addon_list' => $this->addon_list, 'step' => [], 'fail_addon' => [], 'timestamp' => time() ];
Cache::set('install_task', $this->install_task);
set_time_limit(0);
$install_step = ['installDir','installWap','installDepend'];
if (!empty($install_data['compile']) || $mode == 'cloud') {
// 备份前端目录
$install_step[] = 'backupFrontend';
}
$this->backupFrontend();
$tips = [];
if ($mode != 'cloud') $tips[] = get_lang('dict_addon.install_after_update');
foreach ($this->addon_list as $addon) {
$this->install_task['addon'] = $addon;
Cache::set('install_task', $this->install_task);
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$install_data = $this->getAddonConfig($addon);
$install_step = ['installDir','installDepend'];
// 检测插件是否存在编译内容
if (!empty($install_data['compile'])) {
$install_step[] = 'coverCompile';
}
if ($mode == 'cloud') {
$install_step[] = 'cloudInstall';
} else {
$install_step[] = 'handleAddonInstall';
}
try {
foreach ($install_step as $step) {
$this->install_task['step'][] = $step;
$this->$step();
if ($step != 'handleAddonInstall') Cache::set('install_task', $this->install_task);
}
if ($mode != 'cloud') {
// 配置文件
$package_path = $this->install_addon_path . 'package' . DIRECTORY_SEPARATOR;
@ -233,49 +250,68 @@ class CoreAddonInstallService extends CoreAddonBaseService
return str_replace($package_path . DIRECTORY_SEPARATOR, '', $file);
}, $package_file);
$tips = [get_lang('dict_addon.install_after_update')];
if (in_array('admin-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_admin_update');
if (in_array('composer.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_composer_update');
if (in_array('uni-app-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_wap_update');
if (in_array('web-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_web_update');
return $tips;
if (in_array('admin-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_admin_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_admin_update');
if (in_array('composer.json', $package_file) && !in_array(get_lang('dict_addon.install_after_composer_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_composer_update');
if (in_array('uni-app-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_wap_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_wap_update');
if (in_array('web-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_web_update'), $tips) ) $tips[] = get_lang('dict_addon.install_after_web_update');
}
return true;
} catch (\Exception $e) {
try {
$this->install_task['step'] = [];
foreach ($install_step as $step) {
$this->install_task['step'][] = $step;
Cache::set('install_task', $this->install_task);
$this->installExceptionHandle();
$this->$step();
}
} catch (\Exception $e) {
$this->install_task['fail_addon'] = $this->addon;
$this->installExceptionHandle($addon);
if (count($this->addon_list) == 1) {
throw new CommonException($e->getMessage());
}
Log::write($install_data['title'] . '插件安装失败');
Log::write($e->getTrace());
$tips[] = $install_data['title'] . '插件安装失败';
}
}
$this->installWap();
if ($mode == 'cloud') {
$this->install_task['tips'] = $tips;
Cache::set('install_task', $this->install_task);
$this->cloudInstall();
} else {
$this->handleAddonInstall();
}
return empty($tips) ? true : $tips;
}
/**
* 安装异常处理
* @return void
*/
public function installExceptionHandle() {
public function installExceptionHandle($name = '') {
$install_task = Cache::get('install_task');
if (in_array('installDir', $install_task['step'])) {
foreach ($this->addon_list as $addon) {
if (!empty($name) && $name != $addon) continue;
@$this->uninstallDir();
}
if (in_array('installWap', $install_task['step'])) {
@$this->uninstallWap();
}
if (in_array('backupFrontend', $install_task['step'])) {
@$this->revertFrontendBackup();
}
Cache::set('install_task', null);
}
/**
* 取消安装任务
* @return void
*/
public function cancleInstall() {
if (Cache::get('install_task')) $this->installExceptionHandle();
if (Cache::get('install_task')) {
$this->installExceptionHandle();
Cache::set('install_task', null);
}
}
/**
@ -411,6 +447,16 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function handleAddonInstall()
{
$core_addon_service = new CoreAddonService();
$fail_addon = $this->install_task['fail_addon'] ?? [];
foreach ($this->addon_list as $addon) {
if (in_array($addon, $fail_addon)) continue;
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
// 执行安装sql
$this->installSql();
// 安装菜单
@ -418,18 +464,20 @@ class CoreAddonInstallService extends CoreAddonBaseService
// 安装计划任务
$this->installSchedule();
$core_addon_service = new CoreAddonService();
$install_data = $this->getAddonConfig($this->addon);
$install_data['icon'] = 'addon/' . $this->addon . '/icon.png';
$core_addon_service->set($install_data);
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
//执行命令
//执行插件安装方法
$class = "addon\\" . $this->addon . "\\" . 'Addon';
if (class_exists($class)) {
(new $class())->install();
}
}
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
// 清除插件安装中标识
Cache::delete('install_task');
Cache::delete($this->cache_key . '_install_check');
@ -691,13 +739,13 @@ class CoreAddonInstallService extends CoreAddonBaseService
{
// 编译 diy-group 自定义组件代码文件
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 pages.json 页面路由代码文件
$this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR);
$this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 加载插件标题语言包
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
}

View File

@ -83,7 +83,12 @@ trait WapTrait
}
}
if (!empty($addon)) {
$addon_arr[] = $addon; // 追加新装插件
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
@ -122,7 +127,7 @@ trait WapTrait
$content .= " </view>\n";
$content .= " </template>\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && diyGroup.showCopyright.value && data.global.copyright && data.global.copyright.isShow\">\n";
$content .= " <copy-right />\n";
$content .= " <copy-right :textColor=\"data.global.copyright.textColor\" />\n";
$content .= " </template>\n\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && data.global.bottomTabBar && data.global.bottomTabBar.isShow\">\n";
$content .= " <view class=\"pt-[20rpx]\"></view>\n";
@ -184,7 +189,7 @@ trait WapTrait
* @param $compile_path
* @return bool|int|void
*/
public function installPageCode($compile_path)
public function installPageCode($compile_path, $addon = '')
{
if (!file_exists($this->geAddonPackagePath($this->addon) . 'uni-app-pages.php')) return;
@ -195,7 +200,25 @@ trait WapTrait
}
$pages = [];
$addon_arr = array_unique(array_merge([ $this->addon ], array_column(( new CoreAddonService() )->getInstallAddonList(), 'key')));
$addon_service = new CoreAddonService();
$addon_list = $addon_service->getInstallAddonList();
$addon_arr = [];
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
$addon_arr[] = $v[ 'key' ];
}
}
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $addon) {
if (!file_exists($this->geAddonPackagePath($addon) . 'uni-app-pages.php')) continue;
$uniapp_pages = require $this->geAddonPackagePath($addon) . 'uni-app-pages.php';
@ -284,10 +307,18 @@ trait WapTrait
$json = json_decode($app_json, true);
// 清空当前安装/卸载的插件语言包
foreach ($json as $jk => $jc) {
if (is_array($addon)) {
foreach ($addon as $key) {
if (strpos($jk, $key) !== false) {
unset($json[ $jk ]);
}
}
} else {
if (strpos($jk, $addon) !== false) {
unset($json[ $jk ]);
}
}
}
$locale_data[ $cv ] = [
'path' => $ck,
'json' => $json
@ -305,8 +336,16 @@ trait WapTrait
$addon_arr[] = $v[ 'key' ];
}
}
$addon_arr[] = $addon; // 追加新装插件
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $k => $v) {
$addon_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/' . $v . '/locale'); // 插件语言包根目录
$addon_file_arr = getFileMap($addon_path, []);

View File

@ -131,7 +131,6 @@ class CorePosterService extends BaseCoreService
$condition[] = ['is_default', '=', 1];
}
$poster = (new Poster())->where($condition)->findOrEmpty();
try {
if ($poster->isEmpty()) {
@ -146,7 +145,6 @@ class CorePosterService extends BaseCoreService
}
if (empty($poster)) throw new CommonException('海报模板不存在');
$poster_data = [];
$poster_data_arr = array_values(array_filter(event('GetPosterData', [
'type' => $type,
@ -154,7 +152,6 @@ class CorePosterService extends BaseCoreService
'param' => $param,
'channel' => $channel
])));
// 合并模版数据
foreach ($poster_data_arr as $k => $v) {
$poster_data = array_merge($poster_data, $v);

View File

@ -155,10 +155,10 @@ class CoreWeappService extends BaseCoreService
$result = CoreOplatformService::weappVersion($site_id);
if (isset($result['errcode']) && $result['errcode'] != 0) throw new CommonException($result['errmsg']);
return [
"release_version" => $result['release_info']['release_version'],
"release_time" => date('Y-m-d H:i:s', $result['release_info']['release_time']),
"exp_version" => $result['exp_info']['exp_version'] ?? '',
"exp_time" => !empty($result['exp_info']['exp_time']) ? date('Y-m-d H:i:s', $result['exp_info']['exp_time']) : '',
"release_version" => !empty($result['release_info']) ? $result['release_info']['release_version'] : '',
"release_time" => !empty($result['release_info']) ? date('Y-m-d H:i:s', $result['release_info']['release_time']) : '',
"exp_version" => !empty($result['exp_info']) ? ($result['exp_info']['exp_version'] ?? '') : '',
"exp_time" => !empty($result['exp_info']) ? date('Y-m-d H:i:s', $result['exp_info']['exp_time']) : '',
];
}
return [];

View File

@ -17,6 +17,7 @@ use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\Kernel\Support\Collection;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use think\facade\Log;
/**
* 微信小程序服务提供
@ -39,12 +40,13 @@ class CoreWeappTemplateService extends BaseCoreService
*/
public function send(int $site_id, string $template_id, string $touser, array $data, string $page = ''){
$api = CoreWeappService::appApiClient($site_id);
$api->postJson('cgi-bin/message/subscribe/send', [
$res = $api->postJson('cgi-bin/message/subscribe/send', [
'template_id' => $template_id, // 所需下发的订阅模板id
'touser' => $touser, // 接收者(用户)的 openid
'page' => $page, // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,示例index?foo=bar。该字段不填则模板无跳转。
'data' => $data,
]);
Log::write('小程序消息发送RESPONSE'.json_encode($res->toArray(),256));
}
/**

View File

@ -43,7 +43,8 @@ class CoreWechatConfigService extends BaseCoreService
'token' => $info[ 'token' ] ?? '',
'encoding_aes_key' => $info[ 'encoding_aes_key' ] ?? '',
'encryption_type' => $info[ 'encryption_type' ] ?? 'not_encrypt',//加解密模式 not_encrypt 明文 compatible 兼容 safe 安全
'is_authorization' => $info[ 'is_authorization' ] ?? 0
'is_authorization' => $info[ 'is_authorization' ] ?? 0,
'base_uri' => $info['base_uri'] ?? ''
];
}

View File

@ -51,6 +51,7 @@ class CoreWechatService extends BaseCoreService
'retry' => true, // 使用默认重试配置
]
);
if (isset($wechat_config['base_uri']) && !empty($wechat_config['base_uri'])) $config['http']['base_uri'] = $wechat_config['base_uri'];
return new Application($config);
}
}

View File

@ -44,7 +44,7 @@ class CoreOplatformService extends BaseCoreService
'token' => $oplatform_config['token'],
'aes_key' => $oplatform_config['aes_key'],// 明文模式请勿填写 EncodingAESKey
'http' => [
'timeout' => 5.0,
'timeout' => 10,//若返回不及时会导致接口返回报错 9402205 (猜测)
'retry' => true, // 使用默认重试配置
]
);

View File

@ -0,0 +1,73 @@
<?php
namespace app\upgrade\v119;
use app\model\diy\Diy;
use app\model\diy_form\DiyForm;
class Upgrade
{
public function handle()
{
$this->handleDiyData();
$this->handleDiyFormData();
}
/**
* 处理自定义数据
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function handleDiyData()
{
$diy_model = new Diy();
$where = [
['value', '<>', ''],
];
$field = 'id,value';
$list = $diy_model->where($where)->field($field)->select()->toArray();
if (!empty($list)) {
foreach ($list as $k => $v) {
$diy_data = json_decode($v['value'], true);
$diy_data['global']['copyright']['textColor'] = '#ccc';
$diy_data = json_encode($diy_data);
$diy_model->where([['id', '=', $v['id']]])->update(['value' => $diy_data]);
}
}
}
/**
* 处理万能表单数据
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function handleDiyFormData()
{
$diy_form_model = new DiyForm();
$where = [
['value', '<>', '']
];
$field = 'form_id,value';
$list = $diy_form_model->where($where)->field($field)->select()->toArray();
if (!empty($list)) {
foreach ($list as $k => $v) {
$diy_data = $v['value'];
if (!isset($diy_data['global']['copyright']['textColor'])) {
$diy_data['global']['copyright']['textColor'] = '#ccc';
}
$diy_form_model->where([['form_id', '=', $v['form_id']]])->update(['value' => $diy_data]);
}
}
}
}

View File

View File

@ -1,6 +1,6 @@
<?php
return [
'version' => '1.1.8',
'code' => '202510300001'
'version' => '1.1.9',
'code' => '202511110001'
];

View File

@ -0,0 +1,840 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\addon;
use app\model\site\Site;
use app\model\site\SiteGroup;
use app\service\admin\sys\MenuService;
use app\service\core\menu\CoreMenuService;
use app\service\core\schedule\CoreScheduleInstallService;
use core\exception\AddonException;
use core\exception\CommonException;
use core\util\Terminal;
use think\db\exception\DbException;
use think\db\exception\PDOException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
/**
* 安装服务层
* Class CoreInstallService
* @package app\service\core\install
*/
class CoreAddonInstallService extends CoreAddonBaseService
{
use WapTrait;
public static $instance;
/**
* 需要迁移的文件,用于检测是否冲突
* @var array[]
*/
public $install_files = [
'admin' => [],
'web' => [],
'wap' => [],
];
private $files = [
'niucloud' => [],
'admin' => [],
'web' => [],
'wap' => [],
'resource' => []
];
private $flow_path = [
'file',
'sql',
'menu',
'diy'
];
private $addon;
private $install_addon_path;
private $cache_key = '';
private $install_task = null;
private $addon_list = [];
public function __construct($addon)
{
parent::__construct();
$this->addon_list = explode(',', $addon);
$this->addon = $this->addon_list[0];
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$this->cache_key = "install_{$addon}";
$this->install_task = Cache::get('install_task');
}
/**
* 初始化实例
* @param string $addon
* @return static
*/
public static function instance(string $addon)
{
if (is_null(self::$instance)) {
self::$instance = new static($addon);
}
return self::$instance;
}
/**
* 安装前检测
* @return array
*/
public function installCheck()
{
// 放入的文件
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR;
if (!is_dir($this->root_path . 'admin' . DIRECTORY_SEPARATOR)) throw new CommonException('ADMIN_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'web' . DIRECTORY_SEPARATOR)) throw new CommonException('WEB_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR)) throw new CommonException('UNIAPP_DIR_NOT_EXIST');
$data = [
// 目录检测
'dir' => [
// 要求可读权限
'is_readable' => [],
// 要求可写权限
'is_write' => []
]
];
if (is_dir($this->addon_path)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $this->addon_path), 'status' => is_readable($this->addon_path)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_admin_dir), 'status' => is_dir($to_admin_dir) ? is_write($to_admin_dir) : mkdir($to_admin_dir, 0777, true)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_web_dir), 'status' => is_dir($to_web_dir) ? is_write($to_web_dir) : mkdir($to_web_dir, 0777, true)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_wap_dir), 'status' => is_dir($to_wap_dir) ? is_write($to_wap_dir) : mkdir($to_wap_dir, 0777, true)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_resource_dir), 'status' => is_dir($to_resource_dir) ? is_write($to_resource_dir) : mkdir($to_resource_dir, 0777, true)];
// 校验niucloud/public下 wap web admin 目录及文件是否可读可写
$check_res = checkDirPermissions($this->addon_path);
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'wap'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'admin'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'web'));
if (!empty($check_res['unreadable'])) {
foreach ($check_res['unreadable'] as $item) {
$data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false];
}
}
if (!empty($check_res['not_writable'])) {
foreach ($check_res['not_writable'] as $item) {
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false];
}
}
// 检测插件
$framework_version = config('version.version');
$framework_version_arr = explode('.', $framework_version);
$data['addon_check'] = [];
foreach ($this->addon_list as $addon) {
$install_data = $this->getAddonConfig($addon);
if (empty($install_data)) {
$data['addon_check'][] = [
'msg' => "未找到插件{$addon}的info.json文件",
'status' => false
];
continue;
}
$core_addon_service = new CoreAddonService();
if (!empty($core_addon_service->getInfoByKey($addon))) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件已安装,不能重复安装',
'status' => false
];
continue;
}
if (isset($install_data['support_app']) && !empty($install_data['support_app']) &&
empty($core_addon_service->getInfoByKey($install_data['support_app'])) && !in_array($install_data['support_app'], $this->addon_list)) {
$support_app_data = $this->getAddonConfig($install_data['support_app']);
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的主应用'. (empty($support_app_data) ? $install_data['support_app'] : $support_app_data['title']) .'插件还未安装,请先安装主应用',
'status' => false
];
continue;
}
if (!isset($install_data['support_version']) || empty($install_data['support_version'])) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
continue;
}
$support_framework_arr = explode('.', $install_data['support_version']);
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
}
}
}
// 是否通过校验
$data['is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
array_column($data['addon_check'], 'status')
));
$data['file_permission_is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
));
Cache::set($this->cache_key . '_install_check', $data['is_pass']);
return $data;
}
/**
* 插件安装
* @return true
*/
public function install(string $mode = 'local')
{
$check_res = Cache::get($this->cache_key . '_install_check');
if (!$check_res) throw new CommonException('INSTALL_CHECK_NOT_PASS');
if ($this->install_task) throw new CommonException('ADDON_INSTALLING');
$this->install_task = [ 'mode' => $mode, 'addon' => $this->addon, 'addon_list' => $this->addon_list, 'step' => [], 'fail_addon' => [], 'timestamp' => time() ];
Cache::set('install_task', $this->install_task);
set_time_limit(0);
// 备份前端目录
$this->backupFrontend();
$tips = [];
if ($mode != 'cloud') $tips[] = get_lang('dict_addon.install_after_update');
foreach ($this->addon_list as $addon) {
$this->install_task['addon'] = $addon;
Cache::set('install_task', $this->install_task);
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$install_data = $this->getAddonConfig($addon);
$install_step = ['installDir','installDepend'];
// 检测插件是否存在编译内容
if (!empty($install_data['compile'])) {
$install_step[] = 'coverCompile';
}
if ($mode != 'cloud') {
// 配置文件
$package_path = $this->install_addon_path . 'package' . DIRECTORY_SEPARATOR;
$package_file = [];
search_dir($package_path, $package_file);
$package_file = array_map(function ($file) use ($package_path) {
return str_replace($package_path . DIRECTORY_SEPARATOR, '', $file);
}, $package_file);
if (in_array('admin-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_admin_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_admin_update');
if (in_array('composer.json', $package_file) && !in_array(get_lang('dict_addon.install_after_composer_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_composer_update');
if (in_array('uni-app-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_wap_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_wap_update');
if (in_array('web-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_web_update'), $tips) ) $tips[] = get_lang('dict_addon.install_after_web_update');
}
try {
$this->install_task['step'] = [];
foreach ($install_step as $step) {
$this->install_task['step'][] = $step;
Cache::set('install_task', $this->install_task);
$this->$step();
}
} catch (\Exception $e) {
$this->install_task['fail_addon'] = $this->addon;
$this->installExceptionHandle($addon);
if (count($this->addon_list) == 1) {
throw new CommonException($e->getMessage());
}
Log::write($install_data['title'] . '插件安装失败');
Log::write($e->getTrace());
$tips[] = $install_data['title'] . '插件安装失败';
}
}
$this->installWap();
if ($mode == 'cloud') {
$this->install_task['tips'] = $tips;
Cache::set('install_task', $this->install_task);
$this->cloudInstall();
} else {
$this->handleAddonInstall();
}
return empty($tips) ? true : $tips;
}
/**
* 安装异常处理
* @return void
*/
public function installExceptionHandle($name = '') {
$install_task = Cache::get('install_task');
foreach ($this->addon_list as $addon) {
if (!empty($name) && $name != $addon) continue;
@$this->uninstallDir();
@$this->uninstallWap();
}
@$this->revertFrontendBackup();
}
/**
* 取消安装任务
* @return void
*/
public function cancleInstall() {
if (Cache::get('install_task')) {
$this->installExceptionHandle();
Cache::set('install_task', null);
}
}
/**
* 获取安装任务
* @return mixed
*/
public function getInstallTask() {
return $this->install_task;
}
/**
* 安装迁移复制文件
* @return bool
*/
public function installDir()
{
$from_admin_dir = $this->install_addon_path . 'admin' . DIRECTORY_SEPARATOR;
$from_web_dir = $this->install_addon_path . 'web' . DIRECTORY_SEPARATOR;
$from_wap_dir = $this->install_addon_path . 'uni-app' . DIRECTORY_SEPARATOR;
$from_resource_dir = $this->install_addon_path . 'resource' . DIRECTORY_SEPARATOR;
// 放入的文件
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
// 安装admin管理端
if (file_exists($from_admin_dir)) {
dir_copy($from_admin_dir, $to_admin_dir, $this->files['admin'], exclude_dirs:['icon']);
// 判断图标目录是否存在
if (is_dir($from_admin_dir . 'icon')) {
$addon_icon_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'styles' . DIRECTORY_SEPARATOR . 'icon' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon;
dir_copy($from_admin_dir . 'icon', $addon_icon_dir);
}
// 编译后台图标库文件
$this->compileAdminIcon();
}
// 安装电脑端
if (file_exists($from_web_dir)) {
// 安装布局文件
$layout = $from_web_dir . 'layouts';
if (is_dir($layout)) {
dir_copy($layout, $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'layouts');
del_target_dir($layout, true);
}
dir_copy($from_web_dir, $to_web_dir, $this->files['web']);
}
// 安装手机端
if (file_exists($from_wap_dir)) {
dir_copy($from_wap_dir, $to_wap_dir, $this->files['wap']);
}
//安装资源文件
if (file_exists($from_resource_dir)) {
dir_copy($from_resource_dir, $to_resource_dir, $this->files['resource']);
}
return true;
}
/**
* 编译后台图标库文件
* 图标开发注意事项,不能占用 iconfont、icon 关键词(会跟系统图标冲突),建议增加业务前缀,比如 旅游业recharge
* @return bool
*/
public function compileAdminIcon()
{
$compile_path = $this->root_path . str_replace('/', DIRECTORY_SEPARATOR, 'admin/src/styles/icon/');
$content = "";
$root_path = $compile_path . 'addon'; // 插件图标根目录
$file_arr = getFileMap($root_path);
if (!empty($file_arr)) {
foreach ($file_arr as $ck => $cv) {
if (str_contains($cv, '.css')) {
$path = str_replace($root_path . '/', '', $ck);
$path = str_replace('/.css', '', $path);
$content .= "@import \"addon/{$path}\";\n";
}
}
}
file_put_contents($compile_path . 'addon-iconfont.css', $content);
return true;
}
public function installSql()
{
$sql = $this->install_addon_path . 'sql' . DIRECTORY_SEPARATOR . 'install.sql';
$this->executeSql($sql);
return true;
}
/**
* 执行sql
* @param string $sql_file
* @return bool
*/
public static function executeSql(string $sql_file): bool
{
if (is_file($sql_file)) {
$sql = file_get_contents($sql_file);
// 执行sql
$sql_arr = parse_sql($sql);
if (!empty($sql_arr)) {
$prefix = config('database.connections.mysql.prefix');
Db::startTrans();
try {
foreach ($sql_arr as $sql_line) {
$sql_line = trim($sql_line);
if (!empty($sql_line)) {
$sql_line = str_ireplace('{{prefix}}', $prefix, $sql_line);
$sql_line = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $sql_line);
Db::execute($sql_line);
}
}
Db::commit();
return true;
} catch ( PDOException $e ) {
Db::rollback();
throw new AddonException($e->getMessage());
}
}
}
return true;
}
/**
* 执行插件install方法
* @return true
*/
public function handleAddonInstall()
{
$core_addon_service = new CoreAddonService();
$fail_addon = $this->install_task['fail_addon'] ?? [];
foreach ($this->addon_list as $addon) {
if (in_array($addon, $fail_addon)) continue;
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
// 执行安装sql
$this->installSql();
// 安装菜单
$this->installMenu();
// 安装计划任务
$this->installSchedule();
$install_data = $this->getAddonConfig($this->addon);
$install_data['icon'] = 'addon/' . $this->addon . '/icon.png';
$core_addon_service->set($install_data);
//执行插件安装方法
$class = "addon\\" . $this->addon . "\\" . 'Addon';
if (class_exists($class)) {
(new $class())->install();
}
}
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
// 清除插件安装中标识
Cache::delete('install_task');
Cache::delete($this->cache_key . '_install_check');
return true;
}
/**
* 合并依赖
* @return void
*/
public function installDepend()
{
(new CoreDependService())->installDepend($this->addon);
}
/**
* 备份前端页面
* @return void
*/
public function backupFrontend() {
$backup_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'frontend' . DIRECTORY_SEPARATOR;
if (is_dir($backup_dir)) del_target_dir($backup_dir, true);
foreach (['admin', 'wap', 'web'] as $port) {
$to_dir = public_path() . $port;
if (is_dir($to_dir)) {
if (is_dir($backup_dir . $port)) del_target_dir($backup_dir . $port, true);
// 备份原目录
dir_copy($to_dir, $backup_dir . $port);
}
}
}
/**
* 还原被覆盖前的文件
* @return void
*/
public function revertFrontendBackup() {
$backup_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'frontend' . DIRECTORY_SEPARATOR;
$backup_file = [];
search_dir($backup_dir, $backup_file);
if (!empty($backup_file)) {
dir_copy(public_path(), $backup_dir);
@del_target_dir($backup_dir, true);
}
}
/**
* 插件编译文件覆盖
* @return void
*/
public function coverCompile() {
$compile = $this->getAddonConfig($this->addon)['compile'];
foreach ($compile as $port) {
$to_dir = public_path() . $port;
$from_dir = $this->addon_path . 'compile' . DIRECTORY_SEPARATOR . $port;
if (is_dir($from_dir) && is_dir($to_dir)) {
// 删除后覆盖目录
del_target_dir($to_dir, true);
dir_copy($from_dir, $to_dir . $port);
}
}
}
/**
* 云安装
* @return void
*/
public function cloudInstall() {
(new CoreAddonCloudService())->cloudBuild($this->addon);
}
/**
* 插件卸载环境检测
* @return array|array[]
*/
public function uninstallCheck() {
$data = [
// 目录检测
'dir' => [
// 要求可读权限
'is_readable' => [],
// 要求可写权限
'is_write' => []
]
];
// 将要删除的根目录
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
if (is_dir($to_admin_dir)) $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_admin_dir), 'status' => is_write($to_admin_dir)];
if (is_dir($to_web_dir)) $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_web_dir), 'status' => is_write($to_web_dir)];
if (is_dir($to_wap_dir)) $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_wap_dir), 'status' => is_write($to_wap_dir)];
if (is_dir($to_resource_dir)) $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_resource_dir), 'status' => is_write($to_resource_dir)];
$check_res = array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status')
);
// 是否通过校验
$data['is_pass'] = !in_array(false, $check_res);
return $data;
}
/**
* 卸载插件
* @return true
*/
public function uninstall()
{
$site_groups = (new SiteGroup())->where([ ['app|addon', 'like', "%\"$this->addon\"%"] ])->column("group_id");
if (!empty($site_groups)) {
$site_num = (new Site())->where([ ['group_id', 'in', $site_groups] ])->count('site_id');
if ($site_num) throw new CommonException('APP_NOT_ALLOW_UNINSTALL');
}
(new CoreAddonDevelopBuildService())->build($this->addon);
//执行插件卸载方法
$class = "addon\\" . $this->addon . "\\" . 'Addon';
if (class_exists($class)) {
(new $class())->uninstall();
}
$core_addon_service = new CoreAddonService();
$addon_info = $core_addon_service->getInfoByKey($this->addon);
if (empty($addon_info)) throw new AddonException('NOT_UNINSTALL');
if (!$this->uninstallSql()) throw new AddonException('ADDON_SQL_FAIL');
// 卸载菜单
$this->uninstallMenu();
// 卸载计划任务
$this->uninstallSchedule();
// 卸载wap
$this->uninstallWap();
// 还原备份
if (!empty($addon_info['compile'])) (new CoreAddonCompileHandleService())->revertBackup();
$core_addon_service = new CoreAddonService();
$core_addon_service->delByKey($this->addon);
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
return true;
}
/**
* 卸载数据库
* @return true
*/
public function uninstallSql()
{
$sql = $this->install_addon_path . 'sql' . DIRECTORY_SEPARATOR . 'uninstall.sql';
$this->executeSql($sql);
return true;
}
/**
* 卸载插件
* @return true
*/
public function uninstallDir()
{
// 将要删除的根目录
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_web_layouts = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'layouts' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
// 卸载admin管理端
if (is_dir($to_admin_dir)) del_target_dir($to_admin_dir, true);
// 移除admin图标
$addon_icon_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'styles' . DIRECTORY_SEPARATOR . 'icon' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon;
if (is_dir($addon_icon_dir)) del_target_dir($addon_icon_dir, true);
// 编译后台图标库文件
$this->compileAdminIcon();
// 卸载pc端
if (is_dir($to_web_dir)) del_target_dir($to_web_dir, true);
if (is_dir($to_web_layouts)) del_target_dir($to_web_layouts, true);
// 卸载手机端
if (is_dir($to_wap_dir)) del_target_dir($to_wap_dir, true);
//删除资源文件
if (is_dir($to_resource_dir)) del_target_dir($to_resource_dir, true);
//todo 卸载插件目录涉及到的空文件
return true;
}
/**
* 卸载菜单
* @return true
* @throws DbException
*/
public function uninstallMenu()
{
$core_menu_service = new CoreMenuService();
$core_menu_service->deleteByAddon($this->addon);
Cache::tag(MenuService::$cache_tag_name)->clear();
return true;
}
/**
* 卸载计划任务
* @return true
*/
public function uninstallSchedule()
{
(new CoreScheduleInstallService())->uninstallAddonSchedule($this->addon);
return true;
}
/**
* 卸载手机端
* @return void
*/
public function uninstallWap()
{
// 编译 diy-group 自定义组件代码文件
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
// 编译 pages.json 页面路由代码文件
$this->uninstallPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR);
// 编译 加载插件标题语言包
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
}
/**
* 安装插件菜单
* @return true
*/
public function installMenu()
{
(new CoreMenuService)->refreshAddonMenu($this->addon);
Cache::tag(MenuService::$cache_tag_name)->clear();
return true;
}
/**
* 安装手机端
* @return void
*/
public function installWap()
{
// 编译 diy-group 自定义组件代码文件
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 pages.json 页面路由代码文件
$this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 加载插件标题语言包
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
}
public function download()
{
}
public function edit()
{
}
/**
* 更新composer依赖
* @return true
*/
public function updateComposer()
{
$result = Terminal::execute(root_path(), 'composer update');
if ($result !== true) {
throw new CommonException($result);
}
return $result;
}
/**
* 更新admin端依赖
* @return true
*/
public function updateAdminDependencies()
{
$result = Terminal::execute(root_path() . '../admin/', 'npm install');
if ($result !== true) {
throw new CommonException($result);
}
return $result;
}
/**
* 更新手机端依赖
* @return true
*/
public function updateWapDependencies()
{
$result = Terminal::execute(root_path() . '../uni-app/', 'npm install');
if ($result !== true) {
throw new CommonException($result);
}
return $result;
}
/**
* 更新web端依赖
* @return true
*/
public function updateWebDependencies()
{
$result = Terminal::execute(root_path() . '../web/', 'npm install');
if ($result !== true) {
throw new CommonException($result);
}
return $result;
}
/**
* 安装完成 销毁插件实例
* @return true
*/
public function installComplete()
{
return true;
}
/**
* 安装计划任务
* @return true
*/
public function installSchedule()
{
(new CoreScheduleInstallService())->installAddonSchedule($this->addon);
return true;
}
/**
* 处理编译之后的文件
* @return true
*/
public function handleBuildFile() {
return true;
}
}

View File

@ -0,0 +1,401 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\addon;
/**
* 编译手机端文件
*/
trait WapTrait
{
// TODO 主题色调 theme
// TODO 图标库 iconfont
/**
* 编译 diy-group 自定义组件代码文件
* @param $compile_path
* @param $addon
* @return false|int
*/
public function compileDiyComponentsCode($compile_path, $addon)
{
$content = "<template>\n";
$content .= " <view class=\"diy-group\" id=\"componentList\">\n";
$content .= " <top-tabbar :scrollBool=\"diyGroup.componentsScrollBool.TopTabbar\" v-if=\"data.global && Object.keys(data.global).length && data.global.topStatusBar && data.global.topStatusBar.isShow\" ref=\"topTabbarRef\" :data=\"data.global\" />\n";
$content .= " <pop-ads v-if=\"data.global && Object.keys(data.global).length && data.global.popWindow && data.global.popWindow.show\" ref=\"popAbsRef\" :data=\"data.global\" />\n";
$content .= " <template v-for=\"(component, index) in data.value\" :key=\"component.id\">\n";
$content .= " <view v-show=\"component.componentIsShow\"\n";
$content .= " @click=\"diyStore.changeCurrentIndex(index, component)\"\n";
$content .= " :class=\"diyGroup.getComponentClass(index,component)\" :style=\"component.pageStyle\">\n";
$content .= " <view class=\"relative\" :style=\"{ marginTop : component.margin.top < 0 ? (component.margin.top * 2) + 'rpx' : '0', marginBottom : component.margin.bottom < 0 ? (component.margin.bottom * 2) + 'rpx' : '0' }\">\n";
$content .= " <!-- 装修模式下,设置负上边距后超出的内容,禁止选中设置 -->\n";
$content .= " <view v-if=\"diyGroup.isShowPlaceHolder(index,component)\" class=\"absolute w-full z-1\" :style=\"{ height : (component.margin.top * 2 * -1) + 'rpx' }\" @click.stop=\"diyGroup.placeholderEvent\"></view>\n";
$root_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'app/components/diy'); // 系统自定义组件根目录
$file_arr = getFileMap($root_path);
if (!empty($file_arr)) {
foreach ($file_arr as $ck => $cv) {
if (str_contains($cv, 'index.vue')) {
$path = str_replace($root_path . '/', '', $ck);
$path = str_replace('/index.vue', '', $path);
if ($path == 'group') {
continue;
}
// 获取自定义组件 key 关键词
$name_arr = explode('-', $path);
foreach ($name_arr as $k => $v) {
// 首字母大写
$name_arr[ $k ] = strtoupper($v[ 0 ] ?? '') . substr($v, 1);
}
$name = implode('', $name_arr);
$file_name = 'diy-' . $path;
$content .= " <template v-if=\"component.componentName == '{$name}'\">\n";
$event_str = '$event';
$content .= " <$file_name ref=\"diy{$name}Ref\" :component=\"component\" :global=\"data.global\" :index=\"index\" :scrollBool=\"diyGroup.componentsScrollBool.{$name}\" @update:componentIsShow=\"component.componentIsShow = {$event_str}\" />\n";
$content .= " </template>\n";
}
}
}
// 查询已安装的插件
$addon_import_content = "";
$addon_service = new CoreAddonService();
$addon_list = $addon_service->getInstallAddonList();
$addon_arr = [];
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
$addon_arr[] = $v[ 'key' ];
}
}
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $k => $v) {
$addon_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/' . $v . '/components/diy'); // 插件自定义组件根目录
$addon_file_arr = getFileMap($addon_path);
if (!empty($addon_file_arr)) {
foreach ($addon_file_arr as $ck => $cv) {
if (str_contains($cv, 'index.vue')) {
$path = str_replace($addon_path . '/', '', $ck);
$path = str_replace('/index.vue', '', $path);
// 获取自定义组件 key 关键词
$name_arr = explode('-', $path);
foreach ($name_arr as $nk => $nv) {
// 首字母大写
$name_arr[ $nk ] = strtoupper($nv[ 0 ] ?? '') . substr($nv, 1);
}
$name = implode('', $name_arr);
$file_name = 'diy-' . $path;
$content .= " <template v-if=\"component.componentName == '{$name}'\">\n";
$event_str = '$event';
$content .= " <$file_name ref=\"diy{$name}Ref\" :component=\"component\" :global=\"data.global\" :index=\"index\" :scrollBool=\"diyGroup.componentsScrollBool.{$name}\" @update:componentIsShow=\"component.componentIsShow = {$event_str}\" />\n";
$content .= " </template>\n";
$addon_import_content .= " import diy{$name} from '@/addon/" . $v . "/components/diy/{$path}/index.vue';\n";
}
}
}
}
$content .= " </view>\n";
$content .= " </view>\n";
$content .= " </template>\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && diyGroup.showCopyright.value && data.global.copyright && data.global.copyright.isShow\">\n";
$content .= " <copy-right :textColor=\"data.global.copyright.textColor\" />\n";
$content .= " </template>\n\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && data.global.bottomTabBar && data.global.bottomTabBar.isShow\">\n";
$content .= " <view class=\"pt-[20rpx]\"></view>\n";
$content .= " <tabbar :addon=\"data.global.bottomTabBar.designNav.key\" />\n";
$content .= " </template>\n";
$content .= " </view>\n";
$content .= "</template>\n";
$content .= "<script lang=\"ts\" setup>\n";
if (!empty($addon_import_content)) {
$content .= $addon_import_content;
}
$content .= " import topTabbar from '@/components/top-tabbar/top-tabbar.vue'\n";
$content .= " import popAds from '@/components/pop-ads/pop-ads.vue'\n";
$content .= " import useDiyStore from '@/app/stores/diy';\n";
$content .= " import { useDiyGroup } from './useDiyGroup';\n";
$content .= " import { ref,getCurrentInstance } from 'vue';\n\n";
$content .= " const props = defineProps(['data']);\n";
$content .= " const instance: any = getCurrentInstance();\n";
$content .= " const getFormRef = () => {\n";
$content .= " return {\n";
$content .= " componentRefs: instance.refs\n";
$content .= " }\n";
$content .= " }\n";
$content .= " const diyStore = useDiyStore();\n";
$content .= " const diyGroup = useDiyGroup({\n";
$content .= " ...props,\n";
$content .= " getFormRef\n";
$content .= " });\n";
$content .= " const data = ref(diyGroup.data);\n\n";
$content .= " // 监听页面加载完成\n";
$content .= " diyGroup.onMounted();\n\n";
$content .= " // 监听滚动事件\n";
$content .= " diyGroup.onPageScroll();\n";
$content .= " defineExpose({\n";
$content .= " refresh: diyGroup.refresh,\n";
$content .= " getFormRef\n";
$content .= " })\n";
$content .= "</script>\n";
$content .= "<style lang=\"scss\" scoped>\n";
$content .= " @import './index.scss';\n";
$content .= "</style>\n";
return file_put_contents($compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/components/diy/group/index.vue'), $content);
}
/**
* 编译 pages.json 页面路由代码文件,// {{PAGE}}
* @param $compile_path
* @return bool|int|void
*/
public function installPageCode($compile_path, $addon = '')
{
if (!file_exists($this->geAddonPackagePath($this->addon) . 'uni-app-pages.php')) return;
$uniapp_pages = require $this->geAddonPackagePath($this->addon) . 'uni-app-pages.php';
if (empty($uniapp_pages[ 'pages' ])) {
return;
}
$pages = [];
$addon_service = new CoreAddonService();
$addon_list = $addon_service->getInstallAddonList();
$addon_arr = [];
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
$addon_arr[] = $v[ 'key' ];
}
}
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $addon) {
if (!file_exists($this->geAddonPackagePath($addon) . 'uni-app-pages.php')) continue;
$uniapp_pages = require $this->geAddonPackagePath($addon) . 'uni-app-pages.php';
if (empty($uniapp_pages[ 'pages' ])) continue;
$page_begin = strtoupper($addon) . '_PAGE_BEGIN';
$page_end = strtoupper($addon) . '_PAGE_END';
// 对0.2.0之前的版本做处理
$uniapp_pages[ 'pages' ] = preg_replace_callback('/(.*)(\\r\\n.*\/\/ PAGE_END.*)/s', function ($match) {
return $match[ 1 ] . ( substr($match[ 1 ], -1) == ',' ? '' : ',' ) . $match[ 2 ];
}, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('PAGE_BEGIN', $page_begin, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('PAGE_END', $page_end, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('{{addon_name}}', $addon, $uniapp_pages[ 'pages' ]);
$pages[] = $uniapp_pages[ 'pages' ];
}
$content = @file_get_contents($compile_path . "pages.json");
$content = preg_replace_callback('/(.*\/\/ \{\{ PAGE_BEGAIN \}\})(.*)(\/\/ \{\{ PAGE_END \}\}.*)/s', function ($match) use ($pages) {
return $match[ 1 ] . PHP_EOL . implode(PHP_EOL, $pages) . PHP_EOL . $match[ 3 ];
}, $content);
// 找到页面路由文件 pages.json写入内容
return file_put_contents($compile_path . "pages.json", $content);
}
/**
* 编译 pages.json 页面路由代码文件
* @param $compile_path
* @return bool|int|void
*/
public function uninstallPageCode($compile_path)
{
if (!file_exists($this->geAddonPackagePath($this->addon) . 'uni-app-pages.php')) return;
$uniapp_pages = require $this->geAddonPackagePath($this->addon) . 'uni-app-pages.php';
if (empty($uniapp_pages[ 'pages' ])) {
return;
}
$pages = [];
$addon_arr = array_diff(array_column(( new CoreAddonService() )->getInstallAddonList(), 'key'), [ $this->addon ]);
foreach ($addon_arr as $addon) {
if (!file_exists($this->geAddonPackagePath($addon) . 'uni-app-pages.php')) continue;
$uniapp_pages = require $this->geAddonPackagePath($addon) . 'uni-app-pages.php';
if (empty($uniapp_pages[ 'pages' ])) continue;
$page_begin = strtoupper($addon) . '_PAGE_BEGIN';
$page_end = strtoupper($addon) . '_PAGE_END';
$uniapp_pages[ 'pages' ] = str_replace('PAGE_BEGIN', $page_begin, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('PAGE_END', $page_end, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('{{addon_name}}', $addon, $uniapp_pages[ 'pages' ]);
$pages[] = $uniapp_pages[ 'pages' ];
}
$content = @file_get_contents($compile_path . "pages.json");
$content = preg_replace_callback('/(.*\/\/ \{\{ PAGE_BEGAIN \}\})(.*)(\/\/ \{\{ PAGE_END \}\}.*)/s', function ($match) use ($pages) {
return $match[ 1 ] . PHP_EOL . implode(PHP_EOL, $pages) . PHP_EOL . $match[ 3 ];
}, $content);
// 找到页面路由文件 pages.json写入内容
return file_put_contents($compile_path . "pages.json", $content);
}
/**
* 编译 加载插件标题语言包
* @param $compile_path
* @param $addon
*/
public function compileLocale($compile_path, $addon)
{
$locale_data = [];
$root_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'locale'); // 系统语言包根目录
$file_arr = getFileMap($root_path, []);
if (!empty($file_arr)) {
foreach ($file_arr as $ck => $cv) {
if (str_contains($cv, '.json')) {
$app_json = @file_get_contents($ck);
$json = json_decode($app_json, true);
// 清空当前安装/卸载的插件语言包
foreach ($json as $jk => $jc) {
if (is_array($addon)) {
foreach ($addon as $key) {
if (strpos($jk, $key) !== false) {
unset($json[ $jk ]);
}
}
} else {
if (strpos($jk, $addon) !== false) {
unset($json[ $jk ]);
}
}
}
$locale_data[ $cv ] = [
'path' => $ck,
'json' => $json
];
}
}
}
// 查询已安装的插件
$addon_service = new CoreAddonService();
$addon_list = $addon_service->getInstallAddonList();
$addon_arr = [];
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
$addon_arr[] = $v[ 'key' ];
}
}
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $k => $v) {
$addon_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/' . $v . '/locale'); // 插件语言包根目录
$addon_file_arr = getFileMap($addon_path, []);
if (!empty($addon_file_arr)) {
foreach ($addon_file_arr as $ck => $cv) {
if (str_contains($cv, '.json')) {
$json = @file_get_contents($ck);
$json = json_decode($json, true);
$addon_json = [];
foreach ($json as $jk => $jv) {
$addon_json[ $v . '.' . $jk ] = $jv;
}
if (isset($locale_data[ $cv ])) $locale_data[ $cv ][ 'json' ] = array_merge($locale_data[ $cv ][ 'json' ], $addon_json);
}
}
}
}
foreach ($locale_data as $k => $v) {
file_put_contents($v[ 'path' ], json_encode($v[ 'json' ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
}
}
/**
* 合并manifest.json
* @param string $compile_path
* @param array $merge_data
* @return void
*/
public function mergeManifestJson(string $compile_path, array $merge_data)
{
$manifest_json = str_replace('/', DIRECTORY_SEPARATOR, $compile_path . 'src/manifest.json');
$manifest_content = $this->jsonStringToArray(file_get_contents($manifest_json));
( new CoreAddonBaseService() )->writeArrayToJsonFile(array_merge2($manifest_content, $merge_data), $manifest_json);
}
/**
* json 字符串解析成数组
* @param $string
* @return array
*/
private function jsonStringToArray($string)
{
$list = explode("\n", $string);
$json_array = [];
foreach ($list as $index => $item) {
if (strpos($item, '/*') === false) {
$json_array[] = $item;
}
}
return json_decode(implode(PHP_EOL, $json_array), true);
}
}

View File

@ -0,0 +1 @@
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-6fd8f478.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

@ -0,0 +1 @@
import{dC as f}from"./index-6fd8f478.js";export{f as default};

View File

@ -0,0 +1 @@
import z from"./VerifySlide-3eaafa00.js";import g from"./VerifyPoints-fd48ca90.js";import{Q as k,r as o,l as w,ba 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,bb as j,v}from"./index-6fd8f478.js";import{_ as O}from"./_plugin-vue_export-helper-c27b6911.js";import"./index-f1634d30.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

@ -0,0 +1 @@
import{r as F,a as V,b as K,c as Z}from"./index-f1634d30.js";import{Q as G,bc as Q,r as s,n as m,aZ as X,h as H,c as I,a as l,x as A,Z as Y,_ as U,F as $,W as ee,t as L,ax as te}from"./index-6fd8f478.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}=G(N),{proxy:n}=Q(),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)})};X(()=>{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};Z(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"})},[Y(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

@ -0,0 +1 @@
import{d as V,y as B,f as N,r as x,aZ 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,aH as I,aI as R,E as $,a_ as D,a$ as F,b0 as H,K,b1 as M,a9 as P}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as Q}from"./aliapp-6b51f887.js";const U={class:"main-container"},Z={class:"flex justify-between items-center"},z={class:"text-page-title"},G={class:"p-[20px]"},J={class:"panel-title !text-sm"},L={class:"text-[14px] font-[700]"},O={class:"text-[#999]"},W={class:"mt-[20px] mb-[40px] h-[32px]"},X={class:"text-[14px] font-[700]"},Y={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]"},bt=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 w=c=>{window.open(c,"_blank")},b=c=>{d.push({path:_.value})};return(c,l)=>{const g=I,y=R,m=$,i=D,C=F,u=H,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",z,n(e(v)),1)]),o(y,{modelValue:_.value,"onUpdate:modelValue":l[0]||(l[0]=r=>_.value=r),class:"my-[20px]",onTabChange:b},{default:s(()=>[o(g,{label:e(a)("weappAccessFlow"),name:"/channel/aliapp"},null,8,["label"])]),_:1},8,["modelValue"]),t("div",G,[t("h3",J,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",L,n(e(a)("weappAttestation")),1)]),description:s(()=>[t("span",O,n(e(a)("weappAttest")),1),t("div",W,[o(m,{type:"primary",onClick:l[1]||(l[1]=r=>w("https://open.alipay.com/develop/manage"))},{default:s(()=>[h(n(e(a)("clickAccess")),1)]),_:1})])]),_:1}),o(i,null,{title:s(()=>[t("p",X,n(e(a)("weappSetting")),1)]),description:s(()=>[t("span",Y,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{bt as default};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{d as B,y as T,f as $,r as c,aZ as q,b5 as I,o as M,h as R,c as W,e,w as t,a,t as o,u as n,q as s,i as u,aH as A,aI as L,E as U,a_ as j,a$ as D,b0 as F,b1 as G,a9 as H}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as P}from"./wechat-1fe17a88.js";const Z={class:"main-container"},z={class:"flex justify-between items-center"},J={class:"text-page-title"},K={class:"p-[20px]"},O={class:"panel-title !text-sm"},Q={class:"text-[14px] font-[700]"},X={class:"text-[#999]"},Y={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]"},at={class:"mt-[20px] mb-[40px] h-[32px]"},dt=B({__name:"access",setup(st){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=H;return R(),W("div",Z,[e(N,{class:"card !border-none",shadow:"never"},{default:t(()=>[a("div",z,[a("span",J,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(s)("accessFlow"),name:"/channel/app"},null,8,["label"]),e(v,{label:n(s)("versionManage"),name:"/channel/app/version"},null,8,["label"])]),_:1},8,["modelValue"]),a("div",K,[a("h3",O,o(n(s)("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(()=>[a("p",Q,o(n(s)("uniappApp")),1)]),description:t(()=>[a("span",X,o(n(s)("appAttestation1")),1),a("div",Y,[e(d,{type:"primary",onClick:i[1]||(i[1]=p=>w("https://dcloud.io/"))},{default:t(()=>[u(o(n(s)("toCreate")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[a("p",tt,o(n(s)("appSetting")),1)]),description:t(()=>[a("div",et,[e(d,{type:"primary",onClick:i[2]||(i[2]=p=>n(_).push("/channel/app/config"))},{default:t(()=>[u(o(n(s)("settingInfo")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[a("p",nt,o(n(s)("versionManage")),1)]),description:t(()=>[a("div",at,[e(d,{type:"primary",plain:"",onClick:i[3]||(i[3]=p=>n(_).push("/channel/app/version"))},{default:t(()=>[u(o(n(s)("releaseVersion")),1)]),_:1})])]),_:1})]),_:1})]),_:1})]),_:1})])]),_:1})])}}});export{dt as default};

View File

@ -0,0 +1 @@
import{d as W,y as $,f as j,r as u,aZ as F,b5 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,aH as M,aI as D,E as G,a_ as H,a$ as K,b0 as P,K as Q,b1 as Z,a9 as J}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as O}from"./wechat-1fe17a88.js";import{a as X}from"./wxoplatform-32bd4d63.js";const Y={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 O().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=()=>{X().then(({data:l})=>{window.open(l)})};return(l,c)=>{const m=M,B=D,i=G,x=H,V=K,g=P,q=Q,N=Z,T=J;return w(),y("div",Y,[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

@ -0,0 +1 @@
import{_ as o}from"./add-member.vue_vue_type_script_setup_true_lang-03eaad7d.js";import"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import"./member-08ee6cb9.js";export{o as default};

View File

@ -0,0 +1 @@
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 j,e as s,i as k,t as C,u as t,Z as z,bY as A,L as O,M as T,N as Z,E as K,V as S,a3 as Y}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{p as G,z as J,A as Q}from"./member-08ee6cb9.js";const W={class:"dialog-footer"},me=I({__name:"add-member",emits:["complete"],setup(X,{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 J().then(n=>{c=n.data}).catch(()=>{})},q=async n=>{if(i.value||!n)return;const e=Q;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 G(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=O,u=T,V=Z,h=K,F=S,H=Y;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(()=>[j("span",W,[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(()=>[z((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(A)(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

@ -0,0 +1 @@
import{_ as o}from"./add-table.vue_vue_type_script_setup_true_lang-1159c8a5.js";import"./index-6fd8f478.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-1d3824c5.js";export{o as default};

View File

@ -0,0 +1 @@
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,aj as z,L as q,E as F,ak as P,V as U,a3 as j}from"./index-6fd8f478.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 G,l as I}from"./tools-1d3824c5.js";const le=L({__name:"add-table",setup(M,{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,G().then(a=>{e.loading=!1,e.data=a.data}).catch(()=>{e.loading=!1})};u();const w=a=>{const l=a.Name;e.loading=!0,I({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=j;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:S=>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

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

View File

@ -0,0 +1 @@
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 I,M as O,bI as $,N as j,E as A,V as S}from"./index-6fd8f478.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-e1949c05.js";const z={class:"dialog-footer"},X=U({__name:"add-theme",emits:["confirm"],setup(L,{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=I,u=O,E=$,C=j,c=A,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

@ -0,0 +1 @@
import{P as t}from"./index-6fd8f478.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

@ -0,0 +1 @@
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,ch as I,a6 as N,ci as U,b7 as L,M as R,a9 as S,N as T,E as j,a3 as q}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css */import A from"./index-68fc6f03.js";import"./el-form-item-4ed993c7.js";/* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-e1fd86ac.js";/* empty css *//* empty css */import"./attachment-ebf503f5.js";import"./index.vue_vue_type_script_setup_true_lang-80dd73f7.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-4a53fa0a.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-9a3bbef3.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

@ -0,0 +1 @@
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,cj as N,aj as T,E as j,ak as D,a9 as L,a3 as A}from"./index-6fd8f478.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 V={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=j,f=D,b=L,w=A;return m(),E("div",V,[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

@ -0,0 +1 @@
import{d as q,y as M,f as P,r as y,ck as S,n as T,l as $,q as r,h,c as I,e as a,w as s,u as n,b3 as U,Z as j,s as A,a as w,i as k,t as x,cl as L,cm as O,b4 as H,a9 as Z,L as z,M as G,N as J,E as K,a3 as Q}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css */import{_ as W}from"./index.vue_vue_type_script_setup_true_lang-5a405f05.js";import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-e1fd86ac.js";/* empty css *//* empty css */import"./attachment-ebf503f5.js";import"./index.vue_vue_type_script_setup_true_lang-80dd73f7.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-4a53fa0a.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-9a3bbef3.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(),I("div",X,[a(c,{class:"card !border-none",shadow:"never"},{default:s(()=>[a(o,{content:n(B),icon:n(U),onBack:e[0]||(e[0]=l=>p())},null,8,["content","icon"])]),_:1}),j((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

@ -0,0 +1 @@
import{P as t}from"./index-6fd8f478.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

@ -0,0 +1 @@
import{P as n}from"./index-6fd8f478.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

@ -0,0 +1 @@
import{_ as o}from"./app-version-edit.vue_vue_type_style_index_0_lang-6c9d6b3b.js";import"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-24610787.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import"./app-c876f7a6.js";import"./generate-sing-cert.vue_vue_type_script_setup_true_lang-5cf89bff.js";export{o as default};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
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,ca as b,H as w,E as z,K as H,b9 as K,cb as O,ab as P,a3 as U,p as W,g as Z}from"./index-6fd8f478.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-8de9fa57.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

@ -0,0 +1 @@
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,aH as V,aI as w,a9 as E}from"./index-6fd8f478.js";/* empty css *//* empty css */import k from"./attachment-ebf503f5.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-80dd73f7.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-4a53fa0a.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-9a3bbef3.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

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{d as b,r as d,n as w,I as m,l as g,R as c,h as F,s as E,w as i,e as n,a,Z as N,i as R,_ as j,aF as B,L as C,M as I,N as O}from"./index-6fd8f478.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),A=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 F(),E(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{A as default};

View File

@ -0,0 +1 @@
import{d as U,y as O,r as b,n as V,h as u,c as E,e as n,w as s,a as i,t as m,u as o,Z as z,s as p,q as l,bW as k,C as f,i as v,F as L,W as S,b7 as j,M as G,L as H,aD as I,aE as K,aF as P,bD as q,a9 as X,N as Z,E as $,a3 as J}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{d as Q,W as Y,X as ee}from"./member-08ee6cb9.js";const te={class:"main-container"},ae={class:"flex justify-between items-center"},oe={class:"text-page-title"},se={class:"text-[12px] text-[#999] leading-[24px]"},le=i("span",{class:"ml-2"},"%",-1),ne={class:"text-[12px] text-[#999] leading-[24px]"},re={class:"fixed-footer-wrap"},ie={class:"fixed-footer"},Fe=U({__name:"cash_out",setup(de){const C=O().meta.title,c=b(!0),g=b(),t=V({is_auto_transfer:"0",is_auto_verify:"0",is_open:"0",min:"0",rate:"0",transfer_type:[]}),y=b([]);(async()=>{y.value=await(await Q()).data})(),(async()=>{const d=await(await Y()).data;Object.keys(t).forEach(e=>{d[e]!=null&&(t[e]=d[e])}),c.value=!1})();const R=V({min:[{validator:(d,e,r)=>{Number(e)<.01?r(new Error(l("cashWithdrawalAmountHint"))):r()},trigger:"blur"}],rate:[{validator:(d,e,r)=>{Number(e)>100||Number(e)<0?r(new Error(l("commissionRatioHint"))):r()},trigger:"blur"}]}),F=async d=>{c.value||!d||await d.validate(e=>{if(e){const r={...t};ee(r).then(()=>{c.value=!1}).catch(()=>{c.value=!1})}})};return(d,e)=>{const r=j,_=G,h=H,x=I,N=K,D=P,T=q,w=X,W=Z,A=$,B=J;return u(),E("div",te,[n(w,{class:"box-card !border-none",shadow:"never"},{default:s(()=>[i("div",ae,[i("span",oe,m(o(C)),1)]),z((u(),p(W,{class:"page-form mt-[20px]",model:t,"label-width":"150px",ref_key:"ruleFormRef",ref:g,rules:R},{default:s(()=>[n(w,{class:"box-card !border-none",shadow:"never"},{default:s(()=>[n(_,{label:o(l)("isOpen")},{default:s(()=>[n(r,{modelValue:t.is_open,"onUpdate:modelValue":e[0]||(e[0]=a=>t.is_open=a),"active-value":"1","inactive-value":"0"},null,8,["modelValue"])]),_:1},8,["label"]),t.is_open?(u(),p(_,{key:0,label:o(l)("cashWithdrawalAmount"),prop:"min"},{default:s(()=>[i("div",null,[n(h,{modelValue:t.min,"onUpdate:modelValue":e[1]||(e[1]=a=>t.min=a),modelModifiers:{trim:!0},onKeyup:e[2]||(e[2]=a=>o(k)(a)),class:"input-width",placeholder:o(l)("cashWithdrawalAmountPlaceholder")},null,8,["modelValue","placeholder"]),i("div",se,m(o(l)("minTips")),1)])]),_:1},8,["label"])):f("",!0),t.is_open?(u(),p(_,{key:1,label:o(l)("commissionRatio"),prop:"rate"},{default:s(()=>[n(h,{modelValue:t.rate,"onUpdate:modelValue":e[3]||(e[3]=a=>t.rate=a),modelModifiers:{trim:!0},onKeyup:e[4]||(e[4]=a=>o(k)(a)),class:"input-width",placeholder:o(l)("commissionRatioPlaceholder")},null,8,["modelValue","placeholder"]),le]),_:1},8,["label"])):f("",!0),t.is_open?(u(),p(_,{key:2,label:o(l)("audit"),class:"items-center"},{default:s(()=>[n(N,{modelValue:t.is_auto_verify,"onUpdate:modelValue":e[5]||(e[5]=a=>t.is_auto_verify=a)},{default:s(()=>[n(x,{label:"0",size:"large"},{default:s(()=>[v(m(o(l)("manualAudit")),1)]),_:1}),n(x,{label:"1",size:"large"},{default:s(()=>[v(m(o(l)("automaticAudit")),1)]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["label"])):f("",!0),t.is_open?(u(),p(_,{key:3,label:o(l)("transferMode"),class:"items-baseline"},{default:s(()=>[i("div",null,[n(T,{modelValue:t.transfer_type,"onUpdate:modelValue":e[6]||(e[6]=a=>t.transfer_type=a),size:"large"},{default:s(()=>[(u(!0),E(L,null,S(y.value,(a,M)=>(u(),p(D,{label:a.key,key:"a"+M},{default:s(()=>[v(m(a.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"]),i("div",ne,m(o(l)("transferModeTips")),1)])]),_:1},8,["label"])):f("",!0)]),_:1})]),_:1},8,["model","rules"])),[[B,c.value]])]),_:1}),i("div",re,[i("div",ie,[n(A,{type:"primary",onClick:e[7]||(e[7]=a=>F(g.value))},{default:s(()=>[v(m(o(l)("save")),1)]),_:1})])])])}}});export{Fe as default};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
const e="公众号名称",c="公众号原始ID",t="公众号二维码",o="建议尺寸上传430px*430px宽高的二维码",n="开发者ID",a="开发者ID是公众号开发识别码配合开发者密码可调用公众号的接口能力。",s="开发者密码",i="开发者密码是校验公众号开发者身份的密码,具有极高的安全性",p="业务域名",h="JS接口安全域名",r="网页授权域名",l="公众号信息",d="公众号开发信息",w="消息推送配置",T="功能设置",g="在微信公众平台中,点击 设置与开发>公众号设置>功能设置,设置业务域名 JS接口安全域名 网页授权域名",S="必须为英文或数字长度为3-32字符。",A="消息加密密钥由43位字符组成可随机修改字符范围为A-Za-z0-9。",m="消息加解密方式",f="明文模式",P="兼容模式",D="安全模式(推荐)",M="请输入公众号名称",u="请输入公众号原始ID",y="请输入开发者ID",I="请输入开发者密码",b="请输入Token",x="请输入EncodingAESKey",B="明文模式下,不使用消息体加解密功能,安全系数较低",U="兼容模式下,明文、密文将共存,方便开发者调试和维护",k="安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高",K="借权域名",v="",E="默认留空填写后将替换https://open.weixin.gg.com/获取授权!",N={wechatName:e,wechatOriginal:c,wechatQrcode:t,wechatQrcodeTips:o,wechatAppid:n,wechatAppidTips:a,wechatAppsecret:s,wechatAppsecretTips:i,businessDomain:p,jsSecureDomain:h,webAuthDomain:r,wechatInfo:l,wechatDevelopInfo:d,theServerSetting:w,functionSetting:T,functionSettingTips:g,tokenTips:S,encodingAESKeyTips:A,encryptionType:m,cleartextMode:f,compatibleMode:P,safeMode:D,wechatNamePlaceholder:M,wechatOriginalPlaceholder:u,appidPlaceholder:y,appSecretPlaceholder:I,tokenPlaceholder:b,encodingAesKeyPlaceholder:x,cleartextModeTips:B,compatibleModeTips:U,safeModeTips:k,wechatBaseUri:K,wechatBaseUriPlaceholder:v,wechatBaseUriTips:E};export{I as appSecretPlaceholder,y as appidPlaceholder,p as businessDomain,f as cleartextMode,B as cleartextModeTips,P as compatibleMode,U as compatibleModeTips,N as default,A as encodingAESKeyTips,x as encodingAesKeyPlaceholder,m as encryptionType,T as functionSetting,g as functionSettingTips,h as jsSecureDomain,D as safeMode,k as safeModeTips,w as theServerSetting,b as tokenPlaceholder,S as tokenTips,r as webAuthDomain,n as wechatAppid,a as wechatAppidTips,s as wechatAppsecret,i as wechatAppsecretTips,K as wechatBaseUri,v as wechatBaseUriPlaceholder,E as wechatBaseUriTips,d as wechatDevelopInfo,l as wechatInfo,e as wechatName,M as wechatNamePlaceholder,c as wechatOriginal,u as wechatOriginalPlaceholder,t as wechatQrcode,o as wechatQrcodeTips};

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

@ -0,0 +1 @@
import{d as M,y as B,f as N,r as v,n as U,l as R,h as b,c as T,e as a,w as s,u as t,Z as D,s as $,a as n,t as d,q as l,i as m,b4 as L,a9 as P,L as F,E as K,M as O,N as S,a3 as j}from"./index-6fd8f478.js";/* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css */import{g as q,s as H}from"./app-c876f7a6.js";const Z={class:"main-container"},z={class:"panel-title !text-sm"},G={class:"form-tip flex items-center"},J={class:"form-tip"},Q={class:"form-tip"},W={class:"panel-title !text-sm"},X={class:"form-tip"},Y={class:"fixed-footer-wrap"},ee={class:"fixed-footer"},ce=M({__name:"config",setup(ae){const V=B(),y=N(),g=V.meta.title,r=v(!0),o=U({uni_app_id:"",app_name:"",android_app_key:"",application_id:"",wechat_app_id:"",wechat_app_secret:""}),f=v(),k=R(()=>({}));q().then(i=>{Object.assign(o,i.data),r.value=!1});const x=async i=>{r.value||!i||await i.validate(async e=>{e&&(r.value=!0,H(o).then(()=>{r.value=!1}).catch(()=>{r.value=!1}))})},h=i=>{window.open(i)},A=()=>{y.push("/channel/app")};return(i,e)=>{const C=L,_=P,c=F,w=K,u=O,I=S,E=j;return b(),T("div",Z,[a(_,{class:"card !border-none",shadow:"never"},{default:s(()=>[a(C,{content:t(g),icon:i.ArrowLeft,onBack:e[0]||(e[0]=p=>A())},null,8,["content","icon"])]),_:1}),D((b(),$(I,{class:"page-form mt-[15px]",model:o,"label-width":"170px",ref_key:"formRef",ref:f,rules:t(k)},{default:s(()=>[a(_,{class:"box-card !border-none mt-[15px]",shadow:"never"},{default:s(()=>[n("h3",z,d(t(l)("appInfo")),1),a(u,{label:t(l)("uniAppId"),prop:"uni_app_id"},{default:s(()=>[a(c,{modelValue:o.uni_app_id,"onUpdate:modelValue":e[1]||(e[1]=p=>o.uni_app_id=p),modelModifiers:{trim:!0},placeholder:"",class:"input-width",clearable:""},null,8,["modelValue"]),n("div",G,[m(d(t(l)("uniAppIdTips"))+" ",1),a(w,{link:"",type:"primary",onClick:e[2]||(e[2]=p=>h("https://www.dcloud.io/"))},{default:s(()=>[m(d(t(l)("toCreate")),1)]),_:1})])]),_:1},8,["label"]),a(u,{label:t(l)("appName"),prop:"app_name"},{default:s(()=>[a(c,{modelValue:o.app_name,"onUpdate:modelValue":e[3]||(e[3]=p=>o.app_name=p),modelModifiers:{trim:!0},placeholder:"",class:"input-width",clearable:""},null,8,["modelValue"])]),_:1},8,["label"]),a(u,{label:t(l)("androidAppKey"),prop:"android_app_key"},{default:s(()=>[a(c,{modelValue:o.android_app_key,"onUpdate:modelValue":e[4]||(e[4]=p=>o.android_app_key=p),modelModifiers:{trim:!0},placeholder:"",class:"input-width",clearable:""},null,8,["modelValue"]),n("div",J,[m(d(t(l)("androidAppKeyTips"))+" ",1),n("span",{class:"text-primary cursor-pointer",onClick:e[5]||(e[5]=p=>h("https://nativesupport.dcloud.net.cn/AppDocs/usesdk/appkey.html"))},"查看详情")])]),_:1},8,["label"]),a(u,{label:t(l)("applicationId"),prop:"application_id"},{default:s(()=>[a(c,{modelValue:o.application_id,"onUpdate:modelValue":e[6]||(e[6]=p=>o.application_id=p),modelModifiers:{trim:!0},placeholder:"",class:"input-width",clearable:""},null,8,["modelValue"]),n("div",Q,d(t(l)("applicationIdTips")),1)]),_:1},8,["label"])]),_:1}),a(_,{class:"box-card !border-none mt-[15px]",shadow:"never"},{default:s(()=>[n("h3",W,d(t(l)("wechatAppInfo")),1),a(u,{label:t(l)("wechatAppid"),prop:"app_id"},{default:s(()=>[a(c,{modelValue:o.wechat_app_id,"onUpdate:modelValue":e[7]||(e[7]=p=>o.wechat_app_id=p),modelModifiers:{trim:!0},placeholder:t(l)("appidPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"]),n("div",X,d(t(l)("wechatAppidTips")),1)]),_:1},8,["label"]),a(u,{label:t(l)("wechatAppsecret"),prop:"app_secret"},{default:s(()=>[a(c,{modelValue:o.wechat_app_secret,"onUpdate:modelValue":e[8]||(e[8]=p=>o.wechat_app_secret=p),modelModifiers:{trim:!0},placeholder:t(l)("appSecretPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1})]),_:1},8,["model","rules"])),[[E,r.value]]),n("div",Y,[n("div",ee,[a(w,{type:"primary",loading:r.value,onClick:e[9]||(e[9]=p=>x(f.value))},{default:s(()=>[m(d(t(l)("save")),1)]),_:1},8,["loading"])])])])}}});export{ce as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{P as b,d as S,y as B,r as v,n as R,b8 as D,b2 as F,R as I,$ as g,q as o,h as M,c as $,e as a,w as l,a as r,t as u,u as i,i as j,b7 as H,M as O,L as U,N as L,a9 as P,E as T}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{_ as z}from"./_plugin-vue_export-helper-c27b6911.js";function A(){return b.get("channel/h5/config")}function G(_){return b.put("channel/h5/config",_,{showSuccessMessage:!0})}const J={class:"main-container"},K={class:"flex justify-between items-center"},Q={class:"text-page-title"},W={class:"fixed-footer-wrap"},X={class:"fixed-footer"},Y=S({__name:"config",setup(_){const h=B().meta.title,n=v(!0),e=R({is_open:!0,request_url:""}),d=v();A().then(t=>{Object.assign(e,t.data),e.is_open=Boolean(Number(e.is_open)),n.value=!1}),D().then(t=>{e.request_url=t.data.wap_url+"/"});const{copy:y,isSupported:w,copied:m}=F(),x=t=>{if(!w.value){g({message:o("notSupportCopy"),type:"warning"});return}y(t)};I(m,()=>{m.value&&g({message:o("copySuccess"),type:"success"})});const C=()=>{window.open(e.request_url)},E=async t=>{n.value||!t||await t.validate(async s=>{if(s){n.value=!0;const c={...e};c.is_open=Number(c.is_open),G(c).then(()=>{n.value=!1}).catch(()=>{n.value=!1})}})};return(t,s)=>{const c=H,f=O,N=U,k=L,q=P,V=T;return M(),$("div",J,[a(q,{class:"box-card !border-none",shadow:"never"},{default:l(()=>[r("div",K,[r("span",Q,u(i(h)),1)]),a(k,{class:"page-form mt-[20px]",model:e,"label-width":"150px",ref_key:"formRef",ref:d},{default:l(()=>[a(f,{label:i(o)("isOpen")},{default:l(()=>[a(c,{modelValue:e.is_open,"onUpdate:modelValue":s[0]||(s[0]=p=>e.is_open=p)},null,8,["modelValue"])]),_:1},8,["label"]),a(f,{label:i(o)("h5DomainName")},{default:l(()=>[a(N,{"model-value":e.request_url,class:"input-width",readonly:!0},{append:l(()=>[r("div",{class:"cursor-pointer",onClick:s[1]||(s[1]=p=>x(e.request_url))},u(i(o)("copy")),1)]),_:1},8,["model-value"]),r("span",{class:"ml-2 cursor-pointer visit-btn",onClick:C},u(i(o)("clickVisit")),1)]),_:1},8,["label"])]),_:1},8,["model"])]),_:1}),r("div",W,[r("div",X,[a(V,{type:"primary",loading:n.value,onClick:s[2]||(s[2]=p=>E(d.value))},{default:l(()=>[j(u(i(o)("save")),1)]),_:1},8,["loading"])])])])}}});const ie=z(Y,[["__scopeId","data-v-8a5349bf"]]);export{ie as default};

View File

@ -0,0 +1 @@
import{P as b,d as S,y as B,r as v,n as R,b8 as D,b2 as F,R as I,$ as g,q as a,h as M,c as P,e as n,w as l,a as r,t as u,u as i,i as $,b7 as j,M as O,L as U,N as L,a9 as T,E as z}from"./index-6fd8f478.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{_ as A}from"./_plugin-vue_export-helper-c27b6911.js";function G(){return b.get("channel/pc/config")}function H(_){return b.put("channel/pc/config",_,{showSuccessMessage:!0})}const J={class:"main-container"},K={class:"flex justify-between items-center"},Q={class:"text-page-title"},W={class:"fixed-footer-wrap"},X={class:"fixed-footer"},Y=S({__name:"config",setup(_){const y=B().meta.title,o=v(!0),e=R({is_open:!1,request_url:""}),d=v();D().then(t=>{e.request_url=t.data.web_url+"/",o.value=!1}),G().then(t=>{Object.assign(e,t.data),e.is_open=Boolean(Number(e.is_open)),o.value=!1});const{copy:w,isSupported:h,copied:m}=F(),x=t=>{if(!h.value){g({message:a("notSupportCopy"),type:"warning"});return}w(t)};I(m,()=>{m.value&&g({message:a("copySuccess"),type:"success"})});const C=()=>{window.open(e.request_url)},E=async t=>{o.value||!t||await t.validate(async s=>{if(s){o.value=!0;const c={...e};c.is_open=Number(c.is_open),H(c).then(()=>{o.value=!1}).catch(()=>{o.value=!1})}})};return(t,s)=>{const c=j,f=O,N=U,k=L,q=T,V=z;return M(),P("div",J,[n(q,{class:"box-card !border-none",shadow:"never"},{default:l(()=>[r("div",K,[r("span",Q,u(i(y)),1)]),n(k,{class:"page-form mt-[20px]",model:e,"label-width":"150px",ref_key:"formRef",ref:d},{default:l(()=>[n(f,{label:i(a)("isOpen")},{default:l(()=>[n(c,{modelValue:e.is_open,"onUpdate:modelValue":s[0]||(s[0]=p=>e.is_open=p)},null,8,["modelValue"])]),_:1},8,["label"]),n(f,{label:i(a)("pCDomainName")},{default:l(()=>[n(N,{"model-value":e.request_url,class:"input-width",readonly:!0},{append:l(()=>[r("div",{class:"cursor-pointer",onClick:s[1]||(s[1]=p=>x(e.request_url))},u(i(a)("copy")),1)]),_:1},8,["model-value"]),r("span",{class:"ml-2 cursor-pointer visit-btn",onClick:C},u(i(a)("clickVisit")),1)]),_:1},8,["label"])]),_:1},8,["model"])]),_:1}),r("div",W,[r("div",X,[n(V,{type:"primary",loading:o.value,onClick:s[2]||(s[2]=p=>E(d.value))},{default:l(()=>[$(u(i(a)("save")),1)]),_:1},8,["loading"])])])])}}});const ie=A(Y,[["__scopeId","data-v-2f7e1e13"]]);export{ie as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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