From e009d53cad04c0cf6658d353caa9d61487666792 Mon Sep 17 00:00:00 2001 From: mediabot-pt <295750538+mediabot-pt@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:00:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AB=99=E7=82=B9=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=97=B6=E5=BC=B9=E5=87=BA=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E6=A1=86=EF=BC=8C=E6=94=AF=E6=8C=81=E5=AE=A1=E6=A0=B8=E8=80=85?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE=E5=90=8E=E5=86=8D=E9=80=9A?= =?UTF-8?q?=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SiteReview.vue: 「通过」打开编辑弹窗,可改名称/地址/类型/状态/备注 - AdminController: approveChange 接受 request body(编辑数据) - SiteService.approveChange: 优先用审核者编辑数据,否则用原始提交 - 拒绝保持原逻辑直接拒绝 --- .../par/api/controller/AdminController.java | 11 +++- .../com/par/core/service/SiteService.java | 5 +- .../core/service/impl/SiteServiceImpl.java | 26 +++++--- web/src/api/index.js | 2 +- web/src/views/SiteReview.vue | 65 +++++++++++++++++-- 5 files changed, 91 insertions(+), 18 deletions(-) diff --git a/par-api/src/main/java/com/par/api/controller/AdminController.java b/par-api/src/main/java/com/par/api/controller/AdminController.java index a77967b..3a7aa84 100644 --- a/par-api/src/main/java/com/par/api/controller/AdminController.java +++ b/par-api/src/main/java/com/par/api/controller/AdminController.java @@ -272,10 +272,17 @@ public class AdminController { } @PostMapping("/changes/{id}/approve") - public ApiResponse approveChange(@PathVariable Long id, HttpServletRequest request) { + public ApiResponse approveChange(@PathVariable Long id, + @RequestBody(required = false) Map body, + HttpServletRequest request) { checkAdmin(request); Long reviewerId = (Long) request.getAttribute("accountId"); - siteService.approveChange(id, reviewerId); + String name = body != null ? (String) body.get("name") : null; + String baseUrl = body != null ? (String) body.get("baseUrl") : null; + String siteType = body != null ? (String) body.get("siteType") : null; + String status = body != null ? (String) body.get("status") : null; + String notes = body != null ? (String) body.get("notes") : null; + siteService.approveChange(id, reviewerId, name, baseUrl, siteType, status, notes); log.info("Change approved: id={}, reviewer={}", id, reviewerId); return ApiResponse.success(); } diff --git a/par-core/src/main/java/com/par/core/service/SiteService.java b/par-core/src/main/java/com/par/core/service/SiteService.java index 6ce0814..3f3a9c8 100644 --- a/par-core/src/main/java/com/par/core/service/SiteService.java +++ b/par-core/src/main/java/com/par/core/service/SiteService.java @@ -52,8 +52,9 @@ public interface SiteService { /** 待审核变更列表 */ List listPendingChanges(); - /** 审核通过 → 写入 sites 表 */ - Site approveChange(Long changeId, Long reviewerId); + /** 审核通过 → 写入 sites 表(支持审核时编辑 name/baseUrl/siteType/status/notes) */ + Site approveChange(Long changeId, Long reviewerId, String name, String baseUrl, + String siteType, String status, String notes); /** 拒绝变更 */ void rejectChange(Long changeId, Long reviewerId); diff --git a/par-core/src/main/java/com/par/core/service/impl/SiteServiceImpl.java b/par-core/src/main/java/com/par/core/service/impl/SiteServiceImpl.java index cf00b88..3cb97ba 100644 --- a/par-core/src/main/java/com/par/core/service/impl/SiteServiceImpl.java +++ b/par-core/src/main/java/com/par/core/service/impl/SiteServiceImpl.java @@ -238,7 +238,8 @@ public class SiteServiceImpl implements SiteService { } @Override - public Site approveChange(Long changeId, Long reviewerId) { + public Site approveChange(Long changeId, Long reviewerId, String reviewerName, String reviewerBaseUrl, + String reviewerSiteType, String reviewerStatus, String reviewerNotes) { SiteChange entry = changeMapper.selectById(changeId); if (entry == null) throw new IllegalArgumentException("变更记录不存在"); if (!"pending".equals(entry.getStatus())) throw new IllegalArgumentException("该变更已处理"); @@ -250,11 +251,13 @@ public class SiteServiceImpl implements SiteService { throw new RuntimeException("解析变更数据失败", e); } + // 优先使用审核者编辑的数据,否则用原始提交数据 @SuppressWarnings("unchecked") - List names = (List) raw.getOrDefault("names", List.of()); - @SuppressWarnings("unchecked") - List urls = (List) raw.getOrDefault("urls", List.of()); - String notes = (String) raw.getOrDefault("notes", ""); + List names = reviewerName != null ? List.of(reviewerName) + : (List) raw.getOrDefault("names", List.of()); + List urls = reviewerBaseUrl != null ? List.of(reviewerBaseUrl) + : (List) raw.getOrDefault("urls", List.of()); + String notes = reviewerNotes != null ? reviewerNotes : (String) raw.getOrDefault("notes", ""); Site existing = siteMapper.selectBySiteId(entry.getSiteId()); Site site; @@ -262,7 +265,14 @@ public class SiteServiceImpl implements SiteService { existing.setNamesJson(toJsonArray(names)); existing.setUrlsJson(toJsonArray(urls)); if (notes != null && !notes.isBlank()) existing.setNotes(notes); - existing.setStatus(SiteStatus.ACTIVE); + if (reviewerSiteType != null) { + try { existing.setSiteType(SiteType.fromValue(reviewerSiteType)); } catch (Exception ignored) {} + } + if (reviewerStatus != null) { + try { existing.setStatus(SiteStatus.fromValue(reviewerStatus)); } catch (Exception ignored) {} + } else { + existing.setStatus(SiteStatus.ACTIVE); + } siteMapper.updateById(existing); site = existing; } else { @@ -271,9 +281,9 @@ public class SiteServiceImpl implements SiteService { site.setNamesJson(toJsonArray(names)); site.setUrlsJson(toJsonArray(urls)); site.setNotes(notes); - site.setSiteType(SiteType.UNKNOWN); + site.setSiteType(reviewerSiteType != null ? SiteType.fromValue(reviewerSiteType) : SiteType.UNKNOWN); site.setSchemaVersion("1.0.0"); - site.setStatus(SiteStatus.ACTIVE); + site.setStatus(reviewerStatus != null ? SiteStatus.fromValue(reviewerStatus) : SiteStatus.ACTIVE); site.setSubmitterId(entry.getSubmitterId()); siteMapper.insert(site); } diff --git a/web/src/api/index.js b/web/src/api/index.js index 45162c9..72ca3ae 100644 --- a/web/src/api/index.js +++ b/web/src/api/index.js @@ -37,7 +37,7 @@ export default { create: (data) => api.post('/sites', data), update: (id, data) => api.put(`/sites/${id}`, data), pendingChanges: () => api.get('/admin/sites/pending'), - approveChange: (id) => api.post(`/admin/changes/${id}/approve`), + approveChange: (id, data) => api.post(`/admin/changes/${id}/approve`, data), rejectChange: (id) => api.post(`/admin/changes/${id}/reject`), linkChange: (id, siteId) => api.post(`/admin/changes/${id}/link`, { siteId }), changesBySite: (siteId) => api.get(`/admin/sites/${siteId}/changes`), diff --git a/web/src/views/SiteReview.vue b/web/src/views/SiteReview.vue index f26adb4..09478cc 100644 --- a/web/src/views/SiteReview.vue +++ b/web/src/views/SiteReview.vue @@ -32,6 +32,31 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -48,6 +73,14 @@ import api from '../api' const submissions = ref([]) +const approveVisible = ref(false), saving = ref(false) +const approveForm = reactive({ id: null, siteId: '', name: '', baseUrl: '', siteType: '', status: 'active', notes: '' }) +const siteTypes = [ + { value: 'nexusphp', label: 'NexusPHP' }, { value: 'mtorrent', label: 'MTorrent' }, + { value: 'mteam', label: 'M-Team API' }, { value: 'pttime', label: 'PTTime' }, + { value: 'gazelle', label: 'Gazelle' }, { value: 'unit3d', label: 'UNIT3D' }, + { value: 'jsonapi', label: 'JSON API' }, { value: 'unknown', label: '未知' }, +] const matchVisible = ref(false), matchQuery = ref(''), matchResults = ref([]), matchSearching = ref(false) let matchTargetId = null @@ -56,9 +89,33 @@ const fetch = async () => { catch { ElMessage.error('获取待审核列表失败') } } -const handleApprove = async (row) => { - try { await api.sites.approveChange(row.id); ElMessage.success('已通过'); fetch() } - catch (e) { ElMessage.error(e.response?.data?.message||'操作失败') } +const handleApprove = (row) => { + approveForm.id = row.id + approveForm.siteId = row.siteId + approveForm.name = (row.names || []).join('\n') + approveForm.baseUrl = (row.urls || []).join('\n') + approveForm.siteType = row.siteType || 'unknown' + approveForm.status = row.siteStatus === '关停' ? 'deprecated' : 'active' + approveForm.notes = row.notes || '' + approveVisible.value = true +} + +const confirmApprove = async () => { + if (!approveForm.name.trim() || !approveForm.baseUrl.trim()) { ElMessage.warning('名称和地址不能为空'); return } + saving.value = true + try { + await api.sites.approveChange(approveForm.id, { + name: approveForm.name.trim().split('\n').filter(Boolean)[0] || '', + baseUrl: approveForm.baseUrl.trim().split('\n').filter(Boolean)[0] || '', + siteType: approveForm.siteType || 'unknown', + status: approveForm.status, + notes: approveForm.notes || null, + }) + ElMessage.success('已通过') + approveVisible.value = false + fetch() + } catch (e) { ElMessage.error(e.response?.data?.message||'操作失败') } + finally { saving.value = false } } const handleReject = async (row) => { @@ -69,7 +126,6 @@ const handleReject = async (row) => { } const handleMatch = (row) => { matchTargetId = row.id; matchQuery.value = (row.names||[])[0]||''; matchVisible.value = true; handleSearch() } - const handleSearch = async () => { if (!matchQuery.value.trim()) { matchResults.value = []; return } matchSearching.value = true @@ -77,7 +133,6 @@ const handleSearch = async () => { catch { matchResults.value = [] } finally { matchSearching.value = false } } - const handleLinkSite = async (row) => { try { await api.sites.linkChange(matchTargetId, row.siteId); ElMessage.success(`已关联到 ${row.siteId}`); matchVisible.value = false; fetch() } catch (e) { ElMessage.error(e.response?.data?.message||'关联失败') }