Compare commits

...

9 Commits

Author SHA1 Message Date
wangchen14709853322
67e7669694 Create readme.md 2026-06-06 19:15:55 +08:00
wangchen14709853322
9f683839e6 1.2.4
新增 云编译排队机制
优化 授权域名校验忽略站点域名
修复 会员注册事件存在异常会导致会员码未生成的问题
2026-06-06 11:18:46 +08:00
wangchen147
44805a4a1f 处理编译内存溢出 2026-05-09 16:38:27 +08:00
wangchen147
0864a7a502 1.2.3
注意事项:本次升级后将不再支持调用官方的云编译服务,如需使用云编译功能需使用官方提供的第三方云编译程序自行启用云编译服务。

修复 本地开发时会验证授权信息的问题
优化 本版本更新后卸载插件会同时删除本地文件
修复 支付回调失败问题
优化 云编译失败后增加异常分析,可排除异常插件后重新编译
修复 云编译没有清除旧的编译文件
2026-05-08 14:30:00 +08:00
李玉
396eb8406d
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2026-05-06 09:40:42 +00:00
李玉
20db81d87e
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2026-04-29 01:10:32 +00:00
李玉
4309d7c458
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2026-04-20 09:12:13 +00:00
李玉
9ed68ca110
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2026-04-14 01:25:55 +00:00
李玉
b4ebe684b2
update README.md.
Signed-off-by: 李玉 <16193307+li-yu125521@user.noreply.gitee.com>
2026-04-07 08:38:54 +00:00
3885 changed files with 6498 additions and 2096 deletions

View File

@ -125,5 +125,5 @@ niucloud-admin-saas是一款快速开发通用管理后台框架整体功能
All rights reserved。 All rights reserved。
杭州数字云动科技有限公司 杭州数字云动科技有限公司
杭州牛之云科技有限公司 杭州牛之云科技有限公司
提供技术支持 提供技术支持

View File

@ -8,4 +8,4 @@ VITE_IMG_DOMAIN=''
VITE_REQUEST_HEADER_TOKEN_KEY='token' VITE_REQUEST_HEADER_TOKEN_KEY='token'
# 请求时header中站点的参数名 # 请求时header中站点的参数名
VITE_REQUEST_HEADER_SITEID_KEY='site-id' VITE_REQUEST_HEADER_SITEID_KEY='site-id'

View File

@ -1,143 +0,0 @@
# 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

@ -1,7 +1,6 @@
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
export {} export {}
declare global { declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElNotification: typeof import('element-plus/es')['ElNotification'] const ElNotification: typeof import('element-plus/es')['ElNotification']
} }

17
admin/components.d.ts vendored
View File

@ -21,22 +21,16 @@ declare module '@vue/runtime-core' {
ElCarousel: typeof import('element-plus/es')['ElCarousel'] ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
@ -44,27 +38,19 @@ declare module '@vue/runtime-core' {
ElImage: typeof import('element-plus/es')['ElImage'] ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMain: typeof import('element-plus/es')['ElMain'] ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElOptionGroup: typeof import('element-plus/es')['ElOptionGroup']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElResult: typeof import('element-plus/es')['ElResult'] ElResult: typeof import('element-plus/es')['ElResult']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem'] ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElStatistic: typeof import('element-plus/es')['ElStatistic'] ElStatistic: typeof import('element-plus/es')['ElStatistic']
ElStep: typeof import('element-plus/es')['ElStep'] ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps'] ElSteps: typeof import('element-plus/es')['ElSteps']
@ -77,10 +63,7 @@ declare module '@vue/runtime-core' {
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline'] ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem'] ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default'] ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default'] HeatMap: typeof import('./src/components/heat-map/index.vue')['default']

View File

@ -5,7 +5,7 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 && vite build && node publish.cjs", "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build && node publish.cjs",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {

View File

@ -31,7 +31,7 @@ export function installAddon(params: Record<string, any>) {
* @returns * @returns
*/ */
export function cloudInstallAddon(params: Record<string, any>) { export function cloudInstallAddon(params: Record<string, any>) {
return request.post(`addon/cloudinstall/${ params.addon }`, params) return request.post(`addon/cloudinstall/${ params.addon }`, params, { showErrorMessage: false })
} }
/** /**

View File

@ -1,36 +1,90 @@
import axios from 'axios'
import request from '@/utils/request' import request from '@/utils/request'
import storage from '@/utils/storage'
/** export const CLOUD_COMPILE_BASE_URL = 'http://go.site.niucloud.com'
*
*/ function createCloudCompileRequest() {
export function cloudBuild() { const instance = axios.create({
return request.post('niucloud/build', {}) baseURL: CLOUD_COMPILE_BASE_URL,
timeout: 0,
headers: {
'lang': storage.get('lang') ?? 'zh-cn'
}
})
instance.interceptors.request.use(
(config) => {
const token = storage.get('token')
if (token) {
config.headers['token'] = token
}
return config
},
(err) => {
return Promise.reject(err)
}
)
instance.interceptors.response.use(
(response) => {
return response.data
},
(err) => {
return Promise.reject(err)
}
)
return instance
}
const cloudCompileRequest = createCloudCompileRequest()
export function cloudBuild() {
return request.post('niucloud/build')
} }
/**
*
*/
export function getCloudBuildTask() { export function getCloudBuildTask() {
return request.get('niucloud/build') return request.get('niucloud/build')
} }
/**
*
*/
export function getCloudBuildLog() { export function getCloudBuildLog() {
return request.get('niucloud/build/log') return request.get('niucloud/build/log')
} }
/**
*
*/
export function clearCloudBuildTask() { export function clearCloudBuildTask() {
return request.post('niucloud/build/clear') return request.post('niucloud/build/clear', {}, { showErrorMessage: false, showSuccessMessage: false })
} }
/**
*
*/
export function preBuildCheck() { export function preBuildCheck() {
return request.get('niucloud/build/check') return request.get('niucloud/build/check')
} }
export function getCloudBuildQueuePosition(taskId: string) {
return cloudCompileRequest.get('/cloud/queue_position', { params: { task_id: taskId } })
}
export function getCloudBuildSseUrl(taskId: string): string {
return `${CLOUD_COMPILE_BASE_URL}/cloud/sse?task_id=${taskId}`
}
export function getCloudCompileLocalUrl() {
return request.get('niucloud/build/get_local_url')
}
export function setCloudCompileLocalUrl(url: string) {
return request.post('niucloud/build/set_local_url', { url })
}
export function startServerDownload(taskId: string, downloadUrl: string, authorizeCode: string, timestamp: string) {
return request.post('niucloud/build/start_server_download', {
task_id: taskId,
download_url: downloadUrl,
authorize_code: authorizeCode,
timestamp
})
}
export function getSseBuildLog(taskId: string) {
return request.get('niucloud/build/get_sse_build_log', { params: { task_id: taskId } })
}

View File

@ -77,6 +77,15 @@ export function getWeappUploadLog(key: string) {
return request.get(`weapp/upload/${ key }`) return request.get(`weapp/upload/${ key }`)
} }
/**
*
* @param key
* @returns
*/
export function fetchWeappUploadLog(key: string) {
return request.get(`weapp/upload_log/${ key }`)
}
/***************************************************** 管理端 ****************************************************/ /***************************************************** 管理端 ****************************************************/
/** /**

View File

@ -70,7 +70,8 @@
</div> </div>
<div class="flex justify-end mt-[20px]" v-show="cloudBuildTask"> <div class="flex justify-end mt-[20px]" v-show="cloudBuildTask">
<el-button @click="dialogCancel()" class="!w-[90px]">取消</el-button> <el-button @click="dialogCancel()" class="!w-[90px]">取消</el-button>
<el-button type="primary" :loading="timeloading" class="!w-[140px]">已用时 {{ formattedDuration }}</el-button> <el-button type="primary" :loading="timeloading" class="!w-[140px]" v-if="!errorInfo">已用时 {{ formattedDuration }}</el-button>
<el-button type="primary" @click="active = 'error'" v-if="errorInfo">下一步</el-button>
</div> </div>
</div> </div>
<div v-show="active == 'error'"> <div v-show="active == 'error'">
@ -81,10 +82,18 @@
<img src="@/app/assets/images/error_icon.png" alt=""> <img src="@/app/assets/images/error_icon.png" alt="">
</template> </template>
<template #extra> <template #extra>
<el-scrollbar class="max-h-[150px] !overflow-auto text-[15px] text-[#4F516D] mb-[15px] mt-[-15px]"> <el-scrollbar class="max-h-[150px] !overflow-auto text-[15px] text-[#4F516D] mb-[15px] mt-[-15px]" v-if="errorInfo">
{{errorInfo}} {{errorInfo}}
</el-scrollbar> </el-scrollbar>
<el-alert :closable="false" class="!mb-[15px] !w-full" v-if="errorAnalysis.analysis" type="warning">
<template #default>
<div class="text-left">
错误分析{{ errorAnalysis.analysis }}
</div>
</template>
</el-alert>
<el-button @click="handleReturn" class="!w-[90px]">错误信息</el-button> <el-button @click="handleReturn" class="!w-[90px]">错误信息</el-button>
<el-button @click="againBuild" type="primary" plain class="!w-[90px]" v-if="errorAnalysis.error_addon">重新编译</el-button>
<el-button @click="showDialog=false" type="primary" class="!w-[90px]">完成</el-button> <el-button @click="showDialog=false" type="primary" class="!w-[90px]">完成</el-button>
</template> </template>
</el-result> </el-result>
@ -106,29 +115,358 @@
</div> </div>
</div> </div>
</div> </div>
<div v-show="active == 'again_build'">
<div class="h-[50vh] flex flex-col">
<div class="flex-1 h-0 flex items-center flex-col">
<el-table
ref="tableRef"
:data="installedAddonList"
row-key="key"
size="large"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="应用信息" align="left" width="300">
<template #default="{ row }">
<div class="flex items-center cursor-pointer relative left-[-10px]">
<el-image class="w-[54px] h-[54px] rounded-[5px]" :src="row.icon" fit="contain">
<template #error>
<div class="flex items-center w-full h-full rounded-[5px]">
<img class="max-w-full max-h-full" src="@/app/assets/images/icon-addon-one.png" alt="" />
</div>
</template>
</el-image>
<div class="flex-1 w-0 flex flex-col justify-center pl-[20px] font-500 text-[13px]">
<div class="w-[236px] truncate leading-[18px]">{{ row.title }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="编译结果" align="left">
<template #default="{ row }">
<div class="flex items-center" v-if="errorAnalysis.error_addon && errorAnalysis.error_addon != row.key">
<el-icon class="text-success mr-1"><SuccessFilled /></el-icon> 编译成功
</div>
<div v-else class="flex items-center">
<el-icon class="text-error mr-1"><WarningFilled /></el-icon> 编译失败请排除该插件后重新进行编译
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-[20px]">
<el-button @click="dialogCancel()" class="!w-[90px]">取消</el-button>
<el-button @click="active = 'error'" plain type="primary" class="!w-[90px]">上一步</el-button>
<el-button type="primary" @click="againBuild" :loading="loading" class="!w-[100px]">开始编译</el-button>
</div>
</div>
</div>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, h, watch, computed } from 'vue' import { ref, watch, computed } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { getCloudBuildLog, getCloudBuildTask, cloudBuild, clearCloudBuildTask, preBuildCheck } from '@/app/api/cloud' import { getCloudBuildLog, getCloudBuildTask, cloudBuild, clearCloudBuildTask, preBuildCheck, getCloudBuildQueuePosition, getCloudBuildSseUrl, CLOUD_COMPILE_BASE_URL, startServerDownload, getSseBuildLog } from '@/app/api/cloud'
import { getInstalledAddonList } from '@/app/api/addon'
import { Terminal, TerminalFlash } from 'vue-web-terminal' import { Terminal, TerminalFlash } from 'vue-web-terminal'
import 'vue-web-terminal/lib/theme/dark.css' import 'vue-web-terminal/lib/theme/dark.css'
import { AnyObject } from '@/types/global' import { AnyObject } from '@/types/global'
import { ElNotification, ElMessageBox } from 'element-plus' import {ElNotification, ElMessageBox, ElMessage} from 'element-plus'
const showDialog = ref<boolean>(false) const showDialog = ref<boolean>(false)
const terminalId = ref(Date.now()); const terminalId = ref(Date.now())
const cloudBuildTask = ref<null | AnyObject>(null) const cloudBuildTask = ref<null | AnyObject>(null)
const active = ref('build') const active = ref('build')
const cloudBuildCheck = ref<null | AnyObject>(null) const cloudBuildCheck = ref<null | AnyObject>(null)
const loading = ref(false) const loading = ref(false)
const terminalRef = ref(null) const terminalRef = ref(null)
const selectAddon = ref([])
const installedAddonList = ref([])
const tableRef = ref(null)
getInstalledAddonList().then(({ data }) => {
installedAddonList.value = Object.values(data)
})
const handleSelectionChange = (rows) => {
selectAddon.value = rows.map(row => {
return row.key
})
}
let cloudBuildLog = [] let cloudBuildLog = []
let eventSource: EventSource | null = null
interface SSEMessage {
type: string
task_id?: string
percent?: number
action?: string
msg?: string
code?: string
time?: string
download_url?: string
download_percent?: number
downloaded_bytes?: number
total_bytes?: number
authorize_code?: string
timestamp?: string
}
const connectSSE = (taskId: string) => {
if (eventSource) {
eventSource.close()
}
const url = getCloudBuildSseUrl(taskId)
eventSource = new EventSource(url)
eventSource.onopen = () => {
console.log('SSE connected')
}
eventSource.onmessage = (event) => {
try {
const data: SSEMessage = JSON.parse(event.data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE parse error:', e)
}
}
eventSource.addEventListener('progress', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE progress parse error:', e)
}
})
eventSource.addEventListener('complete', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE complete parse error:', e)
}
})
eventSource.addEventListener('failed', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE failed parse error:', e)
}
})
eventSource.addEventListener('heartbeat', () => {
console.log('SSE heartbeat')
})
eventSource.addEventListener('download_start', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE download_start parse error:', e)
}
})
eventSource.addEventListener('download_progress', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE download_progress parse error:', e)
}
})
eventSource.addEventListener('download_complete', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('SSE download_complete parse error:', e)
}
})
eventSource.onerror = (error) => {
console.error('SSE error:', error)
setTimeout(() => {
if (showDialog.value && cloudBuildTask.value) {
getCloudBuildLogFn()
}
}, 5000)
}
}
const handleSSEMessage = (data: SSEMessage) => {
if (!showDialog.value) return
if (data.type === 'progress' && data.action) {
if (!cloudBuildLog.includes(data.action)) {
if (cloudBuildLog.length === 0) {
const storedTime = localStorage.getItem('cloud_build_start_time')
if (storedTime) {
buildStartTime.value = Number(storedTime)
} else {
const now = Date.now()
buildStartTime.value = now
localStorage.setItem('cloud_build_start_time', String(now))
}
buildDuration.value = Math.floor((Date.now() - buildStartTime.value) / 1000)
buildTimer && clearInterval(buildTimer)
buildTimer = setInterval(() => {
if (buildStartTime.value) {
buildDuration.value = Math.floor((Date.now() - buildStartTime.value) / 1000)
}
}, 1000)
terminalRef.value.execute('clear')
terminalRef.value.execute('开始编译')
}
if (data.action.indexOf('云编译任务正在排队') != -1) {
cloudQueue = data.action
cloudBuildLog.push(data.action)
return
} else {
cloudQueue = null
}
terminalRef.value.pushMessage({ content: `${data.action}` })
cloudBuildLog.push(data.action)
if (data.code === '0' && data.msg) {
errorAnalysis.value = {}
errorInfo.value = data.msg
terminalRef.value.pushMessage({ content: data.msg, class: 'error' })
timeloading.value = false
active.value = 'error'
terminalRef.value.execute('clear')
clearCloudBuildTask()
buildTimer && clearInterval(buildTimer)
buildTimer = null
localStorage.removeItem('cloud_build_start_time')
localStorage.removeItem('cloud_build_task')
closeSSE()
}
}
} else if (data.type === 'complete') {
terminalRef.value.pushMessage({ content: '编译完成' })
} else if (data.type === 'failed') {
errorInfo.value = data.msg || '编译失败'
active.value = 'error'
terminalRef.value.execute('clear')
clearCloudBuildTask()
buildTimer && clearInterval(buildTimer)
buildTimer = null
localStorage.removeItem('cloud_build_start_time')
localStorage.removeItem('cloud_build_task')
closeSSE()
} else if (data.type === 'download_start') {
if (data.action && !cloudBuildLog.includes(data.action)) {
terminalRef.value.pushMessage({ content: data.action })
cloudBuildLog.push(data.action)
}
} else if (data.type === 'download_progress') {
const percent = data.download_percent || 0
const downloaded = data.downloaded_bytes || 0
const total = data.total_bytes || 0
const downloadedMB = (downloaded / 1024 / 1024).toFixed(2)
const totalMB = (total / 1024 / 1024).toFixed(2)
terminalRef.value.pushMessage({ content: `下载进度: ${percent}% (${downloadedMB}MB / ${totalMB}MB)` })
} else if (data.type === 'download_complete') {
if (data.action && !cloudBuildLog.includes(data.action)) {
terminalRef.value.pushMessage({ content: data.action })
cloudBuildLog.push(data.action)
}
if (data.download_url && data.task_id) {
startServerDownloadFn(data.task_id, data.download_url, data.authorize_code, data.timestamp)
}
}
}
let downloadPollingTimer: number | null = null
const startServerDownloadFn = async (taskId: string, downloadUrl: string, authorizeCode: string, timestamp: string) => {
try {
terminalRef.value.pushMessage({ content: '正在启动后台下载...' })
const parseUrl = new URL(downloadUrl, CLOUD_COMPILE_BASE_URL)
const authorize_code = parseUrl.searchParams.get('authorize_code') || authorizeCode || ''
const ts = parseUrl.searchParams.get('timestamp') || timestamp || ''
await startServerDownload(taskId, downloadUrl, authorize_code, ts)
downloadPollingTimer = setTimeout(async () => {
if (!downloadPollingTimer) return
try {
const res = await getSseBuildLog(taskId)
if (res.code === 1) {
const { status, percent, msg } = res.data
if (status === 'downloading') {
terminalRef.value.pushMessage({ content: `下载进度: ${percent}% - ${msg}` })
} else if (status === 'unzipping') {
terminalRef.value.pushMessage({ content: msg })
} else if (status === 'completed') {
terminalRef.value.pushMessage({ content: '部署完成!' })
downloadPollingTimer && clearInterval(downloadPollingTimer)
downloadPollingTimer = null
active.value = 'complete'
timeloading.value = false
terminalRef.value.execute('clear')
clearCloudBuildTask()
buildTimer && clearInterval(buildTimer)
buildTimer = null
localStorage.removeItem('cloud_build_start_time')
localStorage.removeItem('cloud_build_task')
closeSSE()
ElMessage.success('编译部署完成')
} else if (status === 'error') {
terminalRef.value.pushMessage({ content: `错误: ${msg}`, class: 'error' })
downloadPollingTimer && clearInterval(downloadPollingTimer)
downloadPollingTimer = null
errorInfo.value = msg
active.value = 'error'
timeloading.value = false
clearCloudBuildTask()
closeSSE()
}
} else {
terminalRef.value.pushMessage({ content: '获取下载进度失败', class: 'error' })
downloadPollingTimer && clearInterval(downloadPollingTimer)
downloadPollingTimer = null
}
} catch (e) {
console.error('Polling error:', e)
}
}, 2000)
} catch (error) {
console.error('启动后台下载失败:', error)
terminalRef.value.pushMessage({ content: '启动后台下载失败', class: 'error' })
errorInfo.value = '启动后台下载失败'
active.value = 'error'
}
}
const closeSSE = () => {
if (eventSource) {
eventSource.close()
eventSource = null
}
if (downloadPollingTimer) {
clearInterval(downloadPollingTimer)
downloadPollingTimer = null
}
}
//
const buildStartTime = ref<number | null>(null) const buildStartTime = ref<number | null>(null)
const buildDuration = ref<number>(0) const buildDuration = ref<number>(0)
let buildTimer: number | null = null let buildTimer: number | null = null
@ -157,6 +495,7 @@ const getCloudBuildTaskFn = () => {
getCloudBuildTaskFn() getCloudBuildTaskFn()
const errorInfo = ref('') const errorInfo = ref('')
const timeloading = ref(false) const timeloading = ref(false)
const errorAnalysis = ref({})
const getCloudBuildLogFn = () => { const getCloudBuildLogFn = () => {
timeloading.value = true timeloading.value = true
getCloudBuildLog().then(res => { getCloudBuildLog().then(res => {
@ -202,10 +541,18 @@ const getCloudBuildLogFn = () => {
data[0].forEach(item => { data[0].forEach(item => {
if (!cloudBuildLog.includes(item.action)) { if (!cloudBuildLog.includes(item.action)) {
if (item.action.indexOf('云编译任务正在排队') != -1) {
cloudQueue = item.action
cloudBuildLog.push(item.action)
return
} else {
cloudQueue = null
}
terminalRef.value.pushMessage({ content: `${item.action}` }) terminalRef.value.pushMessage({ content: `${item.action}` })
cloudBuildLog.push(item.action) cloudBuildLog.push(item.action)
if (item.code == 0) { if (item.code === '0') {
errorAnalysis.value = res.data.error_analysis || {}
error = item.msg error = item.msg
terminalRef.value.pushMessage({ content: item.msg, class: 'error' }) terminalRef.value.pushMessage({ content: item.msg, class: 'error' })
timeloading.value = false timeloading.value = false
@ -234,7 +581,7 @@ const getCloudBuildLogFn = () => {
setTimeout(() => { setTimeout(() => {
getCloudBuildLogFn() getCloudBuildLogFn()
}, 2000) }, 5000)
}).catch() }).catch()
} }
@ -271,10 +618,17 @@ const open = async () => {
loading.value = true loading.value = true
active.value = 'build' active.value = 'build'
closeType.value = 'normal' closeType.value = 'normal'
cloudBuildLog = []
if (cloudBuildTask.value) { if (cloudBuildTask.value) {
showDialog.value = true showDialog.value = true
loading.value = false loading.value = false
getCloudBuildLogFn() const taskId = (cloudBuildTask.value as any).task_id
if (taskId) {
connectSSE(taskId)
} else {
getCloudBuildLogFn()
}
return return
} }
@ -284,7 +638,12 @@ const open = async () => {
loading.value = false loading.value = false
cloudBuildTask.value = data cloudBuildTask.value = data
showDialog.value = true showDialog.value = true
getCloudBuildLogFn() const taskId = data.task_id
if (taskId) {
connectSSE(taskId)
} else {
getCloudBuildLogFn()
}
}).catch(() => { }).catch(() => {
showDialog.value = false showDialog.value = false
loading.value = false loading.value = false
@ -294,22 +653,80 @@ const open = async () => {
cloudBuildCheck.value = data cloudBuildCheck.value = data
showDialog.value = true showDialog.value = true
} }
}).catch((e) => {
loading.value = false
showDialog.value = false
if (e.code && e.code == 601) {
ElMessageBox.confirm(
'云编译服务未启动,必须在启动后进行云编译!',
'提示',
{
distinguishCancelAndClose: true,
confirmButtonText: '重新检测',
cancelButtonText: '查看操作手册',
type: 'warning'
}
).then(() => {
open()
}).catch((action) => {
action == 'cancel' && window.open('https://doc.press.niucloud.com/php/saas-framework/use/other/third-party-cloud-compilation.html', '_blank')
})
} else {
ElMessage({ message: e.msg, type: 'error' })
}
})
}
const againBuild = () => {
if (active.value != 'again_build') {
active.value = 'again_build'
selectAddon.value = installedAddonList.value.map((item) => {
tableRef.value.toggleRowSelection(item, true)
return item.key
})
return
}
loading.value = true
cloudBuildLog = []
cloudBuild().then(({ data }) => {
active.value = 'build'
loading.value = false
cloudBuildTask.value = data
showDialog.value = true
localStorage.removeItem('cloud_build_start_time')
const taskId = data.task_id
if (taskId) {
connectSSE(taskId)
} else {
getCloudBuildLogFn()
}
}).catch(() => { }).catch(() => {
showDialog.value = false showDialog.value = false
loading.value = false
}) })
} }
const selectable = (row: any) => {
return selectAddon.value.includes(row.key)
}
/** /**
* 升级进度动画 * 升级进度动画
*/ */
let flashInterval: null | number = null let flashInterval: null | number = null
const terminalFlash = new TerminalFlash() let terminalFlash = null
let cloudQueue = null
const onExecCmd = (key, command, success, failed, name) => { const onExecCmd = (key, command, success, failed, name) => {
if (command == '开始编译') { if (command == '开始编译') {
terminalFlash = new TerminalFlash()
success(terminalFlash) success(terminalFlash)
const frames = makeIterator(['/', '——', '\\', '|']) const frames = makeIterator(['/', '——', '\\', '|'])
flashInterval = setInterval(() => { flashInterval = setInterval(() => {
terminalFlash.flush('> ' + frames.next().value) if (cloudQueue) {
terminalFlash.flush(cloudQueue + '<br>> ' + frames.next().value)
} else {
terminalFlash.flush('> ' + frames.next().value)
}
}, 150) }, 150)
} }
} }
@ -327,6 +744,7 @@ const makeIterator = (array: string[]) => {
} }
const dialogClose = (done: () => {}) => { const dialogClose = (done: () => {}) => {
closeSSE()
if (active.value == 'build' && cloudBuildTask.value && closeType.value == 'normal') { if (active.value == 'build' && cloudBuildTask.value && closeType.value == 'normal') {
ElMessageBox.confirm( ElMessageBox.confirm(
t('cloudbuild.showDialogCloseTips'), t('cloudbuild.showDialogCloseTips'),
@ -352,6 +770,7 @@ const dialogClose = (done: () => {}) => {
} }
const dialogCancel = () => { const dialogCancel = () => {
closeSSE()
if (active.value == 'build' && cloudBuildTask.value && closeType.value == 'normal') { if (active.value == 'build' && cloudBuildTask.value && closeType.value == 'normal') {
ElMessageBox.confirm( ElMessageBox.confirm(
t('cloudbuild.showDialogCloseTips'), t('cloudbuild.showDialogCloseTips'),
@ -382,10 +801,12 @@ const cloudBuildCheckDirFn = () => {
watch(() => showDialog.value, () => { watch(() => showDialog.value, () => {
if (!showDialog.value) { if (!showDialog.value) {
closeSSE()
cloudBuildTask.value = null cloudBuildTask.value = null
active.value = 'build' active.value = 'build'
cloudBuildLog = [] cloudBuildLog = []
flashInterval && clearInterval(flashInterval) flashInterval && clearInterval(flashInterval)
terminalFlash && terminalFlash.finish()
buildTimer && clearInterval(buildTimer) buildTimer && clearInterval(buildTimer)
buildStartTime.value = null buildStartTime.value = null
buildDuration.value = 0 buildDuration.value = 0

View File

@ -356,8 +356,14 @@ const getUpgradeTaskFn = () => {
data.log.forEach((item) => { data.log.forEach((item) => {
if (!upgradeLog.includes(item)) { if (!upgradeLog.includes(item)) {
terminalRef.value.pushMessage({ content: `${item}` }) if (item.indexOf('云编译任务正在排队') != -1) {
upgradeLog.push(item) cloudQueue = item
upgradeLog.push(item)
} else {
cloudQueue = null
terminalRef.value.pushMessage({ content: `${item}` })
upgradeLog.push(item)
}
} }
}) })
// //
@ -438,7 +444,7 @@ const executeUpgradeFn = () => {
executeUpgrade().then(() => { executeUpgrade().then(() => {
getUpgradeTaskFn() getUpgradeTaskFn()
}).catch((err) => { }).catch((err) => {
if (err.message.indexOf('队列') != -1) { if (err.msg.indexOf('队列') != -1) {
retrySecond.value = 30 retrySecond.value = 30
retrySecondInterval = setInterval(() => { retrySecondInterval = setInterval(() => {
retrySecond.value-- retrySecond.value--
@ -447,6 +453,26 @@ const executeUpgradeFn = () => {
} }
}, 1000) }, 1000)
cloudBuildErrorTipsShowDialog.value = true cloudBuildErrorTipsShowDialog.value = true
} else if (err.code && err.code == 601) {
ElMessageBox.confirm(
'云编译服务未启动,必须在启动后进行云编译!',
'提示',
{
distinguishCancelAndClose: true,
confirmButtonText: '重新检测',
cancelButtonText: '查看操作手册',
type: 'warning'
}
).then(() => {
open()
}).catch((action) => {
action == 'cancel' && window.open('https://doc.press.niucloud.com/php/saas-framework/use/other/third-party-cloud-compilation.html', '_blank')
})
} else if (err.response && err.response.status && err.response.status == 502) {
ElMessage({ dangerouslyUseHTMLString: true, duration: 5000, message: '程序执行超时请先调整超时限制, 具体操作方法<a style="text-decoration: underline;" href="https://doc.press.niucloud.com/php/v6-shop/use/chang-jian-wen-ti-chu-li/er-shi-ba-3001-an-88c5-sheng-ji-guo-cheng-zhong-ti-shi-201c-502-bad-gateway-201d-wen-ti-jie-jue.html#%E5%AE%89%E8%A3%85-%E5%8D%87%E7%BA%A7%E5%AE%8C%E6%88%90%E5%90%8E-%E4%BA%91%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E6%8F%90%E7%A4%BA-502-bad-gateway-%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3" target="blank">点击查看相关手册</a>', type: 'error' })
setTimeout(() => {
executeUpgradeFn()
}, 5000)
} else { } else {
ElMessage({ message: err.message, type: 'error' }) ElMessage({ message: err.message, type: 'error' })
} }
@ -526,8 +552,26 @@ const upgradeAddonFn = () => {
upgradeAddon(appKey, upgradeOption.value).then(() => { upgradeAddon(appKey, upgradeOption.value).then(() => {
getUpgradeTaskFn() getUpgradeTaskFn()
}).catch(() => { }).catch((res) => {
loading.value = false loading.value = false
if (res.code && res.code == 601) {
ElMessageBox.confirm(
'云编译服务未启动,必须在启动后进行云编译!',
'提示',
{
distinguishCancelAndClose: true,
confirmButtonText: '重新检测',
cancelButtonText: '查看操作手册',
type: 'warning'
}
).then(() => {
upgradeAddonFn()
}).catch((action) => {
action == 'cancel' && window.open('https://doc.press.niucloud.com/php/saas-framework/use/other/third-party-cloud-compilation.html', '_blank')
})
} else {
ElMessage({ message: res.msg, type: 'error' })
}
}) })
} }
const dialogUpgradePrompt = ref(false) const dialogUpgradePrompt = ref(false)
@ -589,12 +633,18 @@ const open = (addonKey: string = '', callback = null, otherData: any = {}) => {
*/ */
let flashInterval: any = null let flashInterval: any = null
const terminalFlash = new TerminalFlash() const terminalFlash = new TerminalFlash()
let cloudQueue = null
const onExecCmd = (key, command, success, failed, name) => { const onExecCmd = (key, command, success, failed, name) => {
if (command == '开始升级') { if (command == '开始升级') {
success(terminalFlash) success(terminalFlash)
const frames = makeIterator(['/', '——', '\\', '|']) const frames = makeIterator(['/', '——', '\\', '|'])
flashInterval = setInterval(() => { flashInterval = setInterval(() => {
terminalFlash.flush('> ' + frames.next().value) if (cloudQueue) {
terminalFlash.flush(cloudQueue + '<br>> ' + frames.next().value)
} else {
terminalFlash.flush('> ' + frames.next().value)
}
}, 150) }, 150)
} }
} }
@ -625,6 +675,14 @@ const dialogClose = (done: () => {}) => {
} }
} }
window.addEventListener('beforeunload', function (event) {
if (showDialog.value && active.value == 'upgrade' && upgradeTask.value && ['upgradeComplete', 'restoreComplete'].includes(upgradeTask.value.step) === false && !isBack.value) {
event.preventDefault()
event.returnValue = ''
return t('upgrade.showDialogCloseTips')
}
})
watch( watch(
() => showDialog.value, () => showDialog.value,
() => { () => {

View File

@ -0,0 +1,441 @@
<template>
<el-dialog v-model="showDialog" title="小程序上传" width="850px" :close-on-click-modal="false" :close-on-press-escape="false" :before-close="dialogClose">
<div v-show="active == 'upload'" class="h-[50vh]" v-loading="loading">
<div class="h-[45vh]" v-show="cloudBuildTask">
<terminal ref="terminalRef" :name="`weappupload-${terminalId}`" context="" :init-log="null" :show-header="false" :show-log-time="true" @exec-cmd="onExecCmd"/>
</div>
<div class="flex justify-end mt-[20px]" v-show="cloudBuildTask">
<el-button @click="dialogCancel()">取消</el-button>
<el-button type="primary" :loading="timeloading" class="!w-[140px]" v-if="!errorInfo">已用时 {{ formattedDuration }}</el-button>
<el-button type="primary" @click="active = 'error'" v-if="errorInfo">下一步</el-button>
</div>
</div>
<div v-show="active == 'complete'">
<div class="h-[50vh] flex flex-col">
<div class="flex-1 h-0 flex justify-center items-center flex-col">
<el-result icon="success" title="上传成功">
<template #sub-title>
<p class="text-[16px]">小程序上传成功耗时 {{ formattedDuration }}</p>
</template>
<template #extra>
<el-button type="primary" @click="handleComplete">完成</el-button>
</template>
</el-result>
</div>
</div>
</div>
<div v-show="active == 'error'">
<div class="h-[50vh] flex flex-col">
<div class="flex-1 h-0 flex justify-center items-center flex-col">
<el-result icon="error" title="上传失败">
<template #extra>
<p class="text-[14px] text-red-500 mb-[10px]" v-if="errorInfo">错误信息: {{ errorInfo }}</p>
<el-button type="primary" @click="handleErrorNextStep">下一步</el-button>
</template>
</el-result>
</div>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, nextTick, onUnmounted, computed } from 'vue'
import { t } from '@/lang'
import { getWeappUploadLog, fetchWeappUploadLog } from '@/app/api/weapp'
import { CLOUD_COMPILE_BASE_URL } from '@/app/api/cloud'
import { Terminal } from 'vue-web-terminal'
import 'vue-web-terminal/lib/theme/dark.css'
import { ElMessageBox, ElMessage } from 'element-plus'
const showDialog = ref(false)
const terminalId = ref(Date.now())
const cloudBuildTask = ref<any>(null)
const active = ref('upload')
const loading = ref(false)
const terminalRef = ref(null)
const errorInfo = ref('')
const timeloading = ref(false)
const errorAnalysis = ref({})
let uploadLog: any[] = []
let eventSource: EventSource | null = null
const uploadStartTime = ref<number | null>(null)
const uploadDuration = ref(0)
let durationTimer: number | null = null
interface TerminalMessage {
content: string
class?: string
}
let messageQueue: TerminalMessage[] = []
let messageQueueTimer: number | null = null
const MESSAGE_FLUSH_INTERVAL = 300
const flushMessageQueue = () => {
if (!terminalRef.value || messageQueue.length === 0) return
while (messageQueue.length > 0) {
const msg = messageQueue.shift()
if (msg) {
terminalRef.value.pushMessage(msg)
}
}
}
const queueMessage = (content: string, className?: string) => {
messageQueue.push({ content, class: className })
if (messageQueueTimer === null) {
messageQueueTimer = window.setTimeout(() => {
flushMessageQueue()
messageQueueTimer = null
}, MESSAGE_FLUSH_INTERVAL)
}
}
const clearMessageQueue = () => {
messageQueue = []
if (messageQueueTimer !== null) {
clearTimeout(messageQueueTimer)
messageQueueTimer = null
}
}
const formattedDuration = computed(() => {
const seconds = uploadDuration.value
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return mins > 0 ? `${mins}${secs}` : `${secs}`
})
const onExecCmd = (cmd: string) => {
}
const getWeappSseUrl = (taskId: string): string => {
return `${CLOUD_COMPILE_BASE_URL}/cloud/weapp_sse?task_id=${taskId}`
}
interface SSEMessage {
type: string
task_id?: string
percent?: number
action?: string
msg?: string
code?: string
time?: string
}
const connectSSE = (taskId: string) => {
if (eventSource) {
eventSource.close()
}
const url = getWeappSseUrl(taskId)
eventSource = new EventSource(url)
eventSource.onopen = () => {
console.log('Weapp SSE connected')
}
eventSource.onmessage = (event) => {
try {
const data: SSEMessage = JSON.parse(event.data)
handleSSEMessage(data)
} catch (e) {
console.error('Weapp SSE parse error:', e)
}
}
eventSource.addEventListener('progress', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('Weapp SSE progress parse error:', e)
}
})
eventSource.addEventListener('complete', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('Weapp SSE complete parse error:', e)
}
})
eventSource.addEventListener('failed', (event) => {
try {
const data: SSEMessage = JSON.parse((event as MessageEvent).data)
handleSSEMessage(data)
} catch (e) {
console.error('Weapp SSE failed parse error:', e)
}
})
eventSource.onerror = (error) => {
console.error('Weapp SSE error:', error)
closeSSE()
}
}
const closeSSE = () => {
if (eventSource) {
eventSource.close()
eventSource = null
}
clearMessageQueue()
}
const earlyLogCheck = (taskKey: string): Promise<boolean> => {
return new Promise((resolve) => {
fetchWeappUploadLog(taskKey).then(res => {
const data = (res.data && res.data.data) ? res.data.data : []
if (data[0] && data[0].length) {
const last = data[0][data[0].length - 1]
if (last.code == 1 && last.percent == 100) {
resolve(true)
return
}
if (last.code == 0) {
resolve(true)
return
}
}
resolve(false)
}).catch(() => {
resolve(false)
})
})
}
const handleSSEMessage = (data: SSEMessage) => {
if (!showDialog.value) return
if (data.type === 'progress' && data.action) {
if (!uploadLog.includes(data.action)) {
if (uploadLog.length === 0) {
const now = Date.now()
uploadStartTime.value = now
uploadDuration.value = 0
durationTimer && clearInterval(durationTimer)
durationTimer = setInterval(() => {
if (uploadStartTime.value) {
uploadDuration.value = Math.floor((Date.now() - uploadStartTime.value) / 1000)
}
}, 1000)
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
terminalRef.value.execute('开始上传')
}
})
}
queueMessage(`${data.action}`)
uploadLog.push(data.action)
if (data.code === '0') {
errorInfo.value = data.msg || '上传失败'
timeloading.value = false
active.value = 'error'
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
}
})
closeSSE()
uploadDurationTimerClear()
if (props.onError) {
props.onError()
}
return
}
if (data.code === '1' && data.percent === 100) {
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
}
})
queueMessage('上传完成')
timeloading.value = false
active.value = 'complete'
closeSSE()
uploadDurationTimerClear()
ElMessage.success('上传成功')
if (props.onSuccess) {
props.onSuccess()
}
return
}
}
} else if (data.type === 'complete') {
getWeappUploadLog(data.task_id)
queueMessage('上传完成')
timeloading.value = false
active.value = 'complete'
closeSSE()
uploadDurationTimerClear()
ElMessage.success('上传成功')
if (props.onSuccess) {
props.onSuccess()
}
} else if (data.type === 'failed') {
errorInfo.value = data.msg || '上传失败'
timeloading.value = false
active.value = 'error'
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
}
})
closeSSE()
uploadDurationTimerClear()
if (props.onError) {
props.onError()
}
}
}
const uploadDurationTimerClear = () => {
if (durationTimer) {
clearInterval(durationTimer)
durationTimer = null
}
uploadStartTime.value = null
}
const dialogClose = (done: () => void) => {
closeSSE()
uploadDurationTimerClear()
if (active.value == 'upload' && cloudBuildTask.value) {
ElMessageBox.confirm(
'确定要关闭上传窗口吗?关闭后将停止当前上传任务',
'提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
done()
}).catch(() => { })
} else {
done()
}
}
const dialogCancel = () => {
showDialog.value = false
}
const handleComplete = () => {
showDialog.value = false
if (props.onSuccess) {
props.onSuccess()
}
}
const handleErrorNextStep = () => {
showDialog.value = false
if (props.onError) {
props.onError()
}
}
const props = defineProps<{
onSuccess?: () => void
onError?: () => void
}>()
const open = async (taskKey: string, task?: any) => {
loading.value = true
active.value = 'upload'
uploadLog = []
clearMessageQueue()
errorInfo.value = ''
errorAnalysis.value = {}
timeloading.value = true
terminalId.value = Date.now()
const taskData = task || cloudBuildTask.value
if (taskData) {
cloudBuildTask.value = taskData
if (taskData.status == 0) {
loading.value = false
const isCompleted = await earlyLogCheck(taskData.task_key)
if (isCompleted) {
closeSSE()
getWeappUploadLog(taskData.task_key)
showDialog.value = true
active.value = 'complete'
loading.value = false
uploadDuration.value = taskData.update_time - taskData.create_time
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
terminalRef.value.execute('上传完成')
}
})
return
}
showDialog.value = true
connectSSE(taskData.task_key)
} else if (taskData.status == 1) {
active.value = 'complete'
loading.value = false
uploadDuration.value = taskData.update_time - taskData.create_time
showDialog.value = true
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
terminalRef.value.execute('上传完成')
}
})
if (props.onSuccess) {
props.onSuccess()
}
} else if (taskData.status == -1 || taskData.status == -2) {
active.value = 'error'
loading.value = false
errorInfo.value = taskData.fail_reason || '上传失败'
showDialog.value = true
nextTick(() => {
if (terminalRef.value) {
terminalRef.value.execute('clear')
terminalRef.value.execute('上传失败')
}
})
if (props.onError) {
props.onError()
}
} else {
loading.value = false
showDialog.value = true
connectSSE(taskData.task_key)
}
} else {
loading.value = false
}
}
const setTask = (task: any) => {
cloudBuildTask.value = task
}
onUnmounted(() => {
closeSSE()
uploadDurationTimerClear()
})
defineExpose({
open,
setTask,
cloudBuildTask,
loading,
showDialog
})
</script>

View File

@ -46,5 +46,28 @@
"uploadWeapp": "上传小程序", "uploadWeapp": "上传小程序",
"undoAudit" : "撤回审核", "undoAudit" : "撤回审核",
"undoAuditTips" : "撤回代码审核,单个账号每天审核撤回次数最多不超过 5 次每天的额度从0点开始生效一个月不超过 10 次。是否要继续撤回?", "undoAuditTips" : "撤回代码审核,单个账号每天审核撤回次数最多不超过 5 次每天的额度从0点开始生效一个月不超过 10 次。是否要继续撤回?",
"helpInfo": "查看帮助" "helpInfo": "查看帮助",
"weappUpload": {
"title": "小程序上传",
"noTask": "暂无上传任务",
"uploadFailed": "上传失败",
"uploadSuccess": "上传成功",
"uploadSuccessDesc": "小程序上传成功,耗时",
"usedTime": "已用时",
"startUpload": "开始上传",
"uploadComplete": "上传完成",
"dialogCloseTips": "确定要关闭上传窗口吗?关闭后将停止当前上传任务",
"errorInfo": "错误信息",
"errorAnalysis": "错误分析",
"complete": "完成",
"return": "返回",
"nextStep": "下一步",
"waitingUpload": "等待上传任务...",
"minute": "分",
"second": "秒",
"dot": ".",
"defaultDesc": "默认为列表版本号递增自定义则为手动输入版本号进行上传首位必须大于1"
},
"minute": "分",
"second": "秒"
} }

View File

@ -110,11 +110,11 @@
<el-form-item prop="code1"> <el-form-item prop="code1">
<el-input v-model.number="form.code1" class="!w-[70px]" :placeholder="t('codePlaceholder')" /> <el-input v-model.number="form.code1" class="!w-[70px]" :placeholder="t('codePlaceholder')" />
</el-form-item> </el-form-item>
<span class="mx-[10px]">.</span> <span class="mx-[10px]">{{ t('weappUpload.dot') }}</span>
<el-form-item prop="code2"> <el-form-item prop="code2">
<el-input v-model.number="form.code2" class="!w-[70px]" :placeholder="t('codePlaceholder')" /> <el-input v-model.number="form.code2" class="!w-[70px]" :placeholder="t('codePlaceholder')" />
</el-form-item> </el-form-item>
<span class="mx-[10px]">.</span> <span class="mx-[10px]">{{ t('weappUpload.dot') }}</span>
<el-form-item prop="code3"> <el-form-item prop="code3">
<el-input v-model.number="form.code3" class="!w-[70px]" :placeholder="t('codePlaceholder')" /> <el-input v-model.number="form.code3" class="!w-[70px]" :placeholder="t('codePlaceholder')" />
</el-form-item> </el-form-item>
@ -155,6 +155,8 @@
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
<component :is="WeappUpload" ref="weappUploadRef" @success="getWeappVersionListFn" @error="getWeappVersionListFn" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -168,12 +170,17 @@ import { ElMessageBox } from 'element-plus'
import { AnyObject } from '@/types/global' import { AnyObject } from '@/types/global'
import Storage from '@/utils/storage' import Storage from '@/utils/storage'
import { siteWeappCommit, undoAudit } from "@/app/api/wxoplatform"; import { siteWeappCommit, undoAudit } from "@/app/api/wxoplatform";
import WeappUpload from '@/app/components/weappupload/index.vue'
// 使
const WeappUploadComponent = WeappUpload
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const pageName = route.meta.title const pageName = route.meta.title
const dialogVisible = ref(false) const dialogVisible = ref(false)
const loading = ref(true) const loading = ref(true)
const weappUploadRef = ref<any>(null)
const weappTableData:{ const weappTableData:{
page: number, page: number,
limit: number, limit: number,
@ -286,19 +293,24 @@ const formRules = reactive({
/** /**
* 获取版本列表 * 获取版本列表
*/ */
const getWeappVersionListFn = (page: number = 1) => { const getWeappVersionListFn = (page?: number) => {
weappTableData.loading = true weappTableData.loading = true
weappTableData.page = page if (page) weappTableData.page = page
getWeappVersionList({ return getWeappVersionList({
page: weappTableData.page, page: weappTableData.page,
limit: weappTableData.limit limit: weappTableData.limit
}).then(res => { }).then(res => {
weappTableData.loading = false weappTableData.loading = false
weappTableData.data = res.data.data weappTableData.data = res.data.data
weappTableData.total = res.data.total weappTableData.total = res.data.total
if (page == 1 && weappTableData.data.length && weappTableData.data[0].status == 0) getWeappUploadLogFn(weappTableData.data[0].task_key)
weappTableData.version_info = res.data.version_info weappTableData.version_info = res.data.version_info
const uploadingTask = res.data.data.find((d: any) => d.status == 0)
if (uploadingTask && weappUploadRef.value) {
weappUploadRef.value.setTask(uploadingTask)
weappUploadRef.value.open(uploadingTask.task_key, uploadingTask)
}
}).catch(() => { }).catch(() => {
weappTableData.loading = false weappTableData.loading = false
}) })
@ -367,15 +379,35 @@ const insert = () => {
return return
} }
if (uploading.value) return if (uploading.value) {
const ref = weappUploadRef.value
if (ref && ref.cloudBuildTask && ref.cloudBuildTask.task_key) {
ref.open(ref.cloudBuildTask.task_key, ref.cloudBuildTask)
} else if (ref) {
ref.showDialog = true
}
return
}
uploading.value = true uploading.value = true
previewContent.value = '' previewContent.value = ''
setWeappVersion(form.value).then(res => { setWeappVersion(form.value).then(res => {
getWeappVersionListFn() const versionId = res.data
getWeappPreviewImage()
uploading.value = false getWeappVersionListFn().then(() => {
const item = weappTableData.data.find((d: any) => d.id === versionId)
if (item && item.task_key) {
const ref = weappUploadRef.value
if (ref) {
ref.open(item.task_key, item)
}
}
getWeappPreviewImage()
uploading.value = false
}).catch(() => {
uploading.value = false
})
}).catch(() => { }).catch(() => {
uploading.value = false uploading.value = false
}) })
@ -388,6 +420,7 @@ const localInsert = () => {
} }
const previewContent = ref('') const previewContent = ref('')
const getWeappPreviewImage = () => { const getWeappPreviewImage = () => {
if (!authCode.value) return if (!authCode.value) return
getWeappPreview().then(res => { getWeappPreview().then(res => {
@ -395,21 +428,55 @@ const getWeappPreviewImage = () => {
}).catch() }).catch()
} }
const currentUploadKey = ref<string | null>(null)
const uploadPollingCount = ref(0)
const maxPollingCount = 150
const getWeappUploadLogFn = (key: string) => { const getWeappUploadLogFn = (key: string) => {
if (!key) return
if (currentUploadKey.value !== key) {
currentUploadKey.value = key
uploadPollingCount.value = 0
}
uploadPollingCount.value++
if (uploadPollingCount.value > maxPollingCount) {
currentUploadKey.value = null
uploadPollingCount.value = 0
uploading.value = false
return
}
getWeappUploadLog(key).then(res => { getWeappUploadLog(key).then(res => {
const data = res.data.data ?? [] if (currentUploadKey.value !== key) return
const data = (res.data && res.data.data) ? res.data.data : []
if (data[0] && data[0].length) { if (data[0] && data[0].length) {
const last = data[0][data[0].length - 1] const last = data[0][data[0].length - 1]
if (last.code == 0) { if (last.code == 0) {
currentUploadKey.value = null
uploadPollingCount.value = 0
getWeappVersionListFn() getWeappVersionListFn()
return return
} }
if (last.code == 1 && last.percent == 100) { if (last.code == 1 && last.percent == 100) {
currentUploadKey.value = null
uploadPollingCount.value = 0
getWeappVersionListFn() getWeappVersionListFn()
getWeappPreviewImage() getWeappPreviewImage()
!Storage.get('weappUploadTipsLock') && (uploadSuccessShowDialog.value = true) !Storage.get('weappUploadTipsLock') && (uploadSuccessShowDialog.value = true)
return return
} }
}
if (currentUploadKey.value === key) {
setTimeout(() => {
getWeappUploadLogFn(key)
}, 2000)
}
}).catch(() => {
if (currentUploadKey.value === key) {
setTimeout(() => { setTimeout(() => {
getWeappUploadLogFn(key) getWeappUploadLogFn(key)
}, 2000) }, 2000)

View File

@ -36,7 +36,7 @@
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<el-form :inline="true" :model="searchParam" ref="searchFormRef" class="search-form" v-if="!loading && !isShowDetail && (activeName == 'installed' || activeName == 'all' || activeName == 'uninstalled')"> <el-form :inline="true" :model="searchParam" ref="searchFormRef" class="search-form" v-if="!loading && !isShowDetail && (activeName == 'installed' || activeName == 'all' || activeName == 'uninstalled')">
<el-form-item prop="type"> <el-form-item prop="type">
<el-select v-model="searchParam.type" clearable :placeholder="t('应用类型')" class="input-width"> <el-select v-model="searchParam.type" clearable :placeholder="t('应用类型')" class="input-width">
@ -83,7 +83,7 @@
</p> </p>
</div> </div>
</div> </div>
<el-button class="ml-[auto]" @click="updateInformationFn({ key: 'niucloud-admin' })"> <el-button class="ml-[auto]" @click="updateInformationFn({ key: 'niucloud-admin' })">
<el-icon class="mr-[5px]"> <el-icon class="mr-[5px]">
<DocumentCopy /> <DocumentCopy />
@ -139,7 +139,7 @@
</div> </div>
<div class="flex-1 w-0"> <div class="flex-1 w-0">
<div class="flex items-center"> <div class="flex items-center">
<p class="text-[16px] text-[#374151] truncate leading-[20px]" :title="row.title">{{ row.title }}</p> <p class="text-[16px] text-[#374151] truncate leading-[20px]" :title="row.title">{{ row.title }}</p>
<span :class="{'app-ident': row.type == 'app', 'addon-ident': row.type == 'addon'}">{{row.type == 'app' ? '应用' : '插件'}}</span> <span :class="{'app-ident': row.type == 'app', 'addon-ident': row.type == 'addon'}">{{row.type == 'app' ? '应用' : '插件'}}</span>
</div> </div>
<p class="text-xs text-[#4F516D] truncate mt-[2px] font-bold" :title="row.key">{{ row.key }}</p> <p class="text-xs text-[#4F516D] truncate mt-[2px] font-bold" :title="row.key">{{ row.key }}</p>
@ -1245,12 +1245,18 @@ const installCheckResult = ref({})
let flashInterval = null let flashInterval = null
const terminalFlash = new TerminalFlash() const terminalFlash = new TerminalFlash()
let cloudQueue = null
const onExecCmd = (key, command, success, failed, name) => { const onExecCmd = (key, command, success, failed, name) => {
if (command == '开始安装插件') { if (command == '开始安装插件') {
success(terminalFlash) success(terminalFlash)
const frames = makeIterator(['/', '——', '\\', '|']) const frames = makeIterator(['/', '——', '\\', '|'])
flashInterval = setInterval(() => { flashInterval = setInterval(() => {
terminalFlash.flush('> ' + frames.next().value) if (cloudQueue) {
terminalFlash.flush(cloudQueue + '<br>> ' + frames.next().value)
} else {
terminalFlash.flush('> ' + frames.next().value)
}
}, 150) }, 150)
} }
} }
@ -1342,7 +1348,7 @@ const getInstallTask = (first: boolean = true) => {
} }
setTimeout(() => { setTimeout(() => {
getInstallTask(false) getInstallTask(false)
}, 2000) }, 5000)
} else { } else {
if (!first) { if (!first) {
installStep.value = 2 installStep.value = 2
@ -1442,6 +1448,24 @@ const handleCloudInstall = () => {
}) })
.catch((res) => { .catch((res) => {
cloudInstalling.value = false cloudInstalling.value = false
if (res.code && res.code == 601) {
ElMessageBox.confirm(
'云编译服务未启动,必须在启动后进行云编译!',
'提示',
{
distinguishCancelAndClose: true,
confirmButtonText: '重新检测',
cancelButtonText: '查看操作手册',
type: 'warning'
}
).then(() => {
handleCloudInstall()
}).catch((action) => {
action == 'cancel' && window.open('https://doc.press.niucloud.com/php/saas-framework/use/other/third-party-cloud-compilation.html', '_blank')
})
} else {
ElMessage({ message: res.msg, type: 'error' })
}
}) })
} }
@ -1470,6 +1494,13 @@ const getCloudInstallLog = () => {
if (data[0] && data[0].length && installShowDialog.value == true) { if (data[0] && data[0].length && installShowDialog.value == true) {
data[0].forEach((item) => { data[0].forEach((item) => {
if (!installLog.includes(item.action)) { if (!installLog.includes(item.action)) {
if (item.action.indexOf('云编译任务正在排队') != -1) {
cloudQueue = item.action
installLog.push(item.action)
return
} else {
cloudQueue = null
}
terminalRef.value.pushMessage({ content: `${item.action}` }) terminalRef.value.pushMessage({ content: `${item.action}` })
installLog.push(item.action) installLog.push(item.action)

File diff suppressed because it is too large Load Diff

View File

@ -101,46 +101,46 @@ getTransferSceneFn()
// //
const handleInput = (e: any, key: any, data: any) => { const handleInput = (e: any, key: any, data: any) => {
const val = e.target.value?.trim() || '' const val = e.target.value?.trim() || ''
const originalVal = originalValues.value[key] || '' const originalVal = originalValues.value[key] || ''
// //
if (val === '' && originalVal !== '') { if (val === '' && originalVal !== '') {
data.error = false data.error = false
setSceneId({ setSceneId({
scene: key, scene: key,
scene_id: '' scene_id: ''
}).then(() => { }).then(() => {
data.disabled = true data.disabled = true
getTransferSceneFn() getTransferSceneFn()
}) })
return return
} }
// //
if (val === '' && originalVal === '') { if (val === '' && originalVal === '') {
data.error = false data.error = false
data.disabled = true data.disabled = true
return return
} }
// //
if (val.length < 4) { if (val.length < 4) {
data.error = true data.error = true
return return
} }
// 4-5 // 4-5
if (val.length >= 4 && val.length <= 5) { if (val.length >= 4 && val.length <= 5) {
data.error = false data.error = false
setSceneId({ setSceneId({
scene: key, scene: key,
scene_id: val scene_id: val
}).then(() => { }).then(() => {
data.disabled = true data.disabled = true
getTransferSceneFn() getTransferSceneFn()
}) })
} }
} }
const inputRefs = ref<any>({}) const inputRefs = ref<any>({})

View File

@ -87,7 +87,7 @@
<el-table-column :label="t('siteInfo')" width="300" align="left"> <el-table-column :label="t('siteInfo')" width="300" align="left">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center"> <div class="flex items-center">
<img class="w-[54px] h-[54px] mr-[10px] rounded-[4px]" v-if="row.logo" :src="img(row.logo)" alt=""> <img class="w-[54px] h-[54px] mr-[10px] rounded-[4px]" v-if="row.icon" :src="img(row.icon)" alt="">
<img class="w-[54px] h-[54px] mr-[10px] rounded-[4px]" v-else src="@/app/assets/images/site_default.png" alt=""> <img class="w-[54px] h-[54px] mr-[10px] rounded-[4px]" v-else src="@/app/assets/images/site_default.png" alt="">
<div class="flex flex-col"> <div class="flex flex-col">
<span>{{ row.site_name || '' }}</span> <span>{{ row.site_name || '' }}</span>

View File

@ -1 +1,3 @@
/* addon-iconfont.css */ @import "addon/home_service/iconfont.css";
@import "addon/o2o/iconfont.css";
@import "addon/tourism/iconfont.css";

View File

@ -0,0 +1,38 @@
@font-face {
font-family: "o2o"; /* Project id 4412516 */
src: url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff2?t=1705720131974') format('woff2'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff?t=1705720131974') format('woff'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.ttf?t=1705720131974') format('truetype');
}
.o2o {
font-family: "o2o" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.o2o-icon-danhanghuadong:before {
content: "\e66f";
}
.o2o-icon-yuanjiao:before {
content: "\e6c0";
}
.o2o-icon-gl-square:before {
content: "\ea92";
}
.o2o-icon-sousuo12:before {
content: "\e699";
}
.o2o-icon-sousuo11:before {
content: "\e6d4";
}
.o2o-icon-jishi:before {
content: "\e600";
}

View File

@ -0,0 +1,51 @@
{
"id": "4412516",
"name": "上门服务",
"font_family": "o2o",
"css_prefix_text": "o2o-icon-",
"description": "",
"glyphs": [
{
"icon_id": "30621139",
"name": "单行滑动",
"font_class": "danhanghuadong",
"unicode": "e66f",
"unicode_decimal": 58991
},
{
"icon_id": "7149037",
"name": "圆角",
"font_class": "yuanjiao",
"unicode": "e6c0",
"unicode_decimal": 59072
},
{
"icon_id": "7594344",
"name": "20gl-square",
"font_class": "gl-square",
"unicode": "ea92",
"unicode_decimal": 60050
},
{
"icon_id": "10133070",
"name": "搜索",
"font_class": "sousuo12",
"unicode": "e699",
"unicode_decimal": 59033
},
{
"icon_id": "14652583",
"name": "搜索",
"font_class": "sousuo11",
"unicode": "e6d4",
"unicode_decimal": 59092
},
{
"icon_id": "6818781",
"name": "技师",
"font_class": "jishi",
"unicode": "e600",
"unicode_decimal": 58880
}
]
}

View File

@ -0,0 +1,38 @@
@font-face {
font-family: "o2o"; /* Project id 4412516 */
src: url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff2?t=1705720131974') format('woff2'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff?t=1705720131974') format('woff'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.ttf?t=1705720131974') format('truetype');
}
.o2o {
font-family: "o2o" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.o2o-icon-danhanghuadong:before {
content: "\e66f";
}
.o2o-icon-yuanjiao:before {
content: "\e6c0";
}
.o2o-icon-gl-square:before {
content: "\ea92";
}
.o2o-icon-sousuo12:before {
content: "\e699";
}
.o2o-icon-sousuo11:before {
content: "\e6d4";
}
.o2o-icon-jishi:before {
content: "\e600";
}

View File

@ -0,0 +1,51 @@
{
"id": "4412516",
"name": "上门服务",
"font_family": "o2o",
"css_prefix_text": "o2o-icon-",
"description": "",
"glyphs": [
{
"icon_id": "30621139",
"name": "单行滑动",
"font_class": "danhanghuadong",
"unicode": "e66f",
"unicode_decimal": 58991
},
{
"icon_id": "7149037",
"name": "圆角",
"font_class": "yuanjiao",
"unicode": "e6c0",
"unicode_decimal": 59072
},
{
"icon_id": "7594344",
"name": "20gl-square",
"font_class": "gl-square",
"unicode": "ea92",
"unicode_decimal": 60050
},
{
"icon_id": "10133070",
"name": "搜索",
"font_class": "sousuo12",
"unicode": "e699",
"unicode_decimal": 59033
},
{
"icon_id": "14652583",
"name": "搜索",
"font_class": "sousuo11",
"unicode": "e6d4",
"unicode_decimal": 59092
},
{
"icon_id": "6818781",
"name": "技师",
"font_class": "jishi",
"unicode": "e600",
"unicode_decimal": 58880
}
]
}

View File

@ -0,0 +1,58 @@
@font-face {
font-family: "tourism"; /* Project id 4137250 */
src: url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.woff2?t=1687685028672') format('woff2'),
url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.woff?t=1687685028672') format('woff'),
url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.ttf?t=1687685028672') format('truetype');
}
.tourism {
font-family: "tourism" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.tourism-icon-feiji:before {
content: "\e600";
}
.tourism-icon-lvyou:before {
content: "\e6a9";
}
.tourism-icon-lvyouchanpin:before {
content: "\e63b";
}
.tourism-icon-lvyou1:before {
content: "\e623";
}
.tourism-icon-lvyou2:before {
content: "\e601";
}
.tourism-icon-lvyou3:before {
content: "\e60c";
}
.tourism-icon-lvyoubaochedingdan:before {
content: "\e612";
}
.tourism-icon-lvyou4:before {
content: "\e653";
}
.tourism-icon-lvyou5:before {
content: "\e610";
}
.tourism-icon-lvyouguanguang:before {
content: "\e87e";
}
.tourism-icon-lvyou6:before {
content: "\e642";
}

View File

@ -0,0 +1,86 @@
{
"id": "4137250",
"name": "旅游业",
"font_family": "tourism",
"css_prefix_text": "tourism-icon-",
"description": "",
"glyphs": [
{
"icon_id": "1443",
"name": "飞机",
"font_class": "feiji",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "446824",
"name": "旅游",
"font_class": "lvyou",
"unicode": "e6a9",
"unicode_decimal": 59049
},
{
"icon_id": "1167173",
"name": "旅游产品",
"font_class": "lvyouchanpin",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "1354920",
"name": "旅游",
"font_class": "lvyou1",
"unicode": "e623",
"unicode_decimal": 58915
},
{
"icon_id": "1505555",
"name": "旅游",
"font_class": "lvyou2",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "2121726",
"name": "旅游",
"font_class": "lvyou3",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "2357494",
"name": "旅游包车订单",
"font_class": "lvyoubaochedingdan",
"unicode": "e612",
"unicode_decimal": 58898
},
{
"icon_id": "3944019",
"name": "旅游",
"font_class": "lvyou4",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "4838220",
"name": "旅游",
"font_class": "lvyou5",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "7444178",
"name": "旅游观光",
"font_class": "lvyouguanguang",
"unicode": "e87e",
"unicode_decimal": 59518
},
{
"icon_id": "9748082",
"name": "旅游",
"font_class": "lvyou6",
"unicode": "e642",
"unicode_decimal": 58946
}
]
}

View File

@ -21,6 +21,27 @@ interface requestResponse extends AxiosResponse {
config: InternalRequestConfig config: InternalRequestConfig
} }
class ErrorResponse {
msg: string = '';
code: number = 0;
response: any = null;
constructor(msg: string);
constructor(code: number, msg: string, response: any);
constructor(arg1?: string | number, arg2?: string, arg3?: any) {
if (typeof arg1 === 'number') {
this.code = arg1;
this.msg = arg2 || '';
this.response = arg3; // 修正点3补上漏掉的赋值
} else {
this.msg = (arg1 as string) || '';
this.code = 0;
this.response = null;
}
}
}
class Request { class Request {
private instance: AxiosInstance; private instance: AxiosInstance;
@ -45,7 +66,7 @@ class Request {
return config return config
}, },
(err: any) => { (err: any) => {
return Promise.reject(err) return Promise.reject(new ErrorResponse(0, err.message, err.response))
} }
) )
@ -57,7 +78,7 @@ class Request {
if (res.code != 1) { if (res.code != 1) {
this.handleAuthError(res.code) this.handleAuthError(res.code)
if (res.code != 401 && response.config.showErrorMessage !== false) this.showElMessage({ message: res.msg, type: 'error', dangerouslyUseHTMLString: true, duration: 5000 }) if (res.code != 401 && response.config.showErrorMessage !== false) this.showElMessage({ message: res.msg, type: 'error', dangerouslyUseHTMLString: true, duration: 5000 })
return Promise.reject(new Error(res.msg || 'Error')) return Promise.reject(res)
} else { } else {
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' }) if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
return res return res
@ -67,7 +88,7 @@ class Request {
}, },
(err: any) => { (err: any) => {
this.handleNetworkError(err) this.handleNetworkError(err)
return Promise.reject(err) return Promise.reject(new ErrorResponse(0, err.message, err.response))
} }
) )
} }
@ -195,7 +216,7 @@ class Request {
this.messageCache.set(cacheKey, { timestamp: now }); this.messageCache.set(cacheKey, { timestamp: now });
ElMessage(options) ElMessage(options)
} }
// 定期清理过期缓存,防止内存泄漏 // 定期清理过期缓存,防止内存泄漏
if (this.messageCache.size > this.MAX_CACHE_SIZE) { if (this.messageCache.size > this.MAX_CACHE_SIZE) {
for (const [key, value] of this.messageCache.entries()) { for (const [key, value] of this.messageCache.entries()) {

View File

@ -108,7 +108,7 @@ class ExceptionHandle extends Handle
} else if ($e instanceof RouteNotFoundException) { } else if ($e instanceof RouteNotFoundException) {
return fail('当前访问路由未定义或不匹配 路由地址:' . request()->baseUrl()); return fail('当前访问路由未定义或不匹配 路由地址:' . request()->baseUrl());
} else if($e instanceof \RuntimeException){ } else if($e instanceof \RuntimeException){
return fail($e->getMessage(), $massageData); return fail($e->getMessage(), $massageData, $e->getCode() ?: 0);
} else { } else {
return $this->handleException($e); return $this->handleException($e);
} }

View File

@ -30,7 +30,10 @@ class Cloud extends BaseAdminController
* @return \think\Response * @return \think\Response
*/ */
public function build() { public function build() {
return success(data:(new CoreCloudBuildService())->cloudBuild()); $data = $this->request->params([
[ 'addon', [] ]
]);
return success(data:(new CoreCloudBuildService())->cloudBuild($data['addon']));
} }
/** /**
@ -79,7 +82,7 @@ class Cloud extends BaseAdminController
$data = $this->request->params([ $data = $this->request->params([
[ 'url', '' ], [ 'url', '' ],
]); ]);
$is_connected = (new CloudService(true,$data['url']))->is_connected; $is_connected = (new CloudService(true, $data['url']))->is_connected;
return success('SUCCESS',$is_connected); return success('SUCCESS',$is_connected);
} }
@ -91,8 +94,8 @@ class Cloud extends BaseAdminController
public function setLocalCloudCompileConfig() public function setLocalCloudCompileConfig()
{ {
$data = $this->request->params([ $data = $this->request->params([
[ 'is_open', 0],
[ 'url', '' ], [ 'url', '' ],
[ 'is_open', 0 ],
]); ]);
return success('SUCCESS',(new NiucloudService())->setLocalCloudCompileConfig($data)); return success('SUCCESS',(new NiucloudService())->setLocalCloudCompileConfig($data));
} }
@ -106,4 +109,36 @@ class Cloud extends BaseAdminController
{ {
return success('SUCCESS',(new NiucloudService())->getLocalCloudCompileConfig()); return success('SUCCESS',(new NiucloudService())->getLocalCloudCompileConfig());
} }
/**
* 启动后台下载SSE编译完成后调用
* @description 启动后台下载
* @return \think\Response
*/
public function startServerDownload()
{
$data = $this->request->params([
[ 'task_id', '' ],
[ 'download_url', '' ],
[ 'authorize_code', '' ],
[ 'timestamp', '' ],
]);
return success('操作成功', (new CoreCloudBuildService())->startServerDownload(
$data['task_id'],
$data['download_url'],
$data['authorize_code'],
$data['timestamp']
));
}
/**
* 获取后台下载进度
* @description 获取后台下载进度
* @return \think\Response
*/
public function getSseBuildLog()
{
$taskId = $this->request->param('task_id', '');
return success('操作成功', (new CoreCloudBuildService())->getSseBuildLog($taskId));
}
} }

View File

@ -89,4 +89,13 @@ class Version extends BaseAdminController
public function uploadLog(string $key) { public function uploadLog(string $key) {
return success(data: (new WeappVersionService())->getUploadLog($key)); return success(data: (new WeappVersionService())->getUploadLog($key));
} }
/**
* 直接获取小程序上传日志(不更新状态)
* @param string $key
* @return Response
*/
public function getUploadLogOnly(string $key) {
return success(data: (new WeappVersionService())->getUploadLogOnly($key));
}
} }

View File

@ -61,6 +61,10 @@ Route::group('niucloud', function() {
Route::post('build/set_local_url', 'niucloud.Cloud/setLocalCloudCompileConfig'); Route::post('build/set_local_url', 'niucloud.Cloud/setLocalCloudCompileConfig');
//获取本地服务器地址 //获取本地服务器地址
Route::get('build/get_local_url', 'niucloud.Cloud/getLocalCloudCompileConfig'); Route::get('build/get_local_url', 'niucloud.Cloud/getLocalCloudCompileConfig');
//启动后台下载SSE编译完成后
Route::post('build/start_server_download', 'niucloud.Cloud/startServerDownload');
//获取后台下载进度
Route::get('build/get_sse_build_log', 'niucloud.Cloud/getSseBuildLog');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

View File

@ -44,8 +44,10 @@ Route::group('weapp', function() {
Route::get('version', 'weapp.Version/lists'); Route::get('version', 'weapp.Version/lists');
//获取预览码 //获取预览码
Route::get('preview', 'weapp.Version/preview'); Route::get('preview', 'weapp.Version/preview');
//获取小程序上传日志 //获取小程序上传日志(会更新状态)
Route::get('upload/:key', 'weapp.Version/uploadLog'); Route::get('upload/:key', 'weapp.Version/uploadLog');
//直接获取小程序上传日志(不更新状态)
Route::get('upload_log/:key', 'weapp.Version/getUploadLogOnly');

View File

@ -30,6 +30,7 @@ class Pay extends BaseApiController
*/ */
public function notify($site_id, $channel, $type, $action) public function notify($site_id, $channel, $type, $action)
{ {
$this->request->siteId($site_id);
return (new PayService())->notify($channel, $type, $action); return (new PayService())->notify($channel, $type, $action);
} }

View File

@ -26,6 +26,7 @@ Route::group('pay',function () {
Route::get('friendspay/info/:trade_type/:trade_id', 'pay.Pay/friendspayInfo'); Route::get('friendspay/info/:trade_type/:trade_id', 'pay.Pay/friendspayInfo');
})->middleware(ApiChannel::class) })->middleware(ApiChannel::class)
->middleware(ApiCheckToken::class, false)//表示验证登录
->middleware(ApiLog::class); ->middleware(ApiLog::class);
Route::group('pay',function () { Route::group('pay',function () {
@ -50,4 +51,4 @@ Route::group('transfer',function () {
})->middleware(ApiChannel::class) })->middleware(ApiChannel::class)
->middleware(ApiCheckToken::class, true)//表示验证登录 ->middleware(ApiCheckToken::class, true)//表示验证登录
->middleware(ApiLog::class); ->middleware(ApiLog::class);

View File

@ -56,9 +56,6 @@ class Index extends BaseInstall
//sodium //sodium
$sodium = extension_loaded('sodium'); $sodium = extension_loaded('sodium');
$system_variables[] = [ "name" => "sodium", "need" => "开启", "status" => $sodium ]; $system_variables[] = [ "name" => "sodium", "need" => "开启", "status" => $sodium ];
//imagick
$imagick = extension_loaded('imagick');
$system_variables[] = [ "name" => "imagick", "need" => "开启", "status" => $imagick ];
$root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(__FILE__, 4)); $root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(__FILE__, 4));
$root_path = str_replace("../", DIRECTORY_SEPARATOR, $root_path); $root_path = str_replace("../", DIRECTORY_SEPARATOR, $root_path);
@ -91,7 +88,7 @@ class Index extends BaseInstall
$this->assign("name", $name); $this->assign("name", $name);
$this->assign("verison", $verison); $this->assign("verison", $verison);
$this->assign("dirs_list", $dirs_list); $this->assign("dirs_list", $dirs_list);
if ($verison && $pdo && $curl && $openssl && $gd && $fileinfo && $is_dir && $imagick) { if ($verison && $pdo && $curl && $openssl && $gd && $fileinfo && $is_dir) {
$continue = true; $continue = true;
} else { } else {
$continue = false; $continue = false;
@ -419,7 +416,7 @@ class Index extends BaseInstall
} }
//如果数据库不存在,我们就进行创建。 //如果数据库不存在,我们就进行创建。
$dbsql = "CREATE DATABASE `$dbname`"; $dbsql = "CREATE DATABASE `$dbname` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci";
$db_create = mysqli_query($conn, $dbsql); $db_create = mysqli_query($conn, $dbsql);
if (!$db_create) { if (!$db_create) {
return fail('创建数据库失败,请确认是否有足够的权限!'); return fail('创建数据库失败,请确认是否有足够的权限!');

View File

@ -79,7 +79,7 @@
<tr> <tr>
<td class="onetd">数据库编码:</td> <td class="onetd">数据库编码:</td>
<td> <td>
<label class="install-code">UTF8</label> <label class="install-code">utf8mb4</label>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -320,7 +320,7 @@ return [
'NEED_TO_AUTHORIZE_FIRST' => '使用云服务需先进行授权', 'NEED_TO_AUTHORIZE_FIRST' => '使用云服务需先进行授权',
'WEAPP_UPLOADING' => '小程序有正在上传的版本,请等待上一版本上传完毕后再进行操作', 'WEAPP_UPLOADING' => '小程序有正在上传的版本,请等待上一版本上传完毕后再进行操作',
'CLOUD_BUILD_TASK_EXIST' => '已有正在执行中的编译任务', 'CLOUD_BUILD_TASK_EXIST' => '已有正在执行中的编译任务',
'CONNECT_FAIL' => '连接失败', 'CONNECT_FAIL' => '云编译服务连接失败',
//核销相关 //核销相关
'VERIFY_TYPE_ERROR' => '核销类型错误', 'VERIFY_TYPE_ERROR' => '核销类型错误',

View File

@ -110,13 +110,22 @@ class AuthService extends BaseAdminService
if (strpos($rule, $item) !== false) return; if (strpos($rule, $item) !== false) return;
} }
$authinfo = (new CoreAuthService())->getAuthInfo()['data'] ?? [];; $authinfo = [];
try {
$authinfo = (new CoreAuthService())->getAuthInfo()['data'] ?? [];;
} catch (Exception $e) {
}
if (empty($authinfo)) return; if (empty($authinfo)) return;
if (!$this->isCheckDomain()) return; if (!$this->isCheckDomain()) return;
$site_address = $authinfo['site_address'] ?? ''; $site_address = $authinfo['site_address'] ?? '';
$domain = request()->domain(); $domain = request()->domain();
// 如果是站点域名不进行验证
$site_id = (new CoreSiteService())->getSiteIdByDomain($domain);
if (!empty($site_id)) return;
if (!empty($site_address) && strpos($domain, $site_address) !== false) return; if (!empty($site_address) && strpos($domain, $site_address) !== false) return;
throw new CommonException("授权域名校验失败!请确保当前访问域名与授权码绑定的域名一致"); throw new CommonException("授权域名校验失败!请确保当前访问域名与授权码绑定的域名一致");

View File

@ -96,7 +96,6 @@ class NiucloudService extends BaseAdminService
* @return \app\model\sys\SysConfig|bool|\think\Model * @return \app\model\sys\SysConfig|bool|\think\Model
*/ */
public function setLocalCloudCompileConfig($data){ public function setLocalCloudCompileConfig($data){
$data = [ $data = [
'baseUri' => $data['url'], 'baseUri' => $data['url'],
'isOpen' => $data['is_open'], 'isOpen' => $data['is_open'],

View File

@ -35,6 +35,7 @@ use core\exception\CloudBuildException;
use core\exception\CommonException; use core\exception\CommonException;
use core\util\DbBackup; use core\util\DbBackup;
use core\util\niucloud\BaseNiucloudClient; use core\util\niucloud\BaseNiucloudClient;
use core\util\niucloud\CloudService;
use think\facade\Cache; use think\facade\Cache;
use think\facade\Db; use think\facade\Db;
use think\facade\Log; use think\facade\Log;
@ -228,28 +229,31 @@ class UpgradeService extends BaseAdminService
$response = ( new CoreAddonCloudService() )->upgradeAddon($upgrade); $response = ( new CoreAddonCloudService() )->upgradeAddon($upgrade);
if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]);
$key = uniqid();
$upgrade_dir = $this->upgrade_dir . $key . DIRECTORY_SEPARATOR;
if (!is_dir($upgrade_dir)) {
dir_mkdir($upgrade_dir);
}
// 是否需要备份
$is_need_backup = $data['is_need_backup'] ?? true;
if (!$is_need_backup) {
unset($this->steps['backupCode']);
unset($this->steps['backupSql']);
}
// 是否需要云编译
$is_need_cloudbuild = $data['is_need_cloudbuild'] ?? true;
if (!$is_need_cloudbuild) {
unset($this->steps['cloudBuild']);
unset($this->steps['gteCloudBuildLog']);
} else {
// 校验云编译服务
(new CloudService())->checkLocal();
}
try { try {
$key = uniqid();
$upgrade_dir = $this->upgrade_dir . $key . DIRECTORY_SEPARATOR;
if (!is_dir($upgrade_dir)) {
dir_mkdir($upgrade_dir);
}
// 是否需要备份
$is_need_backup = $data['is_need_backup'] ?? true;
if (!$is_need_backup) {
unset($this->steps['backupCode']);
unset($this->steps['backupSql']);
}
// 是否需要云编译
$is_need_cloudbuild = $data['is_need_cloudbuild'] ?? true;
if (!$is_need_cloudbuild) {
unset($this->steps['cloudBuild']);
unset($this->steps['gteCloudBuildLog']);
}
$upgrade_task = [ $upgrade_task = [
'key' => $key, 'key' => $key,
'upgrade' => $upgrade, 'upgrade' => $upgrade,
@ -731,7 +735,15 @@ class UpgradeService extends BaseAdminService
*/ */
public function cloudBuild() public function cloudBuild()
{ {
( new CoreCloudBuildService() )->cloudBuild(); try {
( new CoreCloudBuildService() )->cloudBuild();
} catch (CommonException $e) {
if ($e->getCode() == 601) {
( new CoreCloudBuildService() )->cloudBuild(['checkLocal' => false]);
} else {
throw new CommonException($e->getMessage(), $e->getCode());
}
}
} }
/** /**

View File

@ -13,6 +13,7 @@ namespace app\service\admin\weapp;
use app\dict\common\CommonDict; use app\dict\common\CommonDict;
use app\model\sys\SysConfig; use app\model\sys\SysConfig;
use app\service\core\sys\CoreConfigService;
use app\service\core\weapp\CoreWeappConfigService; use app\service\core\weapp\CoreWeappConfigService;
use app\service\core\wxoplatform\CoreOplatformService; use app\service\core\wxoplatform\CoreOplatformService;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -80,6 +81,12 @@ class WeappConfigService extends BaseAdminService
* @return array * @return array
*/ */
public function getWeappStaticInfo(){ public function getWeappStaticInfo(){
$local_cloud_compile_config = (new CoreConfigService())->getConfig(0, 'LOCAL_CLOUD_COMPILE_CONFIG')['value'] ?? [];
$baseUri = $local_cloud_compile_config['baseUri'] ?? '';
if (empty($baseUri)) $baseUri = 'oss.niucloud.com';
$baseUri = str_replace('http://', '', $baseUri);
$baseUri = str_replace('https://', '', $baseUri);
$domain = request()->domain(); $domain = request()->domain();
$domain = str_replace('http://', 'https://', $domain); $domain = str_replace('http://', 'https://', $domain);
return [ return [
@ -88,7 +95,7 @@ class WeappConfigService extends BaseAdminService
'socket_url' => "wss://".request()->host(), 'socket_url' => "wss://".request()->host(),
'upload_url' => $domain, 'upload_url' => $domain,
'download_url' => $domain, 'download_url' => $domain,
'upload_ip' => gethostbyname('oss.niucloud.com') 'upload_ip' => gethostbyname($baseUri)
]; ];
} }

View File

@ -141,17 +141,30 @@ class WeappVersionService extends BaseAdminService
if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) { if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) {
$last = end($build_log['data'][0]); $last = end($build_log['data'][0]);
file_put_contents(runtime_path() . 'debug_log.txt', date('Y-m-d H:i:s') . " | key: $key | last_code: {$last['code']} | last_percent: {$last['percent']}\n", FILE_APPEND);
if ($last['code'] == 0) { if ($last['code'] == 0) {
(new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_FAIL, 'fail_reason' => $last['msg'] ?? '', 'update_time' => time()], ['task_key' => $key]); $res = (new WeappVersion())->where(['task_key' => $key])->update(['status' => CloudDict::APPLET_UPLOAD_FAIL, 'fail_reason' => $last['msg'] ?? '', 'update_time' => time()]);
file_put_contents(runtime_path() . 'debug_log.txt', date('Y-m-d H:i:s') . " | fail update result: $res\n", FILE_APPEND);
return $build_log; return $build_log;
} }
if ($last['percent'] == 100) { if ($last['percent'] == 100) {
(new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_SUCCESS, 'update_time' => time()], ['task_key' => $key]); $res = (new WeappVersion())->where(['task_key' => $key])->update(['status' => CloudDict::APPLET_UPLOAD_SUCCESS, 'update_time' => time()]);
file_put_contents(runtime_path() . 'debug_log.txt', date('Y-m-d H:i:s') . " | success update result: $res\n", FILE_APPEND);
} }
} }
return $build_log; return $build_log;
} }
/**
* 直接获取小程序上传日志(不更新状态)
* @param string $key
* @return null
*/
public function getUploadLogOnly(string $key)
{
return (new CoreWeappCloudService())->getWeappCompileLog($key);
}
/** /**
* 获取小程序上传日志 * 获取小程序上传日志
* @param string $key * @param string $key

View File

@ -23,6 +23,7 @@ use core\exception\AuthException;
use think\db\exception\DataNotFoundException; use think\db\exception\DataNotFoundException;
use think\db\exception\DbException; use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException; use think\db\exception\ModelNotFoundException;
use think\facade\Log;
/** /**
* 登录服务层 * 登录服务层
@ -78,8 +79,14 @@ class RegisterService extends BaseApiService
} }
$member_id = ( new MemberService() )->add($data); $member_id = ( new MemberService() )->add($data);
$data[ 'member_id' ] = $member_id; $data[ 'member_id' ] = $member_id;
event('MemberRegister', $data);
SetMemberNoJob::dispatch([ 'site_id' => $this->site_id, 'member_id' => $member_id ]); SetMemberNoJob::dispatch([ 'site_id' => $this->site_id, 'member_id' => $member_id ]);
try {
event('MemberRegister', $data);
} catch (\Exception $e) {
Log::write('MemberRegister event error');
Log::write($e->getTrace());
}
} }
$member_info = $member_service->findMemberInfo([ 'member_id' => $member_id, 'site_id' => $this->site_id ]); $member_info = $member_service->findMemberInfo([ 'member_id' => $member_id, 'site_id' => $this->site_id ]);
if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在

View File

@ -17,6 +17,7 @@ use core\exception\CommonException;
use core\util\niucloud\BaseNiucloudClient; use core\util\niucloud\BaseNiucloudClient;
use core\util\niucloud\CloudService; use core\util\niucloud\CloudService;
use think\facade\Cache; use think\facade\Cache;
use think\facade\Log;
/** /**
*/ */
@ -86,7 +87,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
'authorize_code' => $this->auth_code, 'authorize_code' => $this->auth_code,
'timestamp' => $install_task['timestamp'] 'timestamp' => $install_task['timestamp']
]; ];
$response = (new CloudService())->httpPost('cloud/build?' . http_build_query($query), [ $response = (new CloudService(true))->httpPost('cloud/build?' . http_build_query($query), [
'multipart' => [ 'multipart' => [
[ [
'name' => 'file', 'name' => 'file',
@ -122,11 +123,11 @@ class CoreAddonCloudService extends CoreCloudBaseService
'authorize_code' => $this->auth_code, 'authorize_code' => $this->auth_code,
'timestamp' => $install_task['timestamp'] 'timestamp' => $install_task['timestamp']
]; ];
$build_log = (new CloudService())->httpGet('cloud/get_build_logs?' . http_build_query($query)); $build_log = (new CloudService(true))->httpGet('cloud/get_build_logs?' . http_build_query($query));
if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) { if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) {
$last = end($build_log['data'][0]); $last = end($build_log['data'][0]);
if ($last['percent'] == 100 && $last['code'] == 0) { if ((int) $last['code'] == 0) {
(new CoreAddonInstallService($addon))->installExceptionHandle(); (new CoreAddonInstallService($addon))->installExceptionHandle();
$install_task['error'] = 'ADDON_INSTALL_FAIL'; $install_task['error'] = 'ADDON_INSTALL_FAIL';
Cache::set('install_task', $install_task, 10); Cache::set('install_task', $install_task, 10);
@ -162,8 +163,8 @@ class CoreAddonCloudService extends CoreCloudBaseService
$cache = Cache::get('build_success_' . $addon); $cache = Cache::get('build_success_' . $addon);
if (is_null($cache)) { if (is_null($cache) || !isset($cache[ 'index' ])) {
$response = (new CloudService())->request('HEAD','cloud/build_download?' . http_build_query($query), [ $response = (new CloudService(true))->request('HEAD','cloud/build_download?' . http_build_query($query), [
'headers' => ['Range' => 'bytes=0-'] 'headers' => ['Range' => 'bytes=0-']
]); ]);
$length = $response->getHeader('Content-range'); $length = $response->getHeader('Content-range');
@ -187,7 +188,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
$end = ($cache['index'] + 1) * $chunk_size; $end = ($cache['index'] + 1) * $chunk_size;
$end = min($end, $cache['length']); $end = min($end, $cache['length']);
$response = (new CloudService())->request('GET','cloud/build_download?' . http_build_query($query), [ $response = (new CloudService(true))->request('GET','cloud/build_download?' . http_build_query($query), [
'headers' => ['Range' => "bytes={$start}-{$end}"] 'headers' => ['Range' => "bytes={$start}-{$end}"]
]); ]);
fwrite($zip_resource, $response->getBody()); fwrite($zip_resource, $response->getBody());
@ -225,10 +226,18 @@ class CoreAddonCloudService extends CoreCloudBaseService
Cache::set('build_success_' . $addon, null); Cache::set('build_success_' . $addon, null);
} else { } else {
Cache::set('build_success_' . $addon, null); if (!isset($cache[ 'retry' ])) {
// 调用插件安装异常处理 unlink($zip_file);
(new CoreAddonInstallService($addon))->installExceptionHandle(); $cache['retry'] = 1;
throw new CommonException('Zip decompression failed'); unset($cache['index']);
Cache::set('build_success_' . $addon, $cache);
$log[] = [ 'code' => 1, 'msg' => '编译包解压失败,尝试重新下载', 'action' => '编译包解压失败,尝试重新下载', 'percent' => '100' ];
} else {
Cache::set('build_success_' . $addon, null);
// 调用插件安装异常处理
(new CoreAddonInstallService($addon))->installExceptionHandle();
throw new CommonException('Zip decompression failed');
}
} }
} }
} }
@ -251,7 +260,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
'token' => $action_token['data']['token'] ?? '' 'token' => $action_token['data']['token'] ?? ''
]; ];
// 获取文件大小 // 获取文件大小
$response = (new CloudService())->request('HEAD','cloud/download?' . http_build_query($query), [ $response = (new CloudService(false, 'http://oss.niucloud.com/'))->request('HEAD','cloud/download?' . http_build_query($query), [
'headers' => ['Range' => 'bytes=0-'] 'headers' => ['Range' => 'bytes=0-']
]); ]);
$length = $response->getHeader('Content-range'); $length = $response->getHeader('Content-range');
@ -263,7 +272,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
$zip_file = $temp_dir . $addon . '.zip'; $zip_file = $temp_dir . $addon . '.zip';
$zip_resource = fopen($zip_file, 'w'); $zip_resource = fopen($zip_file, 'w');
$response = (new CloudService())->request('GET','cloud/download?' . http_build_query($query), [ $response = (new CloudService(false, 'http://oss.niucloud.com/'))->request('GET','cloud/download?' . http_build_query($query), [
'headers' => ['Range' => "bytes=0-{$length}"] 'headers' => ['Range' => "bytes=0-{$length}"]
]); ]);
fwrite($zip_resource, $response->getBody()); fwrite($zip_resource, $response->getBody());
@ -286,7 +295,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
'token' => $action_token['data']['token'] ?? '' 'token' => $action_token['data']['token'] ?? ''
]; ];
// 获取文件大小 // 获取文件大小
$response = (new CloudService())->httpGet('cloud/upgrade?' . http_build_query($query)); $response = (new CloudService(false, 'http://oss.niucloud.com/'))->httpGet('cloud/upgrade?' . http_build_query($query));
$response['token'] = $query['token']; $response['token'] = $query['token'];
return $response; return $response;
} }
@ -309,7 +318,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
$chunk_size = 1 * 1024 * 1024; $chunk_size = 1 * 1024 * 1024;
if ($index == -1) { if ($index == -1) {
$response = (new CloudService())->request('HEAD','cloud/upgrade/download?' . http_build_query($query), [ $response = (new CloudService(false, 'http://oss.niucloud.com/'))->request('HEAD','cloud/upgrade/download?' . http_build_query($query), [
'headers' => ['Range' => 'bytes=0-'] 'headers' => ['Range' => 'bytes=0-']
]); ]);
$length = $response->getHeader('Content-range'); $length = $response->getHeader('Content-range');
@ -327,7 +336,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
$end = ($index + 1) * $chunk_size; $end = ($index + 1) * $chunk_size;
$end = min($end, $length); $end = min($end, $length);
$response = (new CloudService())->request('GET','cloud/upgrade/download?' . http_build_query($query), [ $response = (new CloudService(false, 'http://oss.niucloud.com/'))->request('GET','cloud/upgrade/download?' . http_build_query($query), [
'headers' => ['Range' => "bytes={$start}-{$end}"] 'headers' => ['Range' => "bytes={$start}-{$end}"]
]); ]);
fwrite($zip_resource, $response->getBody()); fwrite($zip_resource, $response->getBody());

View File

@ -18,7 +18,9 @@ use app\service\core\menu\CoreMenuService;
use app\service\core\schedule\CoreScheduleInstallService; use app\service\core\schedule\CoreScheduleInstallService;
use core\exception\AddonException; use core\exception\AddonException;
use core\exception\CommonException; use core\exception\CommonException;
use core\util\niucloud\CloudService;
use core\util\Terminal; use core\util\Terminal;
use EasyWeChat\Kernel\Exceptions\Exception;
use think\db\exception\DbException; use think\db\exception\DbException;
use think\db\exception\PDOException; use think\db\exception\PDOException;
use think\facade\Cache; use think\facade\Cache;
@ -224,7 +226,16 @@ class CoreAddonInstallService extends CoreAddonBaseService
$this->backupFrontend(); $this->backupFrontend();
$tips = []; $tips = [];
if ($mode != 'cloud') $tips[] = get_lang('dict_addon.install_after_update'); if ($mode != 'cloud') {
$tips[] = get_lang('dict_addon.install_after_update');
} else {
try {
(new CloudService())->checkLocal();
} catch (\Exception $e) {
Cache::set('install_task', null);
throw new CommonException($e->getMessage(), $e->getCode());
}
}
foreach ($this->addon_list as $addon) { foreach ($this->addon_list as $addon) {
$this->install_task['addon'] = $addon; $this->install_task['addon'] = $addon;
@ -625,6 +636,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
$addon_info = $core_addon_service->getInfoByKey($this->addon); $addon_info = $core_addon_service->getInfoByKey($this->addon);
if (empty($addon_info)) throw new AddonException('NOT_UNINSTALL'); if (empty($addon_info)) throw new AddonException('NOT_UNINSTALL');
if (!$this->uninstallSql()) throw new AddonException('ADDON_SQL_FAIL'); if (!$this->uninstallSql()) throw new AddonException('ADDON_SQL_FAIL');
if (!$this->uninstallDir()) throw new AddonException('ADDON_DIR_FAIL');
// 卸载菜单 // 卸载菜单
$this->uninstallMenu(); $this->uninstallMenu();

View File

@ -15,6 +15,7 @@ use app\dict\addon\AddonDict;
use app\model\addon\Addon; use app\model\addon\Addon;
use app\service\core\addon\CoreAddonBaseService; use app\service\core\addon\CoreAddonBaseService;
use app\service\core\addon\CoreAddonDevelopDownloadService; use app\service\core\addon\CoreAddonDevelopDownloadService;
use app\service\core\addon\CoreAddonService;
use app\service\core\addon\WapTrait; use app\service\core\addon\WapTrait;
use core\base\BaseCoreService; use core\base\BaseCoreService;
use core\exception\CloudBuildException; use core\exception\CloudBuildException;
@ -105,6 +106,7 @@ class CoreCloudBuildService extends BaseCoreService
// 是否通过校验 // 是否通过校验
$data[ 'is_pass' ] = !in_array(false, $check_res); $data[ 'is_pass' ] = !in_array(false, $check_res);
return $data; return $data;
} }
@ -113,14 +115,25 @@ class CoreCloudBuildService extends BaseCoreService
* @return array * @return array
* @throws GuzzleException * @throws GuzzleException
*/ */
public function cloudBuild() public function cloudBuild($param = [])
{ {
if (empty($this->auth_code)) { if (empty($this->auth_code)) {
throw new CommonException('CLOUD_BUILD_AUTH_CODE_NOT_FOUND'); throw new CommonException('CLOUD_BUILD_AUTH_CODE_NOT_FOUND');
} }
if ($this->build_task) throw new CommonException('CLOUD_BUILD_TASK_EXIST'); if ($this->build_task) throw new CommonException('CLOUD_BUILD_TASK_EXIST');
$action_token = ( new CoreModuleService() )->getActionToken('cloudbuild', [ 'data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ] ]); // 全部插件
$all_addon = array_keys((new CoreAddonService())->getInstallAddonList());
// 排除的插件
$exclude_addon = [];
if (isset($param['addon']) && !empty($param['addon'])) $exclude_addon = array_values(array_diff($all_addon, $param['addon']));
$action_token = [ 'data' => [] ];
try {
$action_token = ( new CoreModuleService() )->getActionToken('cloudbuild', [ 'data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ] ]);
} catch (\Exception $e) {
}
// 上传任务key // 上传任务key
$task_key = uniqid(); $task_key = uniqid();
@ -134,18 +147,24 @@ class CoreCloudBuildService extends BaseCoreService
// 拷贝手机端文件 // 拷贝手机端文件
$wap_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%wap%' ] ])->field('id')->findOrEmpty(); $wap_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%wap%' ] ])->field('id')->findOrEmpty();
if ($wap_is_compile->isEmpty()) { if ($wap_is_compile->isEmpty()) {
dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist', '.git' ]); dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist', '.git', ...$exclude_addon ]);
$this->handleUniapp($package_dir . 'uni-app'); // 如果有排除的插件
if (!empty($exclude_addon)) {
// 处理pages.json
$this->handlePageCode($package_dir . 'uni-app' . DIRECTORY_SEPARATOR .'src' . DIRECTORY_SEPARATOR, $param['addon']);
// 处理diy-group
$this->compileDiyComponentsCode($package_dir . 'uni-app'. DIRECTORY_SEPARATOR .'src' . DIRECTORY_SEPARATOR, $exclude_addon[0]);
}
} }
// 拷贝admin端文件 // 拷贝admin端文件
$admin_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%admin%' ] ])->field('id')->findOrEmpty(); $admin_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%admin%' ] ])->field('id')->findOrEmpty();
if ($admin_is_compile->isEmpty()) { if ($admin_is_compile->isEmpty()) {
dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea', '.git' ]); dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea', '.git', ...$exclude_addon ]);
} }
// 拷贝web端文件 // 拷贝web端文件
$web_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%web%' ] ])->field('id')->findOrEmpty(); $web_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%web%' ] ])->field('id')->findOrEmpty();
if ($web_is_compile->isEmpty()) { if ($web_is_compile->isEmpty()) {
dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt', '.git' ]); dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt', '.git', ...$exclude_addon ]);
} }
$this->handleCustomPort($package_dir); $this->handleCustomPort($package_dir);
@ -159,7 +178,10 @@ class CoreCloudBuildService extends BaseCoreService
'token' => $action_token[ 'data' ][ 'token' ] ?? '' 'token' => $action_token[ 'data' ][ 'token' ] ?? ''
]; ];
set_time_limit(0); set_time_limit(0);
$response = ( new CloudService(true) )->httpPost('cloud/build?' . http_build_query($query), [
$param['checkLocal'] = $param['checkLocal'] ?? true;
$response = ( new CloudService($param['checkLocal']) )->httpPost('cloud/build?' . http_build_query($query), [
'multipart' => [ 'multipart' => [
[ [
'name' => 'file', 'name' => 'file',
@ -173,17 +195,45 @@ class CoreCloudBuildService extends BaseCoreService
$this->build_task = [ $this->build_task = [
'task_key' => $task_key, 'task_key' => $task_key,
'timestamp' => $query[ 'timestamp' ] 'timestamp' => $query[ 'timestamp' ],
'checkLocal' => $param['checkLocal'],
'task_id' => $response['data']['task_id'] ?? '',
'auth_code' => $this->auth_code
]; ];
Cache::set($this->cache_key, $this->build_task); Cache::set($this->cache_key, $this->build_task);
return $this->build_task; return $this->build_task;
} }
private function handleUniapp(string $dir) private function handlePageCode($compile_path, $addon_arr)
{ {
$addon = ( new Addon() )->where([ [ 'status', '=', AddonDict::ON ] ])->value('key', ''); $pages = [];
$this->compileDiyComponentsCode($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $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';
// 对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);
} }
private function handleCustomPort(string $package_dir) private function handleCustomPort(string $package_dir)
@ -226,10 +276,16 @@ class CoreCloudBuildService extends BaseCoreService
'authorize_code' => $this->auth_code, 'authorize_code' => $this->auth_code,
'timestamp' => $this->build_task[ 'timestamp' ] 'timestamp' => $this->build_task[ 'timestamp' ]
]; ];
$build_log = ( new CloudService(true) )->httpGet('cloud/get_build_logs?' . http_build_query($query)); $build_log = ( new CloudService($this->build_task['checkLocal'] ?? false) )->httpGet('cloud/get_build_logs?' . http_build_query($query));
if (isset($build_log[ 'data' ]) && isset($build_log[ 'data' ][ 0 ]) && is_array($build_log[ 'data' ][ 0 ])) { if (isset($build_log[ 'data' ]) && isset($build_log[ 'data' ][ 0 ]) && is_array($build_log[ 'data' ][ 0 ])) {
$last = end($build_log[ 'data' ][ 0 ]); $last = end($build_log[ 'data' ][ 0 ]);
foreach ($build_log[ 'data' ][ 0 ] as $item) {
if ($item['code'] == 0) {
$build_log[ 'error_analysis' ] = $this->buildResultAnalysis($item[ 'msg' ]);
break;
}
}
if ($last[ 'percent' ] == 100 && $last[ 'code' ] == 1) { if ($last[ 'percent' ] == 100 && $last[ 'code' ] == 1) {
$build_log[ 'data' ][ 0 ] = $this->buildSuccess($build_log[ 'data' ][ 0 ]); $build_log[ 'data' ][ 0 ] = $this->buildSuccess($build_log[ 'data' ][ 0 ]);
} }
@ -237,6 +293,15 @@ class CoreCloudBuildService extends BaseCoreService
return $build_log; return $build_log;
} }
/**
* 编译异常分析
* @param $msg
* @return string[]
*/
public function buildResultAnalysis($msg) {
return ( new CoreModuleService() )->buildResultAnalysis($msg);
}
/** /**
* 编译完成 * 编译完成
* @param array $log * @param array $log
@ -253,7 +318,7 @@ class CoreCloudBuildService extends BaseCoreService
$temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR; $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR;
if (!isset($this->build_task[ 'index' ])) { if (!isset($this->build_task[ 'index' ])) {
$response = ( new CloudService(true) )->request('HEAD', 'cloud/build_download?' . http_build_query($query), [ $response = ( new CloudService($this->build_task['checkLocal'] ?? false) )->request('HEAD', 'cloud/build_download?' . http_build_query($query), [
'headers' => [ 'Range' => 'bytes=0-' ] 'headers' => [ 'Range' => 'bytes=0-' ]
]); ]);
$length = $response->getHeader('Content-range'); $length = $response->getHeader('Content-range');
@ -271,7 +336,7 @@ class CoreCloudBuildService extends BaseCoreService
$end = ( $this->build_task[ 'index' ] + 1 ) * $chunk_size; $end = ( $this->build_task[ 'index' ] + 1 ) * $chunk_size;
$end = min($end, $this->build_task[ 'length' ]); $end = min($end, $this->build_task[ 'length' ]);
$response = ( new CloudService(true) )->request('GET', 'cloud/build_download?' . http_build_query($query), [ $response = ( new CloudService($this->build_task['checkLocal'] ?? false) )->request('GET', 'cloud/build_download?' . http_build_query($query), [
'headers' => [ 'Range' => "bytes={$start}-{$end}" ] 'headers' => [ 'Range' => "bytes={$start}-{$end}" ]
]); ]);
fwrite($zip_resource, $response->getBody()); fwrite($zip_resource, $response->getBody());
@ -290,9 +355,21 @@ class CoreCloudBuildService extends BaseCoreService
$zip->extractTo($temp_dir . 'download'); $zip->extractTo($temp_dir . 'download');
$zip->close(); $zip->close();
if (is_dir($temp_dir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'admin')) {
@del_target_dir(public_path() .'admin', true);
}
if (is_dir($temp_dir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'web')) {
@del_target_dir(public_path() .'web', true);
}
if (is_dir($temp_dir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'wap')) {
@del_target_dir(public_path() .'wap', true);
}
$exclude_files = ['favicon.ico', 'niucloud.ico']; $exclude_files = ['favicon.ico', 'niucloud.ico'];
dir_copy($temp_dir . 'download', root_path(), exclude_files: $exclude_files); dir_copy($temp_dir . 'download', root_path(), exclude_files: $exclude_files);
$this->buildResultAnalysis('success');
$this->clearTask(); $this->clearTask();
} else { } else {
// 压缩包解压失败 尝试重新下载 // 压缩包解压失败 尝试重新下载
@ -304,6 +381,7 @@ class CoreCloudBuildService extends BaseCoreService
$log[] = [ 'code' => 1, 'msg' => '编译包解压失败,尝试重新下载', 'action' => '编译包解压失败,尝试重新下载', 'percent' => '100' ]; $log[] = [ 'code' => 1, 'msg' => '编译包解压失败,尝试重新下载', 'action' => '编译包解压失败,尝试重新下载', 'percent' => '100' ];
} else { } else {
$log[] = [ 'code' => 0, 'msg' => '编译包解压失败', 'action' => '编译包解压', 'percent' => '100' ]; $log[] = [ 'code' => 0, 'msg' => '编译包解压失败', 'action' => '编译包解压', 'percent' => '100' ];
$this->buildResultAnalysis('编译包解压失败');
} }
} }
} }
@ -322,8 +400,276 @@ class CoreCloudBuildService extends BaseCoreService
public function clearTask() public function clearTask()
{ {
if (!$this->build_task) return; if (!$this->build_task) return;
if (isset($this->build_task['task_id']) && !empty($this->build_task['task_id'])) {
try {
( new CloudService($this->build_task['checkLocal'] ?? false) )->httpPost('cloud/cancel', [
'json' => [
'task_id' => $this->build_task['task_id']
]
]);
} catch (\Throwable $e) {
}
}
$temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR; $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR;
@del_target_dir($temp_dir, true); @del_target_dir($temp_dir, true);
Cache::set($this->cache_key, null); Cache::set($this->cache_key, null);
} }
/**
* 获取插件定义的package目录
* @param string $addon
* @return string
*/
public function geAddonPackagePath(string $addon)
{
return root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR;
}
/**
* SSE编译完成后PHP后台执行下载解压部署
* @param string $taskId 任务ID
* @param string $downloadUrl 下载链接
* @param string $authorizeCode 授权码
* @param string $timestamp 时间戳
* @return array
*/
public function startServerDownload(string $taskId, string $downloadUrl, string $authorizeCode, string $timestamp)
{
$taskKey = 'sse_build_' . $taskId;
$tempDir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $taskKey . DIRECTORY_SEPARATOR;
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$downloadInfo = [
'task_id' => $taskId,
'task_key' => $taskKey,
'download_url' => $downloadUrl,
'authorize_code' => $authorizeCode,
'timestamp' => $timestamp,
'temp_dir' => $tempDir,
'zip_file' => $tempDir . 'download.zip',
'chunk_size' => 1 * 1024 * 1024,
'status' => 'downloading',
'msg' => '准备下载...'
];
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return ['code' => 1, 'msg' => '初始化成功', 'data' => [
'task_key' => $taskKey,
'cache_key' => 'cloud_build_' . $taskKey,
'cache_exists' => Cache::has('cloud_build_' . $taskKey)
]];
}
/**
* 获取SSE编译后续操作的进度参考 buildSuccess 逻辑)
* @param string $taskId 任务ID
* @return array
*/
public function getSseBuildLog(string $taskId)
{
$taskKey = 'sse_build_' . $taskId;
$cacheKey = 'cloud_build_' . $taskKey;
$hasBefore = Cache::has($cacheKey);
$downloadInfo = Cache::get($cacheKey);
if (empty($downloadInfo)) {
return ['code' => 0, 'msg' => '任务不存在或已过期', 'status' => 'error', 'debug' => [
'task_id' => $taskId,
'task_key' => $taskKey,
'cache_key' => $cacheKey,
'cache_has_before' => $hasBefore
]];
}
$query = [
'authorize_code' => $downloadInfo['authorize_code'],
'timestamp' => $downloadInfo['timestamp']
];
try {
if (!isset($downloadInfo['index'])) {
$response = ( new CloudService(true) )->request('HEAD', 'cloud/build_download?' . http_build_query($query), [
'headers' => ['Range' => 'bytes=0-']
]);
$contentRange = $response->getHeader('Content-range');
$length = (int) explode("/", $contentRange[0])[1];
$chunkSize = $downloadInfo['chunk_size'];
$step = (int) ceil($length / $chunkSize);
$downloadInfo['index'] = 0;
$downloadInfo['length'] = $length;
$downloadInfo['step'] = $step;
$downloadInfo['downloaded_bytes'] = 0;
$downloadInfo['percent'] = 0;
$downloadInfo['msg'] = '开始下载...';
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 1,
'status' => 'downloading',
'percent' => 0,
'downloaded_bytes' => 0,
'total_bytes' => $length,
'msg' => '开始下载...'
];
} else {
$zipFile = $downloadInfo['zip_file'];
$zipResource = fopen($zipFile, 'a');
if (($downloadInfo['index'] + 1) <= $downloadInfo['step']) {
$start = $downloadInfo['index'] * $downloadInfo['chunk_size'];
$end = ($downloadInfo['index'] + 1) * $downloadInfo['chunk_size'];
$end = min($end, $downloadInfo['length']);
$expectedBytes = $end - $start;
$response = ( new CloudService(true) )->request('GET', 'cloud/build_download?' . http_build_query($query), [
'headers' => ['Range' => "bytes={$start}-{$end}"]
]);
$body = $response->getBody();
$actualBytes = strlen($body);
$contentRange = $response->getHeader('Content-Range');
$contentRangeStr = is_array($contentRange) ? ($contentRange[0] ?? '') : $contentRange;
if ($actualBytes != $expectedBytes) {
$downloadInfo['downloaded_bytes'] = filesize($zipFile);
$downloadInfo['msg'] = "分片{$downloadInfo['index']}大小不符: 期望{$expectedBytes}, 实际{$actualBytes}";
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 1,
'status' => 'downloading',
'percent' => $downloadInfo['percent'],
'downloaded_bytes' => $downloadInfo['downloaded_bytes'],
'total_bytes' => $downloadInfo['length'],
'msg' => $downloadInfo['msg'],
'debug' => [
'chunk_index' => $downloadInfo['index'],
'expected_bytes' => $expectedBytes,
'actual_bytes' => $actualBytes,
'content_range' => $contentRangeStr
]
];
}
fwrite($zipResource, $body);
fclose($zipResource);
$downloadInfo['index'] += 1;
$downloadInfo['downloaded_bytes'] = filesize($zipFile);
$downloadInfo['percent'] = round($downloadInfo['index'] / $downloadInfo['step'] * 100);
$downloadInfo['msg'] = '编译包下载中,已下载' . $downloadInfo['percent'] . '%';
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 1,
'status' => 'downloading',
'percent' => $downloadInfo['percent'],
'downloaded_bytes' => $downloadInfo['downloaded_bytes'],
'total_bytes' => $downloadInfo['length'],
'msg' => $downloadInfo['msg']
];
} else {
fclose($zipResource);
$zip = new \ZipArchive();
$zipOpenResult = $zip->open($zipFile);
if ($zipOpenResult === true) {
$extractDir = $downloadInfo['temp_dir'] . 'download' . DIRECTORY_SEPARATOR;
dir_mkdir($extractDir);
$zipContents = [];
for ($i = 0; $i < $zip->numFiles; $i++) {
$zipContents[] = $zip->getNameIndex($i);
}
$zip->extractTo($extractDir);
$zip->close();
$downloadInfo['msg'] = '解压成功,文件数:' . count($zipContents);
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
$tempDir = $downloadInfo['temp_dir'];
if (is_dir($tempDir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'admin')) {
@del_target_dir(public_path() . 'admin', true);
}
if (is_dir($tempDir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'web')) {
@del_target_dir(public_path() . 'web', true);
}
if (is_dir($tempDir . 'download' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'wap')) {
@del_target_dir(public_path() . 'wap', true);
}
$excludeFiles = ['favicon.ico', 'niucloud.ico'];
dir_copy($tempDir . 'download', root_path(), exclude_files: $excludeFiles);
$this->buildResultAnalysis('success');
$downloadInfo['status'] = 'completed';
$downloadInfo['percent'] = 100;
$downloadInfo['msg'] = '部署完成';
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 1,
'status' => 'completed',
'percent' => 100,
'downloaded_bytes' => $downloadInfo['downloaded_bytes'],
'total_bytes' => $downloadInfo['length'],
'msg' => '部署完成'
];
} else {
if (!isset($downloadInfo['retry'])) {
unlink($zipFile);
$downloadInfo['retry'] = 1;
unset($downloadInfo['index']);
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 1,
'status' => 'downloading',
'percent' => 0,
'downloaded_bytes' => 0,
'total_bytes' => $downloadInfo['length'] ?? 0,
'msg' => '编译包解压失败,尝试重新下载',
'debug' => [
'zip_file' => $zipFile,
'zip_size' => file_exists($zipFile) ? filesize($zipFile) : 'not exists',
'zip_open_result' => $zipOpenResult,
'extract_dir' => $downloadInfo['temp_dir'] . 'download' . DIRECTORY_SEPARATOR,
'temp_dir' => $downloadInfo['temp_dir']
]
];
} else {
$downloadInfo['status'] = 'error';
$downloadInfo['msg'] = '编译包解压失败';
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return [
'code' => 0,
'status' => 'error',
'percent' => $downloadInfo['percent'] ?? 0,
'msg' => '编译包解压失败'
];
}
}
}
}
} catch (\Exception $e) {
$downloadInfo['status'] = 'error';
$downloadInfo['msg'] = $e->getMessage();
Cache::set('cloud_build_' . $taskKey, $downloadInfo, 7200);
return ['code' => 0, 'msg' => $e->getMessage(), 'status' => 'error'];
}
}
} }

View File

@ -164,4 +164,18 @@ class CoreModuleService extends BaseNiucloudClient
{ {
return $this->httpGet('store/app_version/list', [ 'product_key' => self::PRODUCT, 'app_key' => $app_key ])[ 'data' ] ?? false; return $this->httpGet('store/app_version/list', [ 'product_key' => self::PRODUCT, 'app_key' => $app_key ])[ 'data' ] ?? false;
} }
/**
* 编译异常分析
* @param string $msg
* @return array|\core\util\niucloud\Response|object|ResponseInterface
* @throws GuzzleException
*/
public function buildResultAnalysis(string $msg)
{
$params = [
'msg' => $msg,
];
return $this->httpPost('build_error_analysis', $params)['data'] ?? [];
}
} }

View File

@ -323,7 +323,17 @@ class CorePayService extends BaseCoreService
public function createByTrade($site_id, $trade_type, $trade_id) public function createByTrade($site_id, $trade_type, $trade_id)
{ {
//创建新的支付单据 //创建新的支付单据
$data = array_values(array_filter(event('PayCreate', [ 'site_id' => $site_id, 'trade_type' => $trade_type, 'trade_id' => $trade_id ])))[ 0 ] ?? []; $event_result = event('PayCreate', [ 'site_id' => $site_id, 'trade_type' => $trade_type, 'trade_id' => $trade_id ]);
// PHP 8.0+ 兼容性处理:确保 event 返回值是数组
if (!is_array($event_result)) {
$event_result = [];
}
// 过滤掉 false/null 等无效值,只保留有效的数组元素
$filtered = array_values(array_filter($event_result, function($item) {
return is_array($item) && !empty($item);
}));
$data = !empty($filtered) ? $filtered[0] : [];
if (empty($data)) throw new PayException('PAY_NOT_FOUND_TRADE');//找不到可支付的交易 if (empty($data)) throw new PayException('PAY_NOT_FOUND_TRADE');//找不到可支付的交易
if (isset($data[ 'status' ]) && $data[ 'money' ] == 0) { if (isset($data[ 'status' ]) && $data[ 'money' ] == 0) {

View File

@ -64,7 +64,7 @@ class CoreWeappCloudService extends CoreCloudBaseService
*/ */
public function uploadWeapp(array $data) public function uploadWeapp(array $data)
{ {
if (strpos($this->config[ 'base_url' ], 'https://') === false) throw new CommonException('CURR_SITE_IS_NOT_OPEN_SSL'); // if (strpos($this->config[ 'base_url' ], 'https://') === false) throw new CommonException('CURR_SITE_IS_NOT_OPEN_SSL');
$this->site_id = $data[ 'site_id' ] ?? 0; $this->site_id = $data[ 'site_id' ] ?? 0;
if (empty($this->config[ 'app_id' ])) throw new CommonException('WEAPP_APPID_EMPTY'); if (empty($this->config[ 'app_id' ])) throw new CommonException('WEAPP_APPID_EMPTY');
@ -126,7 +126,8 @@ class CoreWeappCloudService extends CoreCloudBaseService
if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]);
return [ 'key' => $query[ 'timestamp' ] ]; $task_id = $response[ 'data' ][ 'task_id' ] ?? $query[ 'timestamp' ];
return [ 'key' => $task_id ];
} }
/** /**
@ -306,14 +307,13 @@ class CoreWeappCloudService extends CoreCloudBaseService
/** /**
* 获取小程序编译日志 * 获取小程序编译日志
* @param string $timestamp * @param string $taskId 任务ID (格式: authorize_code_timestamp)
* @return \Psr\Http\Message\ResponseInterface * @return \Psr\Http\Message\ResponseInterface
*/ */
public function getWeappCompileLog(string $timestamp) public function getWeappCompileLog(string $taskId)
{ {
$query = [ $query = [
'authorize_code' => $this->auth_code, 'task_id' => $taskId
'timestamp' => $timestamp
]; ];
return ( new CloudService(true) )->httpGet('cloud/get_weapp_logs?' . http_build_query($query)); return ( new CloudService(true) )->httpGet('cloud/get_weapp_logs?' . http_build_query($query));
} }

View File

@ -66,12 +66,18 @@ class CoreOplatformConfigService extends BaseCoreService
public function getStaticInfo(){ public function getStaticInfo(){
$wap_domain = (new CoreSysConfigService())->getSceneDomain(0)['wap_url'] ?? ''; $wap_domain = (new CoreSysConfigService())->getSceneDomain(0)['wap_url'] ?? '';
$local_cloud_compile_config = (new CoreConfigService())->getConfig(0, 'LOCAL_CLOUD_COMPILE_CONFIG')['value'] ?? [];
$baseUri = $local_cloud_compile_config['baseUri'] ?? '';
if (empty($baseUri)) $baseUri = 'oss.niucloud.com';
$baseUri = str_replace('http://', '', $baseUri);
$baseUri = str_replace('https://', '', $baseUri);
return [ return [
'auth_serve_url' => (string)url('/adminapi/wxoplatform/server',[],'', true), // 授权事件接收配置 'auth_serve_url' => (string)url('/adminapi/wxoplatform/server',[],'', true), // 授权事件接收配置
'message_serve_url' => (string)url('/adminapi/wxoplatform/message/$APPID$', [],'',true), // 消息与事件接收配置 'message_serve_url' => (string)url('/adminapi/wxoplatform/message/$APPID$', [],'',true), // 消息与事件接收配置
'auth_launch_domain' => parse_url(request()->domain())['host'] ?? '', // 授权发起页域名 'auth_launch_domain' => parse_url(request()->domain())['host'] ?? '', // 授权发起页域名
'wechat_auth_domain' => parse_url($wap_domain)['host'] ?? '', // 公众号开发域名 'wechat_auth_domain' => parse_url($wap_domain)['host'] ?? '', // 公众号开发域名
'upload_ip' => gethostbyname('oss.niucloud.com') 'upload_ip' => gethostbyname($baseUri)
]; ];
} }
} }

View File

@ -0,0 +1,2 @@
ALTER TABLE weapp_version
CHANGE COLUMN task_key task_key varchar(255) NOT NULL DEFAULT '' COMMENT '上传任务key';

View File

@ -1,6 +1,6 @@
<?php <?php
return [ return [
'version' => '1.2.2', 'version' => '1.2.4',
'code' => '202604010001' 'code' => '202606060001'
]; ];

View File

@ -15,40 +15,37 @@ class CloudService
{ {
use HasHttpRequests; use HasHttpRequests;
private $baseUri = 'http://oss.niucloud.com/'; private $baseUri = 'http://go.site.niucloud.com/';
public $is_connected = false; public $is_connected = false;
public function __construct($checkLocal = false, $local_cloud_compile = '') { public function __construct($checkLocal = false, $local_cloud_compile = '') {
$this->baseUri = 'http://' . gethostbyname('oss.niucloud.com') . ':8000/'; if (!empty($local_cloud_compile)) $this->baseUri = $local_cloud_compile;
if ($checkLocal) $this->is_connected = $this->checkLocal($local_cloud_compile); if ($checkLocal) $this->is_connected = $this->checkLocal($local_cloud_compile);
} }
public function checkLocal($local_cloud_compile) { public function checkLocal($local_cloud_compile = '') {
$baseUri = $this->baseUri; $baseUri = $this->baseUri;
$local_cloud_compile_config = (new CoreConfigService())->getConfig(0, 'LOCAL_CLOUD_COMPILE_CONFIG')['value'] ?? [];
if (!empty($local_cloud_compile_config) && isset($local_cloud_compile_config['isOpen']) && $local_cloud_compile_config['isOpen'] == 1){
$baseUri = $local_cloud_compile_config['baseUri'] ?? '';
if (empty($baseUri)){
throw new CommonException("已开启`第三方云编译`,但未配置云编译服务器地址,详情查看:平台端》云编译》第三方云编译");
}
}
if (!empty($local_cloud_compile)){ if (!empty($local_cloud_compile)){
$baseUri = $local_cloud_compile; $baseUri = $local_cloud_compile;
} else {
$local_cloud_compile_config = (new CoreConfigService())->getConfig(0, 'LOCAL_CLOUD_COMPILE_CONFIG')['value'] ?? [];
$isOpen = $local_cloud_compile_config['isOpen'] ?? 1;
if ($isOpen){
$baseUri = $local_cloud_compile_config['baseUri'] ?? '';
}
} }
$is_connected = false; $is_connected = false;
try { try {
$res = (new Client(['base_uri' => $baseUri ]))->request("GET", '', []); $res = (new Client(['base_uri' => $baseUri ]))->request("GET", '', []);
// dd($res->getBody()->getContents());
if ($res->getStatusCode() == '200' && $res->getBody()->getContents() == '欢迎使用NiuCloud编译服务!') { if ($res->getStatusCode() == '200' && $res->getBody()->getContents() == '欢迎使用NiuCloud编译服务!') {
$this->baseUri = $baseUri; $this->baseUri = $baseUri;
$is_connected = true; $is_connected = true;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
throw new CommonException('CONNECT_FAIL');
} }
return $is_connected; return $is_connected;
} }

View File

@ -1,4 +1,4 @@
/.htaccess /.htaccess
upload upload
nginx.htaccess nginx.htaccess
.htaccess .htaccess

View File

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

View File

@ -1 +0,0 @@
import{d as l,r as d,u as i,o as p,c as u,a as t,b as m,e as x,w as v,f,E as h,p as b,g,h as I,i as w,t as S}from"./index-42af2821.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=i();return s=setInterval(()=>{a.value===0?(clearInterval(s),n.go(-1)):a.value--},1e3),p(()=>{s&&clearInterval(s)}),(r,c)=>{const _=h;return I(),u("div",y,[t("div",C,[m(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[x(_,{class:"bottom",onClick:c[0]||(c[0]=D=>f(n).go(-1))},{default:v(()=>[w(S(a.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-4f4088b5"]]);export{z as default};

View File

@ -0,0 +1 @@
import{dY as f}from"./index-8eead49b.js";export{f as default};

View File

@ -1 +0,0 @@
import{dD as f}from"./index-42af2821.js";export{f as default};

View File

@ -0,0 +1 @@
.upload-demo[data-v-d439b536]{width:100%;border:1px dashed #dcdcdc;border-radius:6px;padding:20px;text-align:center}.copy-icon[data-v-d439b536]{cursor:pointer;margin-left:8px;color:#606266;font-size:18px}.copy-icon[data-v-d439b536]:hover{color:#409eff}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import z from"./VerifySlide-02eb59d1.js";import g from"./VerifyPoints-e2bb084a.js";import{P as k,r as o,m as w,bc as T,Y as V,Z as B,h as p,c as u,a as c,i as N,C as y,y as d,v as C,bb as P,x as v}from"./index-8eead49b.js";import{_ as j}from"./_plugin-vue_export-helper-c27b6911.js";import"./index-b4a6dc9f.js";const O={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:R,blockSize:W,barSize:Y}=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(P(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=j(O,[["render",I]]);export{J as default};

View File

@ -1 +0,0 @@
import z from"./VerifySlide-9050bdca.js";import g from"./VerifyPoints-796482d6.js";import{P as k,r as o,m as w,bb as T,Y as V,Z as B,h as p,c as u,a as c,i as N,C as y,y as d,v as C,bc as P,x as v}from"./index-42af2821.js";import{_ as j}from"./_plugin-vue_export-helper-c27b6911.js";import"./index-7b692db8.js";const O={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:R,blockSize:W,barSize:Y}=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(P(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=j(O,[["render",I]]);export{J as default};

View File

@ -1 +0,0 @@
import{r as F,a as M,b as K,c as Y}from"./index-7b692db8.js";import{P as Z,bd as G,r as s,q as m,aZ as X,h as H,c as I,a as l,y as A,Y as Q,Z as U,F as $,V as ee,t as q,ax as te}from"./index-42af2821.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:L,imgSize:R,barSize:c}=Z(N),{proxy:n}=G(),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),V=()=>{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(()=>{V(),n.$el.onselectstart=function(){return!1}});const S=s(null),D=i=>{if(a.push(k(S,i)),o.value==z.value){o.value=P(k(S,i));const t=J(a,u);a.length=0,a.push(...t),setTimeout(()=>{const g=h.value?M(v.value+"---"+JSON.stringify(a),h.value):v.value+"---"+JSON.stringify(a),r={captchaType:e.value,captcha_code:h.value?M(JSON.stringify(a),h.value):JSON.stringify(a),captcha_key:v.value};K(r).then(W=>{W.code==1?(b.value="#4cae4c",x.value="#5cb85c",d.value="验证成功",C.value=!1,_.value=="pop"&&setTimeout(()=>{n.$parent.clickShow=!1,T()},1500),n.$parent.$emit("success",{captchaVerification:g})):(n.$parent.$emit("error",n),b.value="#d9534f",x.value="#d9534f",d.value="验证失败",setTimeout(()=>{T()},700))})},400)}o.value<z.value&&(o.value=P(k(S,i)))},k=function(i,t){const g=t.offsetX,r=t.offsetY;return{x:g,y:r}},P=function(i){return y.push(Object.assign({},i)),o.value+1},T=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};Y(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 J=function(i,t){return i.map(r=>{const W=Math.round(310*r.x/parseInt(t.imgWidth)),E=Math.round(155*r.y/parseInt(t.imgHeight));return{x:W,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:V,canvas:S,canvasClick:D,getMousePos:k,createPoint:P,refresh:T,getPictrue:B,pointTransfrom:J}}},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,L,R){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"})},[Q(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"})},q(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,q(e.text),1)],4)])}const fe=ae(ie,[["render",he]]);export{fe as default};

View File

@ -0,0 +1 @@
import{r as F,a as M,b as K,c as Y}from"./index-b4a6dc9f.js";import{P as Z,bd as G,r as s,q as m,aZ as X,h as H,c as I,a as l,y as A,Y as Q,Z as U,F as $,V as ee,t as q,ax as te}from"./index-8eead49b.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:L,imgSize:R,barSize:c}=Z(N),{proxy:n}=G(),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),V=()=>{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(()=>{V(),n.$el.onselectstart=function(){return!1}});const S=s(null),D=i=>{if(a.push(k(S,i)),o.value==z.value){o.value=P(k(S,i));const t=J(a,u);a.length=0,a.push(...t),setTimeout(()=>{const g=h.value?M(v.value+"---"+JSON.stringify(a),h.value):v.value+"---"+JSON.stringify(a),r={captchaType:e.value,captcha_code:h.value?M(JSON.stringify(a),h.value):JSON.stringify(a),captcha_key:v.value};K(r).then(W=>{W.code==1?(b.value="#4cae4c",x.value="#5cb85c",d.value="验证成功",C.value=!1,_.value=="pop"&&setTimeout(()=>{n.$parent.clickShow=!1,T()},1500),n.$parent.$emit("success",{captchaVerification:g})):(n.$parent.$emit("error",n),b.value="#d9534f",x.value="#d9534f",d.value="验证失败",setTimeout(()=>{T()},700))})},400)}o.value<z.value&&(o.value=P(k(S,i)))},k=function(i,t){const g=t.offsetX,r=t.offsetY;return{x:g,y:r}},P=function(i){return y.push(Object.assign({},i)),o.value+1},T=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};Y(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 J=function(i,t){return i.map(r=>{const W=Math.round(310*r.x/parseInt(t.imgWidth)),E=Math.round(155*r.y/parseInt(t.imgHeight));return{x:W,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:V,canvas:S,canvasClick:D,getMousePos:k,createPoint:P,refresh:T,getPictrue:B,pointTransfrom:J}}},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,L,R){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"})},[Q(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"})},q(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,q(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

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{d as V,k as B,u 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,f as e,s as a,i as h,B as I,aH as R,aI as $,E as q,a_ as D,a$ as F,b0 as H,K,b1 as M,a8 as P}from"./index-42af2821.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as Q}from"./aliapp-f3406b1b.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=R,C=$,m=q,i=D,E=F,u=H,y=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(C,{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(E,{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(y,{class:"w-[180px] h-[180px]",src:p.value?e(I)(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};

View File

@ -1 +0,0 @@
import{d as B,k as T,u as $,r as c,aZ as I,b6 as M,o as R,h as W,c as q,e,w as t,a as s,t as o,f as n,s as a,i as u,aH as A,aI as L,E as U,a_ as j,a$ as D,b0 as F,b1 as G,a8 as H}from"./index-42af2821.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as P}from"./wechat-6fe57299.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]"},st={class:"mt-[20px] mb-[40px] h-[32px]"},dt=B({__name:"access",setup(at){const f=T(),_=$(),x=f.meta.title,r=c("/channel/app"),b=c(""),g=c({}),w=c({}),h=async()=>{await P().then(({data:l})=>{g.value=l,b.value=l.qr_code})};I(async()=>{await h(),await M().then(({data:l})=>{w.value=l}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&h()})}),R(()=>{document.removeEventListener("visibilitychange",()=>{})});const y=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 W(),q("div",Z,[e(N,{class:"card !border-none",shadow:"never"},{default:t(()=>[s("div",z,[s("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(a)("accessFlow"),name:"/channel/app"},null,8,["label"]),e(v,{label:n(a)("versionManage"),name:"/channel/app/version"},null,8,["label"])]),_:1},8,["modelValue"]),s("div",K,[s("h3",O,o(n(a)("appInlet")),1),e(S,null,{default:t(()=>[e(V,{span:20},{default:t(()=>[e(k,{class:"!mt-[10px]",active:3,direction:"vertical"},{default:t(()=>[e(m,null,{title:t(()=>[s("p",Q,o(n(a)("uniappApp")),1)]),description:t(()=>[s("span",X,o(n(a)("appAttestation1")),1),s("div",Y,[e(d,{type:"primary",onClick:i[1]||(i[1]=p=>y("https://dcloud.io/"))},{default:t(()=>[u(o(n(a)("toCreate")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",tt,o(n(a)("appSetting")),1)]),description:t(()=>[s("div",et,[e(d,{type:"primary",onClick:i[2]||(i[2]=p=>n(_).push("/channel/app/config"))},{default:t(()=>[u(o(n(a)("settingInfo")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",nt,o(n(a)("versionManage")),1)]),description:t(()=>[s("div",st,[e(d,{type:"primary",plain:"",onClick:i[3]||(i[3]=p=>n(_).push("/channel/app/version"))},{default:t(()=>[u(o(n(a)("releaseVersion")),1)]),_:1})])]),_:1})]),_:1})]),_:1})]),_:1})])]),_:1})])}}});export{dt as default};

View File

@ -0,0 +1 @@
import{d as $,k as q,u as j,r as u,aZ as F,b6 as I,o as R,h as w,c as y,e as a,w as s,a as n,t as o,f as e,s as t,i as r,F as U,v 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,a8 as J}from"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as O}from"./wechat-cb4e6ea9.js";import{a as X}from"./wxoplatform-105b4bfa.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=$({__name:"access",setup(ve){const k=q(),_=j(),C=k.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,N=Q,T=Z,W=J;return w(),y("div",Y,[a(W,{class:"card !border-none",shadow:"never"},{default:s(()=>[n("div",ee,[n("span",te,o(e(C)),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(T,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(N,{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};

View File

@ -0,0 +1 @@
import{d as V,k as B,u 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,f as e,s as a,i as h,B as I,aH as R,aI as $,E as q,a_ as D,a$ as F,b0 as H,K,b1 as M,a8 as P}from"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as Q}from"./aliapp-72a6151f.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=R,C=$,m=q,i=D,E=F,u=H,y=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(C,{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(E,{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(y,{class:"w-[180px] h-[180px]",src:p.value?e(I)(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};

View File

@ -1 +0,0 @@
import{d as $,k as q,u as j,r as u,aZ as F,b6 as I,o as R,h as w,c as y,e as a,w as s,a as n,t as o,f as e,s as t,i as r,F as U,v 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,a8 as J}from"./index-42af2821.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as O}from"./wechat-6fe57299.js";import{a as X}from"./wxoplatform-2136ae22.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=$({__name:"access",setup(ve){const k=q(),_=j(),C=k.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,N=Q,T=Z,W=J;return w(),y("div",Y,[a(W,{class:"card !border-none",shadow:"never"},{default:s(()=>[n("div",ee,[n("span",te,o(e(C)),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(T,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(N,{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};

View File

@ -0,0 +1 @@
import{d as B,k as T,u as $,r as c,aZ as I,b6 as M,o as R,h as W,c as q,e,w as t,a as s,t as o,f as n,s as a,i as u,aH as A,aI as L,E as U,a_ as j,a$ as D,b0 as F,b1 as G,a8 as H}from"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{g as P}from"./wechat-cb4e6ea9.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]"},st={class:"mt-[20px] mb-[40px] h-[32px]"},dt=B({__name:"access",setup(at){const f=T(),_=$(),x=f.meta.title,r=c("/channel/app"),b=c(""),g=c({}),w=c({}),h=async()=>{await P().then(({data:l})=>{g.value=l,b.value=l.qr_code})};I(async()=>{await h(),await M().then(({data:l})=>{w.value=l}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&h()})}),R(()=>{document.removeEventListener("visibilitychange",()=>{})});const y=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 W(),q("div",Z,[e(N,{class:"card !border-none",shadow:"never"},{default:t(()=>[s("div",z,[s("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(a)("accessFlow"),name:"/channel/app"},null,8,["label"]),e(v,{label:n(a)("versionManage"),name:"/channel/app/version"},null,8,["label"])]),_:1},8,["modelValue"]),s("div",K,[s("h3",O,o(n(a)("appInlet")),1),e(S,null,{default:t(()=>[e(V,{span:20},{default:t(()=>[e(k,{class:"!mt-[10px]",active:3,direction:"vertical"},{default:t(()=>[e(m,null,{title:t(()=>[s("p",Q,o(n(a)("uniappApp")),1)]),description:t(()=>[s("span",X,o(n(a)("appAttestation1")),1),s("div",Y,[e(d,{type:"primary",onClick:i[1]||(i[1]=p=>y("https://dcloud.io/"))},{default:t(()=>[u(o(n(a)("toCreate")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",tt,o(n(a)("appSetting")),1)]),description:t(()=>[s("div",et,[e(d,{type:"primary",onClick:i[2]||(i[2]=p=>n(_).push("/channel/app/config"))},{default:t(()=>[u(o(n(a)("settingInfo")),1)]),_:1})])]),_:1}),e(m,null,{title:t(()=>[s("p",nt,o(n(a)("versionManage")),1)]),description:t(()=>[s("div",st,[e(d,{type:"primary",plain:"",onClick:i[3]||(i[3]=p=>n(_).push("/channel/app/version"))},{default:t(()=>[u(o(n(a)("releaseVersion")),1)]),_:1})])]),_:1})]),_:1})]),_:1})]),_:1})])]),_:1})])}}});export{dt as default};

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{b5 as t}from"./index-8eead49b.js";function r(e){return t.get("relay/pages",{params:e})}function o(){return t.get("relay/init")}function n(e){return t.get("diy/list",{params:e})}function u(e){return t.post("relay/batch_set",e,{showSuccessMessage:!0})}function l(e){return t.post("relay/add",e,{showSuccessMessage:!0})}function c(e){return t.put(`relay/edit/${e.id}`,e,{showSuccessMessage:!0})}function y(e){return t.get(`relay/detail/${e}`)}function i(){return t.get("relay/share")}function g(e){return t.put(`relay/close/${e}`,{showSuccessMessage:!0})}function d(e){return t.delete(`relay/delete/${e}`,{showSuccessMessage:!0})}function f(){return t.get("relay/goods_of_select_source")}function R(e,a){return t.get(`relay/goods_of_select/${e}`,{params:a})}function h(e){return t.get("relay/stat/total",{params:e})}function S(e){return t.get("relay/stat/day",{params:e})}function p(e){return t.get("relay/stat/hour",{params:e})}function w(e){return t.get("relay/stat/channel",{params:e})}function M(e){return t.get("relay/diy/goods",{params:e})}function _(e){return t.get("relay/receive_list",{params:e})}function m(e){return t.post("relay/code/import",e,{showSuccessMessage:!0})}function C(e){return t.post("relay/code/delete",e,{showSuccessMessage:!0})}function $(e){return t.post("relay/code/clear",e,{showSuccessMessage:!0})}export{y as a,_ as b,$ as c,m as d,u as e,n as f,M as g,f as h,R as i,i as j,o as k,c as l,l as m,r as n,d as o,g as p,S as q,C as r,w as s,h as t,p as u};

View File

@ -0,0 +1 @@
import{b5 as t}from"./index-8eead49b.js";function s(e){return t.get("friend_help/pages",{params:e})}function i(){return t.get("friend_help/init")}function o(e){return t.get("diy/list",{params:e})}function d(e){return t.post("friend_help/batch_set",e,{showSuccessMessage:!0})}function u(e){return t.post("friend_help/add",e,{showSuccessMessage:!0})}function l(e){return t.put(`friend_help/edit/${e.id}`,e,{showSuccessMessage:!0})}function a(e){return t.get(`friend_help/detail/${e}`)}function c(){return t.get("friend_help/share")}function p(e){return t.put(`friend_help/close/${e}`,{showSuccessMessage:!0})}function f(e){return t.delete(`friend_help/delete/${e}`,{showSuccessMessage:!0})}function g(){return t.get("friend_help/goods_of_select_source")}function h(e,n){return t.get(`friend_help/goods_of_select/${e}`,{params:n})}function _(e){return t.get("friend_help/stat/total",{params:e})}function H(e){return t.get("friend_help/stat/day",{params:e})}function F(e){return t.get("friend_help/stat/hour",{params:e})}function S(e){return t.get("friend_help/stat/channel",{params:e})}function w(e){return t.get("friend_help/diy/goods",{params:e})}function M(e){return t.get("friend_help/receive_list",{params:e})}function m(e){return t.post("friend_help/code/import",e,{showSuccessMessage:!0})}function y(e){return t.post("friend_help/code/delete",e,{showSuccessMessage:!0})}function C(e){return t.post("friend_help/code/clear",e,{showSuccessMessage:!0})}export{a,o as b,M as c,C as d,m as e,y as f,w as g,d as h,g as i,h as j,c as k,i as l,l as m,u as n,s as o,f as p,p as q,H as r,S as s,_ as t,F as u};

View File

@ -0,0 +1 @@
import{_ as o}from"./active-detail-popup.vue_vue_type_script_setup_true_lang-6b999cc5.js";import"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* 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"./el-form-item-4ed993c7.js";/* empty css */import"./goods_default-247a7f2b.js";import"./active-a803f547.js";export{o as default};

View File

@ -0,0 +1 @@
import{_ as o}from"./active-detail-popup.vue_vue_type_script_setup_true_lang-5aee9bbd.js";import"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* 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"./el-form-item-4ed993c7.js";/* empty css */import"./goods_default-995568ac.js";import"./active-f3a52d93.js";export{o as default};

View File

@ -0,0 +1 @@
import{_ as o}from"./active-detail-popup.vue_vue_type_script_setup_true_lang-20981cd7.js";import"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* 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"./el-form-item-4ed993c7.js";/* empty css */import"./goods_default-664bb559.js";import"./active-132d6527.js";export{o as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{b5 as t}from"./index-8eead49b.js";function l(e){return t.get("seckill/lists",{params:e})}function c(e){return t.get(`seckill/info/${e}`)}function i(e){return t.post("seckill/add",e,{showSuccessMessage:!0})}function o(e){return t.post("seckill/close",e,{showSuccessMessage:!0})}function n(e){return t.put(`seckill/edit/${e.id}`,e,{showSuccessMessage:!0})}function u(e){return t.post("seckill/delete",e,{showSuccessMessage:!0})}function r(){return t.get("seckill/init")}function a(){return t.get("seckill/select")}function k(e){return t.get("seckill/stat/total",{params:e})}function g(e){return t.get("seckill/stat/day",{params:e})}function S(e){return t.get("seckill/stat/hour",{params:e})}function d(e){return t.get("seckill/stat/channel",{params:e})}function f(e){return t.get("seckill/time/select",{params:e})}function h(e){return t.get("seckill/activeGoods/select",{params:e})}function p(e){return t.get("seckill/goods/receive_list",{params:e})}function w(e){return t.post("seckill/goods/code/import",e,{showSuccessMessage:!0})}function M(e){return t.post("seckill/goods/code/delete",e,{showSuccessMessage:!0})}function m(e){return t.post("seckill/goods/code/clear",e,{showSuccessMessage:!0})}export{p as a,m as b,w as c,c as d,r as e,n as f,a as g,i as h,l as i,u as j,o as k,g as l,d as m,f as n,h as o,k as p,S as q,M as s};

View File

@ -0,0 +1 @@
import{b5 as n}from"./index-8eead49b.js";function a(t){return n.get("pintuan/pages",{params:t})}function s(){return n.get("pintuan/init")}function i(t){return n.get("diy/list",{params:t})}function o(t){return n.post("pintuan/batch_set",t,{showSuccessMessage:!0})}function r(t){return n.post("pintuan/add",t,{showSuccessMessage:!0})}function c(t){return n.put(`pintuan/edit/${t.id}`,t,{showSuccessMessage:!0})}function g(t){return n.get(`pintuan/detail/${t}`)}function p(){return n.get("pintuan/share")}function d(t){return n.put(`pintuan/close/${t}`,{showSuccessMessage:!0})}function f(t){return n.delete(`pintuan/delete/${t}`,{showSuccessMessage:!0})}function l(){return n.get("pintuan/goods_of_select_source")}function h(t,e){return n.get(`pintuan/goods_of_select/${t}`,{params:e})}function P(t){return n.get("pintuan/stat/total",{params:t})}function S(t){return n.get("pintuan/stat/day",{params:t})}function w(t){return n.get("pintuan/stat/hour",{params:t})}function M(t){return n.get("pintuan/stat/channel",{params:t})}function _(t){return n.get("pintuan/diy/goods",{params:t})}function m(t){return n.get("pintuan/receive_list",{params:t})}function y(t){return n.post("pintuan/code/import",t,{showSuccessMessage:!0})}function C(t){return n.post("pintuan/code/delete",t,{showSuccessMessage:!0})}function $(t){return n.post("pintuan/code/clear",t,{showSuccessMessage:!0})}export{g as a,i as b,m as c,$ as d,y as e,o as f,_ as g,l as h,h as i,p as j,s as k,c as l,r as m,a as n,f as o,C as p,d as q,S as r,M as s,P as t,w as u};

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 @@
const e="活动名称",t="请输入活动名称",l="活动规则说明",c="请输入活动规则说明",a="活动开始时间",s="请输入活动开始时间",o="活动结束时间",i="请输入活动结束时间",r="排序",d="请输入排序",n="活动状态",m="创建时间",k="请输入创建时间",T="更新时间",h="请输入更新时间",P="添加秒杀活动",p="编辑秒杀活动",u="确定要删除该数据吗?",D="请选择开始时间",N="请选择结束时间",R={seckillName:e,seckillNamePlaceholder:t,seckillRemark:l,seckillRemarkPlaceholder:c,startTime:a,startTimePlaceholder:s,endTime:o,endTimePlaceholder:i,sort:r,sortPlaceholder:d,status:n,createTime:m,createTimePlaceholder:k,updateTime:T,updateTimePlaceholder:h,addSeckill:P,updateSeckill:p,seckillDeleteTips:u,startDate:D,endDate:N};export{P as addSeckill,m as createTime,k as createTimePlaceholder,R as default,N as endDate,o as endTime,i as endTimePlaceholder,u as seckillDeleteTips,e as seckillName,t as seckillNamePlaceholder,l as seckillRemark,c as seckillRemarkPlaceholder,r as sort,d as sortPlaceholder,D as startDate,a as startTime,s as startTimePlaceholder,n as status,p as updateSeckill,T as updateTime,h as updateTimePlaceholder};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
input[data-v-88eb0e7f]::-webkit-outer-spin-button,input[data-v-88eb0e7f]::-webkit-inner-spin-button{-webkit-appearance:none!important;-moz-appearance:none!important;-o-appearance:none!important;appearance:none!important;margin:0}input[type=number][data-v-88eb0e7f]{-webkit-appearance:textfield;-moz-appearance:textfield;-o-appearance:textfield;appearance:textfield}.sku-form-item-wrap[data-v-88eb0e7f] .el-form-item__content{margin-left:0!important}.sku_list[data-v-88eb0e7f] .cell{overflow:initial!important}

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 @@
#AddressMap[data-v-4566f2d4]{border:1px solid #e4e4e4;border-radius:4px}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{_ as o}from"./add-address.vue_vue_type_script_setup_true_lang-aadfa2f5.js";import"./index-8eead49b.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import"./member-9b1f7f51.js";export{o as default};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.member-table[data-v-3e94f3c8] .cell{padding:0 12px!important}#TxMap[data-v-3e94f3c8]{border:1px solid #e4e4e4;border-radius:4px}.dialog-footer[data-v-3e94f3c8]{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}.input-width[data-v-3e94f3c8]{width:500px}.fixed-footer-wrap .fixed-footer[data-v-3e94f3c8]{z-index:1999!important}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.spec-wrap[data-v-f9075805]{flex:1}.spec-wrap .spec-edit-list .spec-item[data-v-f9075805]{background:#f7f7f7;padding:20px;margin-bottom:20px;position:relative;border-radius:6px}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap[data-v-f9075805]{padding:25px 30px 0;position:relative}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap ul[data-v-f9075805]{display:flex;flex-wrap:wrap;flex:1;align-items:baseline}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap ul li[data-v-f9075805]{margin:0 10px 10px 0;position:relative}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap ul li .input-width[data-v-f9075805]{width:200px}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap ul li .icon[data-v-f9075805]{width:32px;padding:0;display:none;position:absolute;top:-12px;right:-20px;cursor:pointer}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap ul li:hover .icon[data-v-f9075805]{display:block}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap .add-spec-value[data-v-f9075805]{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.spec-wrap .spec-edit-list .spec-item .spec-value-wrap .box[data-v-f9075805]{position:absolute;top:0;left:10px;width:20px;height:40px;border:1px solid #b8b9bd;border-top:none;border-right:none}.spec-wrap .spec-edit-list .spec-item .del-spec[data-v-f9075805]{border:none;position:absolute;top:10px;right:10px;display:none;cursor:pointer}.spec-wrap .spec-edit-list .spec-item:hover .del-spec[data-v-f9075805]{display:block}.el-input__suffix[data-v-f9075805]{cursor:pointer}.el-table__row[data-v-f9075805]:focus{outline:none!important}.add-spec[data-v-f9075805]{margin-bottom:16px}.batch-operation-sku[data-v-f9075805]{display:flex;margin-bottom:16px;background-color:#fff;flex-wrap:nowrap;align-items:center}.batch-operation-sku label[data-v-f9075805]{font-size:14px;margin-right:10px}.batch-operation-sku .set-spec-select[data-v-f9075805]{margin-right:10px;max-width:130px}.batch-operation-sku .set-input[data-v-f9075805]{max-width:130px;min-width:60px;margin-right:10px}.editor-width[data-v-f9075805]{width:990px}.sku-table[data-v-f9075805] :focus{outline:none}.sku-form-item-wrap[data-v-f9075805] .el-form-item__content{margin-left:0!important}.sku-table[data-v-f9075805] .el-table__cell .cell{overflow:initial!important}.fixed-footer[data-v-f9075805]{z-index:4}.edui-default .edui-editor{z-index:1!important}.el-cascader__tags.is-validate{right:30px!important}

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