|
|
@@ -0,0 +1,278 @@
|
|
|
+<template>
|
|
|
+ <div class="store-page">
|
|
|
+ <Breadcrumb />
|
|
|
+ <a-card title="下载版本管理">
|
|
|
+ <div class="toolbar">
|
|
|
+ <a-space>
|
|
|
+ <a-select v-model="filters.client_type" allow-clear placeholder="客户端类型" style="width: 180px" @change="getList">
|
|
|
+ <a-option value="windows">Windows 客户端</a-option>
|
|
|
+ <a-option value="android">Android App</a-option>
|
|
|
+ <a-option value="ios">iOS App</a-option>
|
|
|
+ <a-option value="macos">macOS 客户端</a-option>
|
|
|
+ </a-select>
|
|
|
+ <a-button @click="getList">刷新</a-button>
|
|
|
+ </a-space>
|
|
|
+ <a-button type="primary" @click="openCreate">新增版本</a-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <a-table :bordered="false" :data="data" :loading="loading" :pagination="false" row-key="id">
|
|
|
+ <template #columns>
|
|
|
+ <a-table-column title="客户端" data-index="client_type" :width="110" />
|
|
|
+ <a-table-column title="版本" :width="150">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <div class="version-cell">
|
|
|
+ <strong>{{ record.version_name }}</strong>
|
|
|
+ <span>code {{ record.version_code || 0 }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="标题" data-index="title" :width="180" ellipsis tooltip />
|
|
|
+ <a-table-column title="下载地址" data-index="download_url" ellipsis tooltip />
|
|
|
+ <a-table-column title="SHA256" data-index="sha256" :width="160" ellipsis tooltip />
|
|
|
+ <a-table-column title="策略" :width="150">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-space wrap>
|
|
|
+ <a-tag :color="record.force_update ? 'red' : 'gray'">{{ record.force_update ? '强制' : '可选' }}</a-tag>
|
|
|
+ <a-tag :color="record.silent_update ? 'blue' : 'gray'">{{ record.silent_update ? '静默' : '提示' }}</a-tag>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="状态" :width="90">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-tag :color="record.is_active ? 'green' : 'gray'">{{ record.is_active ? '发布' : '停用' }}</a-tag>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="操作" :width="160" fixed="right">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-space>
|
|
|
+ <a-button size="mini" @click="openEdit(record)">编辑</a-button>
|
|
|
+ <a-button status="danger" size="mini" @click="remove(record)">删除</a-button>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </a-card>
|
|
|
+
|
|
|
+ <a-modal v-model:visible="editorVisible" :title="form.id ? '编辑版本' : '新增版本'" width="760px" @before-ok="submitEditor">
|
|
|
+ <a-form :model="form" layout="vertical">
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="客户端类型" required>
|
|
|
+ <a-select v-model="form.client_type" placeholder="选择客户端类型">
|
|
|
+ <a-option value="windows">Windows 客户端</a-option>
|
|
|
+ <a-option value="android">Android App</a-option>
|
|
|
+ <a-option value="ios">iOS App</a-option>
|
|
|
+ <a-option value="macos">macOS 客户端</a-option>
|
|
|
+ </a-select>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="标题">
|
|
|
+ <a-input v-model="form.title" allow-clear placeholder="例如:Windows 客户端 1.0.1" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="版本名称" required>
|
|
|
+ <a-input v-model="form.version_name" allow-clear placeholder="1.0.1" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="版本码">
|
|
|
+ <a-input-number v-model="form.version_code" mode="button" :min="0" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+
|
|
|
+ <a-form-item label="下载地址" required>
|
|
|
+ <a-input v-model="form.download_url" allow-clear />
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="SHA256">
|
|
|
+ <a-input v-model="form.sha256" allow-clear placeholder="建议填写,用于客户端校验安装包完整性" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="文件大小(字节)">
|
|
|
+ <a-input-number v-model="form.file_size" mode="button" :min="0" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :span="8">
|
|
|
+ <a-form-item label="整包/热更新">
|
|
|
+ <a-select v-model="form.package_type">
|
|
|
+ <a-option :value="0">整包</a-option>
|
|
|
+ <a-option :value="1">热更新</a-option>
|
|
|
+ </a-select>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="8">
|
|
|
+ <a-form-item label="排序">
|
|
|
+ <a-input-number v-model="form.sort_order" mode="button" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="8">
|
|
|
+ <a-form-item label="最低支持版本">
|
|
|
+ <a-input v-model="form.min_supported_version" allow-clear placeholder="可选" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+
|
|
|
+ <a-space class="switch-row">
|
|
|
+ <span>发布</span>
|
|
|
+ <a-switch v-model="form.is_active" :checked-value="1" :unchecked-value="0" />
|
|
|
+ <span>强制更新</span>
|
|
|
+ <a-switch v-model="form.force_update" :checked-value="1" :unchecked-value="0" />
|
|
|
+ <span>静默下载</span>
|
|
|
+ <a-switch v-model="form.silent_update" :checked-value="1" :unchecked-value="0" />
|
|
|
+ </a-space>
|
|
|
+
|
|
|
+ <a-form-item label="更新日志">
|
|
|
+ <a-textarea v-model="form.release_notes" :auto-size="{ minRows: 3 }" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="更新日志 HTML">
|
|
|
+ <a-textarea v-model="form.release_notes_html" :auto-size="{ minRows: 3 }" placeholder="可选,兼容 uni-app 更新弹窗" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-modal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { reactive, ref, onMounted } from 'vue'
|
|
|
+import { Modal, Notification, Message } from '@arco-design/web-vue'
|
|
|
+import {
|
|
|
+ getAdminDownloadVersionList,
|
|
|
+ saveAdminDownloadVersion,
|
|
|
+ deleteAdminDownloadVersion
|
|
|
+} from '@/api/download'
|
|
|
+
|
|
|
+const loading = ref(false)
|
|
|
+const data = ref([])
|
|
|
+const editorVisible = ref(false)
|
|
|
+const filters = reactive({ client_type: '' })
|
|
|
+
|
|
|
+const defaultForm = () => ({
|
|
|
+ id: null,
|
|
|
+ client_type: 'windows',
|
|
|
+ version_name: '',
|
|
|
+ version_code: 0,
|
|
|
+ title: '',
|
|
|
+ download_url: '',
|
|
|
+ sha256: '',
|
|
|
+ file_size: 0,
|
|
|
+ package_type: 0,
|
|
|
+ force_update: 0,
|
|
|
+ silent_update: 0,
|
|
|
+ is_active: 1,
|
|
|
+ release_notes: '',
|
|
|
+ release_notes_html: '',
|
|
|
+ min_supported_version: '',
|
|
|
+ sort_order: 0
|
|
|
+})
|
|
|
+
|
|
|
+const form = reactive(defaultForm())
|
|
|
+
|
|
|
+const resetForm = (values = {}) => {
|
|
|
+ Object.assign(form, defaultForm(), values)
|
|
|
+}
|
|
|
+
|
|
|
+const getList = async () => {
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const res = await getAdminDownloadVersionList({
|
|
|
+ client_type: filters.client_type || ''
|
|
|
+ })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ Notification.error({ title: '获取列表失败', content: res?.msg ?? '请稍后再试' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ data.value = res.data || []
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const openCreate = () => {
|
|
|
+ resetForm({ client_type: filters.client_type || 'windows' })
|
|
|
+ editorVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const openEdit = (record) => {
|
|
|
+ resetForm({
|
|
|
+ ...record,
|
|
|
+ version_code: Number(record.version_code) || 0,
|
|
|
+ file_size: Number(record.file_size) || 0,
|
|
|
+ package_type: Number(record.package_type) || 0,
|
|
|
+ force_update: Number(record.force_update) || 0,
|
|
|
+ silent_update: Number(record.silent_update) || 0,
|
|
|
+ is_active: Number(record.is_active) === 0 ? 0 : 1,
|
|
|
+ sort_order: Number(record.sort_order) || 0
|
|
|
+ })
|
|
|
+ editorVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const submitEditor = async () => {
|
|
|
+ if (!form.client_type || !form.version_name || !form.download_url) {
|
|
|
+ Message.error('请填写客户端类型、版本名称和下载地址')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ const res = await saveAdminDownloadVersion({ ...form })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ Notification.error({ title: '保存失败', content: res?.msg ?? '请稍后再试' })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ Message.success('保存成功')
|
|
|
+ getList()
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+const remove = (record) => {
|
|
|
+ Modal.confirm({
|
|
|
+ title: '删除下载版本',
|
|
|
+ content: `确定删除 ${record.client_type} ${record.version_name} 吗?`,
|
|
|
+ onOk: async () => {
|
|
|
+ const res = await deleteAdminDownloadVersion({ id: record.id })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ Notification.error({ title: '删除失败', content: res?.msg ?? '请稍后再试' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ Message.success('删除成功')
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(getList)
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.toolbar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 16px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.version-cell {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 2px;
|
|
|
+}
|
|
|
+
|
|
|
+.version-cell span {
|
|
|
+ color: var(--color-text-3);
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.switch-row {
|
|
|
+ margin: 4px 0 18px;
|
|
|
+}
|
|
|
+</style>
|