From a1f04f94ec5d12c4e3d547810ed966680c81c6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Wed, 8 Apr 2026 20:33:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=BD=AF=E4=BB=B6=E5=8D=87?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + package.json | 1 + scripts/clean-dist.mjs | 49 ++ src/api/complaint.js | 78 +++ src/api/file.js | 14 +- src/api/login.js | 17 + src/api/softwareUpgrade.js | 39 ++ src/utils/request.js | 11 +- .../platform/complaint/components/edit.vue | 216 ++++++++ src/views/platform/complaint/index.vue | 492 ++++++++++++++++++ src/views/platform/index.vue | 11 + .../softwareupgrade/components/edit.vue | 463 ++++++++++++++++ src/views/platform/softwareupgrade/index.vue | 260 +++++++++ vite.config.js | 13 +- 14 files changed, 1658 insertions(+), 11 deletions(-) create mode 100644 scripts/clean-dist.mjs create mode 100644 src/api/complaint.js create mode 100644 src/api/softwareUpgrade.js create mode 100644 src/views/platform/complaint/components/edit.vue create mode 100644 src/views/platform/complaint/index.vue create mode 100644 src/views/platform/index.vue create mode 100644 src/views/platform/softwareupgrade/components/edit.vue create mode 100644 src/views/platform/softwareupgrade/index.vue diff --git a/.gitignore b/.gitignore index ec6aa96..d8ee227 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,13 @@ lerna-debug.log* node_modules dist +output dist-ssr *.local +output.zip +dist.zip +dist.7z +output.7z # Editor directories and files .vscode/* diff --git a/package.json b/package.json index b50b0fb..fd059da 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "vite --open", + "clean": "node scripts/clean-dist.mjs", "build": "vite build", "preview": "vite preview" }, diff --git a/scripts/clean-dist.mjs b/scripts/clean-dist.mjs new file mode 100644 index 0000000..6a20079 --- /dev/null +++ b/scripts/clean-dist.mjs @@ -0,0 +1,49 @@ +/** + * 构建前删除 dist,带重试。缓解 Windows 上 Vite emptyDir 的 EPERM(文件被资源管理器预览、杀毒、vite preview 等占用)。 + */ +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(__dirname, ".."); +const dirs = [path.join(root, "dist"), path.join(root, "output")]; + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +async function rmDirWithRetry(dir) { + for (let i = 0; i < 10; i++) { + if (!fs.existsSync(dir)) { + return true; + } + try { + fs.rmSync(dir, { recursive: true, force: true }); + return true; + } catch (e) { + const code = e && typeof e === "object" && "code" in e ? e.code : ""; + const retryable = code === "EPERM" || code === "EBUSY" || code === "ENOTEMPTY"; + if (!retryable || i === 9) { + console.error(`[clean-dist] 无法删除 ${path.relative(root, dir) || dir}:`, e instanceof Error ? e.message : e); + return false; + } + await sleep(350 * (i + 1)); + } + } + return false; +} + +async function main() { + let ok = true; + for (const dir of dirs) { + const r = await rmDirWithRetry(dir); + if (!r) ok = false; + } + if (!ok) { + console.error( + "请关闭占用上述目录的程序:资源管理器预览、vite preview、IDE、杀毒实时扫描等后执行 npm run clean。" + ); + process.exit(1); + } +} + +await main(); diff --git a/src/api/complaint.js b/src/api/complaint.js new file mode 100644 index 0000000..acc40ef --- /dev/null +++ b/src/api/complaint.js @@ -0,0 +1,78 @@ +import request from "@/utils/request"; + +/** 投诉建议列表 */ +export function getComplaintList(params) { + return request({ + url: "/platform/complaint/list", + method: "get", + params, + }); +} + +export function getComplaintDetail(id) { + return request({ + url: `/platform/complaint/${id}`, + method: "get", + }); +} + +export function createComplaint(data) { + return request({ + url: "/platform/complaint", + method: "post", + data, + }); +} + +export function updateComplaint(id, data) { + return request({ + url: `/platform/complaint/${id}`, + method: "post", + data, + }); +} + +export function deleteComplaint(id) { + return request({ + url: `/platform/complaint/${id}`, + method: "delete", + }); +} + +/** 产品分类(投诉建议用) */ +export function getComplaintCategoryList() { + return request({ + url: "/platform/complaintCategory/list", + method: "get", + }); +} + +export function getComplaintCategorySelect() { + return request({ + url: "/platform/complaintCategory/select", + method: "get", + }); +} + +export function createComplaintCategory(data) { + return request({ + url: "/platform/complaintCategory", + method: "post", + data, + }); +} + +export function updateComplaintCategory(id, data) { + return request({ + url: `/platform/complaintCategory/${id}`, + method: "post", + data, + }); +} + +export function deleteComplaintCategory(id) { + return request({ + url: `/platform/complaintCategory/${id}`, + method: "delete", + }); +} diff --git a/src/api/file.js b/src/api/file.js index 3999826..81bf45d 100644 --- a/src/api/file.js +++ b/src/api/file.js @@ -104,6 +104,7 @@ export function getFileById(id) { * @param {Object} options 额外选项 * @param {string|number} [options.cate] 文件分组,0 为未分类 * @param {string|number} [options.tuid] 租户用户 yz_tenant_user.id;租户侧上传时传,平台管理员不传 + * @param {(e: { loaded: number; total?: number }) => void} [options.onUploadProgress] 上传进度(浏览器 XHR) * @returns {Promise} */ export function uploadFile(formData, options = {}) { @@ -115,14 +116,17 @@ export function uploadFile(formData, options = {}) { formData.append("tuid", String(options.tuid)); } - return request({ + const config = { url: "/platform/uploadfile", method: "post", data: formData, - headers: { - "Content-Type": "multipart/form-data" - } - }); + // 大安装包 / 极弱网:2 小时;勿设置 Content-Type(由浏览器自动带 boundary) + timeout: 2 * 60 * 60 * 1000, + }; + if (typeof options.onUploadProgress === "function") { + config.onUploadProgress = options.onUploadProgress; + } + return request(config); } /** diff --git a/src/api/login.js b/src/api/login.js index ae1d672..ae2471c 100644 --- a/src/api/login.js +++ b/src/api/login.js @@ -104,4 +104,21 @@ export function sendResetCode(data) { method: "post", data, }); +} + +// 租户端自助注册(/backend/*,与 go-platform routers/backend 一致) +export function register(data) { + return request({ + url: "/backend/register", + method: "post", + data, + }); +} + +export function sendRegisterCode(data) { + return request({ + url: "/backend/sendRegisterCode", + method: "post", + data, + }); } \ No newline at end of file diff --git a/src/api/softwareUpgrade.js b/src/api/softwareUpgrade.js new file mode 100644 index 0000000..c3a4f24 --- /dev/null +++ b/src/api/softwareUpgrade.js @@ -0,0 +1,39 @@ +import request from "@/utils/request"; + +export function getSoftwareUpgradeList(params) { + return request({ + url: "/platform/softwareupgrade/list", + method: "get", + params, + }); +} + +export function getSoftwareUpgradeDetail(id) { + return request({ + url: `/platform/softwareupgrade/${id}`, + method: "get", + }); +} + +export function createSoftwareUpgrade(data) { + return request({ + url: "/platform/softwareupgrade", + method: "post", + data, + }); +} + +export function updateSoftwareUpgrade(id, data) { + return request({ + url: `/platform/softwareupgrade/${id}`, + method: "post", + data, + }); +} + +export function deleteSoftwareUpgrade(id) { + return request({ + url: `/platform/softwareupgrade/${id}`, + method: "delete", + }); +} diff --git a/src/utils/request.js b/src/utils/request.js index 1fa43af..f84d0a8 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -3,10 +3,10 @@ import axios from 'axios'; // 获取API基础URL;开发环境可在 .env.development 留空,配合 Vite 代理访问 /platform const apiBaseURL = import.meta.env.VITE_API_BASE_URL ?? ""; -// 创建axios实例 +// 创建axios实例(普通接口 5min;大文件上传在 api/file.js 单独更长 timeout) const service = axios.create({ baseURL: apiBaseURL, - timeout: 10000, + timeout: 300000, withCredentials: false // JWT 不需要 Cookie }); @@ -18,9 +18,12 @@ service.interceptors.request.use( config.headers['Authorization'] = `Bearer ${token}`; } - // 对于有 body 的请求(POST、PUT、PATCH),确保设置 Content-Type + // 对于有 body 的请求(POST、PUT、PATCH),默认 JSON;FormData 由浏览器带 multipart boundary,不可手写 Content-Type if (config.data && ['post', 'put', 'patch'].includes(config.method?.toLowerCase())) { - if (!config.headers['Content-Type'] && !config.headers['content-type']) { + if (config.data instanceof FormData) { + delete config.headers['Content-Type']; + delete config.headers['content-type']; + } else if (!config.headers['Content-Type'] && !config.headers['content-type']) { config.headers['Content-Type'] = 'application/json'; } } diff --git a/src/views/platform/complaint/components/edit.vue b/src/views/platform/complaint/components/edit.vue new file mode 100644 index 0000000..d09ab81 --- /dev/null +++ b/src/views/platform/complaint/components/edit.vue @@ -0,0 +1,216 @@ + + + diff --git a/src/views/platform/complaint/index.vue b/src/views/platform/complaint/index.vue new file mode 100644 index 0000000..1a91d34 --- /dev/null +++ b/src/views/platform/complaint/index.vue @@ -0,0 +1,492 @@ + + + + + diff --git a/src/views/platform/index.vue b/src/views/platform/index.vue new file mode 100644 index 0000000..2fa6465 --- /dev/null +++ b/src/views/platform/index.vue @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/src/views/platform/softwareupgrade/components/edit.vue b/src/views/platform/softwareupgrade/components/edit.vue new file mode 100644 index 0000000..ab930ca --- /dev/null +++ b/src/views/platform/softwareupgrade/components/edit.vue @@ -0,0 +1,463 @@ + + + + + diff --git a/src/views/platform/softwareupgrade/index.vue b/src/views/platform/softwareupgrade/index.vue new file mode 100644 index 0000000..817fbeb --- /dev/null +++ b/src/views/platform/softwareupgrade/index.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/vite.config.js b/vite.config.js index ea2fe52..1da0bff 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,11 @@ import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; // https://vite.dev/config/ export default defineConfig({ + // Windows 下若 dist 被占用,清空或覆盖会 EPERM;产物默认写到 output/(与 dist 分离)。部署时请同步指向 output。 + build: { + outDir: "output", + emptyOutDir: true, + }, plugins: [ vue(), AutoImport({ @@ -23,10 +28,14 @@ export default defineConfig({ }, server: { port: 5000, - // 开发时前端在 5000,接口走相对路径 /platform/*,由这里转发到 Go(go/conf/app.conf 默认 httpport=8080) + // 开发时前端在 5000,接口走相对路径 /platform/*、/backend/*,转发到本地 Go(当前 httpport=8081) proxy: { "/platform": { - target: "http://127.0.0.1:8080", + target: "http://127.0.0.1:8081", + changeOrigin: true, + }, + "/backend": { + target: "http://127.0.0.1:8081", changeOrigin: true, }, },