mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-02-04 16:51:08 +00:00
同步admin
This commit is contained in:
parent
16a8825962
commit
ef43d9e616
143
admin/DEVELOPMENT_GUIDE.md
Normal file
143
admin/DEVELOPMENT_GUIDE.md
Normal 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类型检查
|
||||||
|
- 组件开发遵循高内聚低耦合原则
|
||||||
|
- 优先复用现有组件和工具函数
|
||||||
65
admin/package-lock.json
generated
65
admin/package-lock.json
generated
@ -9,12 +9,18 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.0.10",
|
"@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",
|
"@highlightjs/vue-plugin": "2.1.0",
|
||||||
"@types/lodash-es": "4.17.6",
|
"@types/lodash-es": "4.17.6",
|
||||||
"@vueuse/core": "9.12.0",
|
"@vueuse/core": "9.12.0",
|
||||||
"axios": "1.4.0",
|
"axios": "1.4.0",
|
||||||
"crypto-js": "4.1.1",
|
"crypto-js": "4.1.1",
|
||||||
"css-color-function": "1.3.3",
|
"css-color-function": "1.3.3",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"day": "^0.0.2",
|
"day": "^0.0.2",
|
||||||
"echarts": "5.4.1",
|
"echarts": "5.4.1",
|
||||||
"element-plus": "^2.7.4",
|
"element-plus": "^2.7.4",
|
||||||
@ -963,6 +969,47 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.1.6.tgz",
|
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.1.6.tgz",
|
||||||
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A=="
|
"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": {
|
"node_modules/@highlightjs/vue-plugin": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@highlightjs/vue-plugin/-/vue-plugin-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz",
|
||||||
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
"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": {
|
"node_modules/day": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/day/-/day-0.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/day/-/day-0.0.2.tgz",
|
||||||
@ -5003,6 +5059,15 @@
|
|||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
|
|||||||
@ -10,12 +10,18 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.0.10",
|
"@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",
|
"@highlightjs/vue-plugin": "2.1.0",
|
||||||
"@types/lodash-es": "4.17.6",
|
"@types/lodash-es": "4.17.6",
|
||||||
"@vueuse/core": "9.12.0",
|
"@vueuse/core": "9.12.0",
|
||||||
"axios": "1.4.0",
|
"axios": "1.4.0",
|
||||||
"crypto-js": "4.1.1",
|
"crypto-js": "4.1.1",
|
||||||
"css-color-function": "1.3.3",
|
"css-color-function": "1.3.3",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"day": "^0.0.2",
|
"day": "^0.0.2",
|
||||||
"echarts": "5.4.1",
|
"echarts": "5.4.1",
|
||||||
"element-plus": "^2.7.4",
|
"element-plus": "^2.7.4",
|
||||||
|
|||||||
@ -367,12 +367,16 @@ export function getCashOutDetail(id: number) {
|
|||||||
export function memberAudit(params: Record<string, any>) {
|
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
|
* @param params
|
||||||
*/
|
*/
|
||||||
export function memberCancel(params: Record<string, any>) {
|
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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -391,6 +395,7 @@ export function memberTransfer(params: Record<string, any>) {
|
|||||||
export function memberRemark(params: Record<string, any>) {
|
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
|
* @param id
|
||||||
@ -453,6 +458,7 @@ export function getGrowthRuleDict() {
|
|||||||
export function getPointRuleDict() {
|
export function getPointRuleDict() {
|
||||||
return request.get(`member/dict/point_rule`)
|
return request.get(`member/dict/point_rule`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************** 会员等级 ****************************************************/
|
/***************************************************** 会员等级 ****************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -512,14 +518,14 @@ export function getMemberLevelAll() {
|
|||||||
* 获取会员权益内容
|
* 获取会员权益内容
|
||||||
*/
|
*/
|
||||||
export function getMemberBenefitsContent() {
|
export function getMemberBenefitsContent() {
|
||||||
return request.get(`member/benefits/content`);
|
return request.post(`member/benefits/content`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取会员礼包内容
|
* 获取会员礼包内容
|
||||||
*/
|
*/
|
||||||
export function getMemberGiftsContent(params: Record<string, any>) {
|
export function getMemberGiftsContent(params: Record<string, any>) {
|
||||||
return request.get(`member/gifts/content`, { params });
|
return request.post(`member/gifts/content`, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
admin/src/app/assets/images/app_store/app_manage.png
Normal file
BIN
admin/src/app/assets/images/app_store/app_manage.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
admin/src/app/assets/images/app_store/app_type_addon.png
Normal file
BIN
admin/src/app/assets/images/app_store/app_type_addon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 B |
BIN
admin/src/app/assets/images/app_store/app_type_app.png
Normal file
BIN
admin/src/app/assets/images/app_store/app_type_app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 478 B |
BIN
admin/src/app/assets/images/app_store/system_version.png
Normal file
BIN
admin/src/app/assets/images/app_store/system_version.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 834 B |
@ -29,5 +29,8 @@
|
|||||||
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
|
"encodingAesKeyPlaceholder": "请输入EncodingAESKey",
|
||||||
"cleartextModeTips": "明文模式下,不使用消息体加解密功能,安全系数较低",
|
"cleartextModeTips": "明文模式下,不使用消息体加解密功能,安全系数较低",
|
||||||
"compatibleModeTips": "兼容模式下,明文、密文将共存,方便开发者调试和维护",
|
"compatibleModeTips": "兼容模式下,明文、密文将共存,方便开发者调试和维护",
|
||||||
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高"
|
"safeModeTips": "安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高",
|
||||||
|
"wechatBaseUri": "借权域名",
|
||||||
|
"wechatBaseUriPlaceholder": "",
|
||||||
|
"wechatBaseUriTips": "默认留空,填写后将替换https://open.weixin.gg.com/获取授权!"
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ const getMarketingList = async () => {
|
|||||||
// marketingList.value = res.data
|
// marketingList.value = res.data
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
getMarketingList()
|
// getMarketingList()
|
||||||
|
|
||||||
const toLink = (item: any) => {
|
const toLink = (item: any) => {
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
|
|||||||
@ -36,6 +36,11 @@
|
|||||||
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
|
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width" clearable />
|
||||||
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
|
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
|
||||||
</el-form-item>
|
</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>
|
||||||
|
|
||||||
<el-card class="box-card !border-none mt-[15px]" shadow="never">
|
<el-card class="box-card !border-none mt-[15px]" shadow="never">
|
||||||
@ -140,7 +145,8 @@ const formData = reactive<Record<string, any>>({
|
|||||||
token: '',
|
token: '',
|
||||||
encoding_aes_key: '',
|
encoding_aes_key: '',
|
||||||
encryption_type: 'not_encrypt',
|
encryption_type: 'not_encrypt',
|
||||||
is_authorization: 0
|
is_authorization: 0,
|
||||||
|
base_uri: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|||||||
@ -77,6 +77,9 @@
|
|||||||
<el-switch v-model="diyStore.global.copyright.isShow" />
|
<el-switch v-model="diyStore.global.copyright.isShow" />
|
||||||
<div class="text-sm text-gray-400">{{ t('此处控制当前页面版权信息是否显示') }}</div>
|
<div class="text-sm text-gray-400">{{ t('此处控制当前页面版权信息是否显示') }}</div>
|
||||||
</el-form-item>
|
</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>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-attr-item-wrap">
|
<div class="edit-attr-item-wrap">
|
||||||
|
|||||||
@ -455,7 +455,7 @@ initPage({
|
|||||||
diyStore.components.push(com)
|
diyStore.components.push(com)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log( component.value )
|
||||||
loadDiyTemplatePages(data.type)
|
loadDiyTemplatePages(data.type)
|
||||||
|
|
||||||
// 加载预览
|
// 加载预览
|
||||||
|
|||||||
@ -1,47 +1,127 @@
|
|||||||
<template>
|
<template>
|
||||||
<!--应用市场-->
|
<!--应用市场-->
|
||||||
<div class="main-container">
|
<div class="main-container bg-body min-h-[70vh]" v-loading="loading">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never" v-if="!loading">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex items-center mb-4">
|
||||||
<span class="text-page-title">{{ t("localAppText") }}</span>
|
<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>
|
</div>
|
||||||
|
|
||||||
<el-tabs v-model="activeName" class="mt-[10px]">
|
<!-- 系统版本栏 -->
|
||||||
<el-tab-pane :label="t('installLabel')" name="installed"></el-tab-pane>
|
<div class="flex items-center justify-between bg-body p-4 rounded-md border rounded border-solid border-[var(--el-color-info-light-8)]">
|
||||||
<el-tab-pane :label="t('uninstalledLabel')" name="uninstalled"></el-tab-pane>
|
<div class="flex">
|
||||||
<el-tab-pane :label="t('buyLabel')" name="all"></el-tab-pane>
|
<div class="flex items-center">
|
||||||
<el-tab-pane :label="t('recentlyUpdated')" name="recentlyUpdated">
|
<div class="w-[40px] h-[40px] bg-purple-100 rounded flex items-center justify-center mr-2 relative">
|
||||||
<template #label>
|
<img class="max-w-full max-h-full" src="@/app/assets/images/app_store/system_version.png" alt="" />
|
||||||
<span class="custom-tabs-label">
|
<div v-if="frameworkVersion != frameworkNewVersion" class="w-[8px] h-[8px] bg-[red] rounded-[8px] z-1 absolute top-[-2px] right-[-2px]"></div>
|
||||||
<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>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" v-show="activeName === 'recentlyUpdated'" @click="batchUpgrade" :loading="upgradeRef?.loading" :disabled="authLoading">{{ t("batchUpgrade") }}</el-button>
|
<p class="text-sm font-bold">系统版本:
|
||||||
<!-- <el-button type="primary" @click="handleCloudBuild" :loading="cloudBuildRef?.loading" :disabled="authLoading">{{ t("cloudBuild") }}</el-button> -->
|
<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'" @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>
|
||||||
|
|
||||||
|
<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>
|
||||||
<div class="relative">
|
</div>
|
||||||
<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 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">
|
<el-table-column width="24">
|
||||||
<template #default="{ row }">
|
<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)}">
|
<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 +129,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</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">
|
<el-table-column :label="t('appName')" align="left" width="500">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center cursor-pointer relative left-[-10px]">
|
<div class="flex items-center cursor-pointer relative left-[-10px]">
|
||||||
@ -139,6 +223,8 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<div class="h-[100px]" v-loading="loading" v-if="loading"></div>
|
<div class="h-[100px]" v-loading="loading" v-if="loading"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading && activeName == 'installed' && !authLoading">
|
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading && activeName == 'installed' && !authLoading">
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
@ -195,7 +281,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</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>
|
<template #image>
|
||||||
<div class="w-[230px] mx-auto">
|
<div class="w-[230px] mx-auto">
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="" />
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="" />
|
||||||
@ -205,7 +291,6 @@
|
|||||||
<p class="flex items-center">{{ t("recentlyUpdatedEmpty") }}</p>
|
<p class="flex items-center">{{ t("recentlyUpdatedEmpty") }}</p>
|
||||||
</template>
|
</template>
|
||||||
</el-empty>
|
</el-empty>
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
|
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
|
||||||
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||||
@ -265,9 +350,10 @@
|
|||||||
<div v-show="installStep == 0" v-loading="!installCheckResult.dir">
|
<div v-show="installStep == 0" v-loading="!installCheckResult.dir">
|
||||||
<!-- <el-scrollbar max-height="50vh"> -->
|
<!-- <el-scrollbar max-height="50vh"> -->
|
||||||
<div class="min-h-[150px]">
|
<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>
|
<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">
|
<div class="flex items-center">
|
||||||
<el-icon :size="17"><QuestionFilled /></el-icon>
|
<el-icon :size="17"><QuestionFilled /></el-icon>
|
||||||
<span class="ml-[5px] leading-[20px]">编译权限错误,查看解决方案</span></div>
|
<span class="ml-[5px] leading-[20px]">编译权限错误,查看解决方案</span></div>
|
||||||
@ -285,7 +371,6 @@
|
|||||||
<span>{{ t("status") }}</span>
|
<span>{{ t("status") }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</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-row class="pb-[10px] items pl-[15px]" v-for="(item, index) in installCheckResult.dir.is_readable" :key="index">
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<span>{{ item.dir }}</span>
|
<span>{{ item.dir }}</span>
|
||||||
@ -326,10 +411,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</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>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- </el-scrollbar> -->
|
<!-- </el-scrollbar> -->
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<el-tooltip effect="dark" placement="top">
|
<el-tooltip effect="dark" placement="top">
|
||||||
@ -465,7 +558,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 更新信息 -->
|
<!-- 更新信息 -->
|
||||||
</el-card>
|
|
||||||
</div>
|
</div>
|
||||||
<upgrade-log :upgradeKey="upgradeKey" ref="upgradeLogRef" />
|
<upgrade-log :upgradeKey="upgradeKey" ref="upgradeLogRef" />
|
||||||
<upgrade ref="upgradeRef" @complete="localListFn" @cloudbuild="handleCloudBuild" />
|
<upgrade ref="upgradeRef" @complete="localListFn" @cloudbuild="handleCloudBuild" />
|
||||||
@ -473,7 +565,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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 { t } from '@/lang'
|
||||||
import {
|
import {
|
||||||
getAddonLocal,
|
getAddonLocal,
|
||||||
@ -488,7 +580,7 @@ import {
|
|||||||
getAddonInit
|
getAddonInit
|
||||||
} from '@/app/api/addon'
|
} from '@/app/api/addon'
|
||||||
import { deleteAddonDevelop } from '@/app/api/tools'
|
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 { getVersions } from '@/app/api/auth'
|
||||||
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
||||||
import 'vue-web-terminal/lib/theme/dark.css'
|
import 'vue-web-terminal/lib/theme/dark.css'
|
||||||
@ -501,9 +593,10 @@ import Upgrade from '@/app/components/upgrade/index.vue'
|
|||||||
import CloudBuild from '@/app/components/cloud-build/index.vue'
|
import CloudBuild from '@/app/components/cloud-build/index.vue'
|
||||||
import UpgradeLog from '@/app/components/upgrade-log/index.vue'
|
import UpgradeLog from '@/app/components/upgrade-log/index.vue'
|
||||||
|
|
||||||
|
const tableRef = ref(null)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const terminalId = ref(Date.now());
|
const terminalId = ref(Date.now())
|
||||||
const activeName = ref(storage.get('storeActiveName') || 'installed')
|
const activeName = ref(storage.get('storeActiveName') || 'installed')
|
||||||
const upgradeRef = ref(null)
|
const upgradeRef = ref(null)
|
||||||
const cloudBuildRef = ref(null)
|
const cloudBuildRef = ref(null)
|
||||||
@ -514,10 +607,22 @@ const userStore = useUserStore()
|
|||||||
const unloadHintDialog = ref(false)
|
const unloadHintDialog = ref(false)
|
||||||
const terminalRef = ref(null)
|
const terminalRef = ref(null)
|
||||||
const frameworkVersion = ref('')
|
const frameworkVersion = ref('')
|
||||||
|
const frameworkVersionCode = ref('')
|
||||||
const upgradeLogRef = ref<any>(null)
|
const upgradeLogRef = ref<any>(null)
|
||||||
|
const showType = ref(storage.get('storeShowType') || 'card')
|
||||||
|
const frameworkNewVersion = ref('')
|
||||||
getVersions().then((res) => {
|
getVersions().then((res) => {
|
||||||
frameworkVersion.value = res.data.version.version
|
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 typeList = ref({})
|
||||||
const getAddonInitFn = () => {
|
const getAddonInitFn = () => {
|
||||||
@ -534,6 +639,12 @@ const downEventHintFn = () => {
|
|||||||
const activeNameTabFn = (data: any) => {
|
const activeNameTabFn = (data: any) => {
|
||||||
activeName.value = data
|
activeName.value = data
|
||||||
storage.set({ key: 'storeActiveName', 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) {
|
if (route.query.id) {
|
||||||
activeNameTabFn(route.query.id)
|
activeNameTabFn(route.query.id)
|
||||||
@ -603,26 +714,7 @@ const buildInfo = (list: any[]) => {
|
|||||||
|
|
||||||
return result
|
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 query = () => {
|
||||||
const name = search_name.value
|
const name = search_name.value
|
||||||
const type = search_type.value
|
const type = search_type.value
|
||||||
@ -689,6 +781,7 @@ const localListFn = () => {
|
|||||||
appLink.value[item.meta.app] = item.name
|
appLink.value[item.meta.app] = item.name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
activeNameTabFn(activeName.value)
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@ -909,6 +1002,7 @@ const handleCloudInstall = () => {
|
|||||||
installStep.value = 1
|
installStep.value = 1
|
||||||
terminalRef.value.execute('clear')
|
terminalRef.value.execute('clear')
|
||||||
terminalRef.value.execute('开始安装插件')
|
terminalRef.value.execute('开始安装插件')
|
||||||
|
if (res.data.length) installAfterTips.value = res.data
|
||||||
getInstallTask()
|
getInstallTask()
|
||||||
cloudInstalling.value = false
|
cloudInstalling.value = false
|
||||||
}).catch((res) => {
|
}).catch((res) => {
|
||||||
@ -1155,23 +1249,55 @@ const versionJudge = (row: any) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let batchUpgradeApp = []
|
const batchUpgradeApp = ref<String[]>([])
|
||||||
const handleSelectionChange = (e: any) => {
|
|
||||||
batchUpgradeApp = e.map(item => item.key)
|
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 = () => {
|
const batchUpgrade = () => {
|
||||||
if (!batchUpgradeApp.length) {
|
const appKeys = batchUpgradeApp.value
|
||||||
ElMessage({ message: '请先勾选要升级的插件', type: 'error', duration: 5000 })
|
if (frameworkVersion.value != frameworkNewVersion.value) {
|
||||||
|
appKeys.unshift('niucloud-admin')
|
||||||
|
}
|
||||||
|
if (!appKeys.length) {
|
||||||
|
ElMessage({ message: localList.recentlyUpdated.length ? '请先勾选要升级的插件' : '当前已是最新版', type: 'error', duration: 5000 })
|
||||||
return
|
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(() => {
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -1451,6 +1577,11 @@ html.dark .table-head-bg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-card {
|
||||||
|
width: calc((100% - 120px) / 5);
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -126,7 +126,9 @@ const prop = defineProps({
|
|||||||
},
|
},
|
||||||
ignore: {
|
ignore: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: () => {
|
||||||
|
return [] // 指定需要忽略的自定义链接,例如:['DIY_MAKE_PHONE_CALL'],表示隐藏拨打电话
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,7 @@ getUrl().then((res: any) => {
|
|||||||
|
|
||||||
// 生成H5二维码(支持多参数)
|
// 生成H5二维码(支持多参数)
|
||||||
const generateH5QRCode = () => {
|
const generateH5QRCode = () => {
|
||||||
|
console.log( params.value)
|
||||||
// 处理参数为URL格式
|
// 处理参数为URL格式
|
||||||
const queryStr = params.value
|
const queryStr = params.value
|
||||||
.map(item => `${encodeURIComponent(item.name)}=${encodeURIComponent(item.value)}`)
|
.map(item => `${encodeURIComponent(item.name)}=${encodeURIComponent(item.value)}`)
|
||||||
|
|||||||
@ -219,5 +219,10 @@
|
|||||||
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
|
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
|
||||||
"promoteUrl": "推广链接",
|
"promoteUrl": "推广链接",
|
||||||
"downLoadQRCode": "下载二维码",
|
"downLoadQRCode": "下载二维码",
|
||||||
"configureFailed": "配置失败"
|
"configureFailed": "配置失败",
|
||||||
|
"lefttitle": "左侧标题",
|
||||||
|
"righttitle": "右侧标题",
|
||||||
|
"leftDesc": "左侧简介",
|
||||||
|
"rightDesc": "右侧简介",
|
||||||
|
"descPlaceholder": "请输入简介内容"
|
||||||
}
|
}
|
||||||
@ -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-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-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 || 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" 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="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="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.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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -87,6 +87,7 @@ const useDiyStore = defineStore('diy', {
|
|||||||
copyright: {
|
copyright: {
|
||||||
control: true, // 是否允许展示编辑
|
control: true, // 是否允许展示编辑
|
||||||
isShow: false, // 是否显示
|
isShow: false, // 是否显示
|
||||||
|
textColor : "#ccc", // 文字颜色
|
||||||
},
|
},
|
||||||
// 弹框 count:不弹出 -1,首次弹出 1,每次弹出 0
|
// 弹框 count:不弹出 -1,首次弹出 1,每次弹出 0
|
||||||
popWindow: {
|
popWindow: {
|
||||||
@ -190,6 +191,7 @@ const useDiyStore = defineStore('diy', {
|
|||||||
copyright: {
|
copyright: {
|
||||||
control: true, // 是否允许展示编辑
|
control: true, // 是否允许展示编辑
|
||||||
isShow: true, // 是否显示
|
isShow: true, // 是否显示
|
||||||
|
textColor : "#ccc", // 文字颜色
|
||||||
},
|
},
|
||||||
|
|
||||||
// 弹框 count:不弹出 -1,首次弹出 1,每次弹出 0
|
// 弹框 count:不弹出 -1,首次弹出 1,每次弹出 0
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont";
|
font-family: "iconfont";
|
||||||
/* Project id 3883393 */
|
/* Project id 3883393 */
|
||||||
src: url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.woff2?t=1755603992297') format('woff2'),
|
src: url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.woff2?t=1762651161569') format('woff2'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.woff?t=1755603992297') format('woff'),
|
url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.woff?t=1762651161569') format('woff'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_6d60cyygl4.ttf?t=1755603992297') format('truetype');
|
url('//at.alicdn.com/t/c/font_3883393_0604cbkh5j03.ttf?t=1762651161569') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -14,6 +14,78 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-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 {
|
.icona-bijiPC30:before {
|
||||||
content: "\e90b";
|
content: "\e90b";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,9 +131,10 @@ export function img(path: string): string {
|
|||||||
|
|
||||||
if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '')
|
if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '')
|
||||||
if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1)
|
if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1)
|
||||||
|
if(path){
|
||||||
return isUrl(path) ? path : `${imgDomain}/${path}`
|
return isUrl(path) ? path : `${imgDomain}/${path}`
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出asset img
|
* 输出asset img
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user