diff --git a/docs/05-business-flows.md b/docs/05-business-flows.md index 94715a1b..f809c531 100644 --- a/docs/05-business-flows.md +++ b/docs/05-business-flows.md @@ -183,6 +183,7 @@ Web 端与 CLI 保持同一发布语义,只是在交互上可提供更明确 - 全局空间的新 skill 由其 owner 独立管理版本 - 原团队 skill 可继续独立迭代 - 两者版本不自动同步。来源 owner 或 namespace 管理员可在团队详情选择已发布版本,再次提交平台提升审核;审核通过后在原全局 skill 上新增版本,不覆盖原有版本 +- 再次提升通过后,全局 skill 的展示名和摘要也更新为审核时来源 skill 的展示信息,使详情页与最新发布内容保持一致 - 申请和审批时均检查目标身份、来源版本状态及全局同号冲突。全局独立上传可以同时待审;不同号版本分别发布,后通过者成为 latest,同号后通过的申请失败 - 版本号不比较数值高低;例如全局当前 v1.3、团队提交尚未占用的 v1.1,确认提示后仍可提交,审批通过后 v1.1 成为 latest,v1.3 保留在历史 diff --git a/openspec/changes/support-promotion-updates-and-revocation/specs/promotion-update/spec.md b/openspec/changes/support-promotion-updates-and-revocation/specs/promotion-update/spec.md index de4f6a2c..32c026d6 100644 --- a/openspec/changes/support-promotion-updates-and-revocation/specs/promotion-update/spec.md +++ b/openspec/changes/support-promotion-updates-and-revocation/specs/promotion-update/spec.md @@ -10,6 +10,7 @@ An authorized source owner or source namespace administrator SHALL be able to su - **WHEN** an authorized user submits the version and a platform reviewer approves it - **THEN** the same global Skill ID gets a new published version with the team's version string and source-version provenance - **AND** the previous global versions remain unchanged +- **AND** the global skill's display name and summary reflect the source skill at approval time #### Scenario: Team version is not published diff --git a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/PromotionService.java b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/PromotionService.java index 7f204e24..b34bdfd2 100644 --- a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/PromotionService.java +++ b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/PromotionService.java @@ -202,6 +202,8 @@ public class PromotionService { // Serialize approval with ordinary uploads that lock target Skill before publishing. entityManager.lock(targetSkill, jakarta.persistence.LockModeType.PESSIMISTIC_WRITE); assertTargetVersionAvailable(targetSkill.getId(), sourceVersion.getVersion()); + targetSkill.setDisplayName(sourceSkill.getDisplayName()); + targetSkill.setSummary(sourceSkill.getSummary()); } else { if (promotionRequestRepository.findActiveInitialBySourceSkillId(sourceSkill.getId()).isPresent()) { throw new DomainBadRequestException("promotion.already_promoted", sourceSkill.getId()); diff --git a/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/review/PromotionServiceTest.java b/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/review/PromotionServiceTest.java index 4ecb5767..d96bda2b 100644 --- a/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/review/PromotionServiceTest.java +++ b/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/review/PromotionServiceTest.java @@ -732,6 +732,8 @@ class PromotionServiceTest { approved.setRequestKind(PromotionRequestKind.UPDATE); approved.setTargetSkillId(NEW_SKILL_ID); Skill target = linkedTarget(); + target.setDisplayName("Independently updated global name"); + target.setSummary("Independently updated global summary"); // The global skill may have advanced independently. Publication order, not // numeric version order, determines the latest version after approval. target.setLatestVersionId(999L); @@ -760,6 +762,8 @@ class PromotionServiceTest { assertEquals(NEW_SKILL_ID, result.getTargetSkillId()); assertEquals(NEW_VERSION_ID, result.getTargetVersionId()); assertEquals(NEW_VERSION_ID, target.getLatestVersionId()); + assertEquals("My Skill", target.getDisplayName()); + assertEquals("A test skill", target.getSummary()); verify(promotionRequestRepository).updateStatusWithVersion( PROMOTION_ID, ReviewTaskStatus.APPROVED, REVIEWER_ID, "approved", NEW_SKILL_ID, pending.getVersion()); diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index c3c6b141..05e2afed 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -576,24 +576,6 @@ "promotionDuplicateDescription": "This version already has a pending promotion request.", "promotionAlreadyPromotedTitle": "Skill already promoted", "promotionAlreadyPromotedDescription": "This skill has already been promoted to the global namespace.", - "promotionVersionConflictTitle": "Global version already exists", - "promotionVersionConflictDescription": "The global skill already has this version number. Choose another published team version.", - "revocationDescription": "Revocation deletes the entire linked global skill, including independently uploaded versions. The team skill remains.", - "requestRevocation": "Request global revocation", - "directRevocation": "Revoke directly as admin", - "revocationConfirmTitle": "Confirm global revocation", - "revocationConfirmDescription": "This deletes @global/{{slug}} for “{{skill}}”, including all global versions, ratings, and statistics. The team skill remains. Installed local files cannot be recalled, and another skill may later use this address.", - "revocationReasonLabel": "Reason for revocation", - "revocationReasonPlaceholder": "Reason (optional)", - "revocationPending": "A revocation request is awaiting platform review.", - "revocationRequestSuccess": "Revocation request submitted", - "revocationDirectSuccess": "Global skill revoked", - "revocationError": "Revocation failed", - "revocationHistoryTitle": "Revocation history", - "revocationHistoryItem": "{{date}} · {{status}}", - "revocationHistoryLoading": "Loading revocation history…", - "revocationHistoryError": "Could not load revocation history. Please try again.", - "revocationStatus": { "PENDING": "Pending", "APPROVED": "Revoked", "REJECTED": "Rejected" }, "promotionErrorTitle": "Failed to submit promotion request", "emptyTitle": "No skills yet", "emptyDescription": "Start publishing your first skill", @@ -723,23 +705,6 @@ "typeSkill": "Skill Reviews", "typeProfile": "Profile Reviews", "tabPending": "Pending", - "tabRevocations": "Revocations to review", - "tabRevocationHistory": "Revocation history", - "revocationEmpty": "No revocation requests", - "revocationHistoryEmpty": "No reviewed revocation requests", - "revocationStatus": { "PENDING": "Pending", "APPROVED": "Revoked", "REJECTED": "Rejected" }, - "revocationActors": "Requested by {{submitter}} · Reviewed by {{reviewer}}", - "revocationReviewComment": "Review comment: {{comment}}", - "revocationLoadError": "Could not load revocation requests. Please try again.", - "revocationIds": "Source skill #{{source}} · Global skill #{{target}}", - "revocationReason": "Reason: {{reason}}", - "approveRevocation": "Approve revocation", - "rejectRevocation": "Reject revocation", - "revocationConfirmTitle": "Confirm revocation approval", - "revocationConfirmDescription": "Approval deletes every global version, rating, and statistic for @global/{{slug}}. The address may be reused. The team skill remains, and installed files cannot be recalled.", - "revocationApproved": "Revocation approved", - "revocationRejected": "Revocation request rejected", - "revocationActionError": "Could not process revocation request", "tabApproved": "Approved", "tabRejected": "Rejected", "empty": "No review tasks", @@ -810,6 +775,23 @@ "updateReviewHint": "Approval adds a version to the existing global skill. Check the source and current global versions.", "subtitle": "Review team skill promotion requests to global namespace", "tabPending": "Pending", + "tabRevocations": "Revocations to review", + "tabRevocationHistory": "Revocation history", + "revocationEmpty": "No revocation requests", + "revocationHistoryEmpty": "No reviewed revocation requests", + "revocationStatus": { "PENDING": "Pending", "APPROVED": "Revoked", "REJECTED": "Rejected" }, + "revocationActors": "Requested by {{submitter}} · Reviewed by {{reviewer}}", + "revocationReviewComment": "Review comment: {{comment}}", + "revocationLoadError": "Could not load revocation requests. Please try again.", + "revocationIds": "Source skill #{{source}} · Global skill #{{target}}", + "revocationReason": "Reason: {{reason}}", + "approveRevocation": "Approve revocation", + "rejectRevocation": "Reject revocation", + "revocationConfirmTitle": "Confirm revocation approval", + "revocationConfirmDescription": "Approval deletes every global version, rating, and statistic for @global/{{slug}}. The address may be reused. The team skill remains, and installed files cannot be recalled.", + "revocationApproved": "Revocation approved", + "revocationRejected": "Revocation request rejected", + "revocationActionError": "Could not process revocation request", "tabApproved": "Approved", "tabRejected": "Rejected", "commentPlaceholder": "Review comment (optional)", @@ -1269,6 +1251,24 @@ "submitGlobalUpdate": "Submit this version for global review", "globalUpdateConfirmTitle": "Confirm global skill update", "globalUpdateConfirmDescription": "Submit team v{{source}} of “{{skill}}” for global review. The current latest global version is v{{target}} and may change during review. If approved without a version conflict, this version becomes the latest published version even if its number is lower.", + "promotionVersionConflictTitle": "Global version already exists", + "promotionVersionConflictDescription": "The global skill already has this version number. Choose another published team version.", + "revocationDescription": "Revocation deletes the entire linked global skill, including independently uploaded versions. The team skill remains.", + "requestRevocation": "Request global revocation", + "directRevocation": "Revoke directly as admin", + "revocationConfirmTitle": "Confirm global revocation", + "revocationConfirmDescription": "This deletes @global/{{slug}} for “{{skill}}”, including all global versions, ratings, and statistics. The team skill remains. Installed local files cannot be recalled, and another skill may later use this address.", + "revocationReasonLabel": "Reason for revocation", + "revocationReasonPlaceholder": "Reason (optional)", + "revocationPending": "A revocation request is awaiting platform review.", + "revocationRequestSuccess": "Revocation request submitted", + "revocationDirectSuccess": "Global skill revoked", + "revocationError": "Revocation failed", + "revocationHistoryTitle": "Revocation history", + "revocationHistoryItem": "{{date}} · {{status}}", + "revocationHistoryLoading": "Loading revocation history…", + "revocationHistoryError": "Could not load revocation history. Please try again.", + "revocationStatus": { "PENDING": "Pending", "APPROVED": "Revoked", "REJECTED": "Rejected" }, "promotionConfirmTitle": "Submit promotion request", "promotionConfirmDescription": "Submit v{{version}} of \"{{skill}}\" for promotion into the global namespace?", "promotionSuccessTitle": "Promotion request submitted", diff --git a/web/src/i18n/locales/ru.json b/web/src/i18n/locales/ru.json index 975a7535..1f6a71ff 100644 --- a/web/src/i18n/locales/ru.json +++ b/web/src/i18n/locales/ru.json @@ -576,24 +576,6 @@ "promotionDuplicateDescription": "У этой версии уже есть ожидающий запрос на продвижение.", "promotionAlreadyPromotedTitle": "Скилл уже продвинут", "promotionAlreadyPromotedDescription": "Этот скилл уже продвинут в глобальное пространство имён.", - "promotionVersionConflictTitle": "Глобальная версия уже существует", - "promotionVersionConflictDescription": "У глобального скилла уже есть версия с таким номером. Выберите другую опубликованную командную версию.", - "revocationDescription": "Отзыв удалит весь связанный глобальный скилл, включая независимо загруженные версии. Командный скилл останется.", - "requestRevocation": "Запросить отзыв глобальной публикации", - "directRevocation": "Отозвать напрямую как администратор", - "revocationConfirmTitle": "Подтвердите отзыв глобальной публикации", - "revocationConfirmDescription": "Будет удалён @global/{{slug}} для «{{skill}}» со всеми глобальными версиями, оценками и статистикой. Командный скилл останется. Уже установленные файлы нельзя отозвать, а адрес позже может занять другой скилл.", - "revocationReasonLabel": "Причина отзыва", - "revocationReasonPlaceholder": "Причина (необязательно)", - "revocationPending": "Запрос на отзыв ожидает проверки платформой.", - "revocationRequestSuccess": "Запрос на отзыв отправлен", - "revocationDirectSuccess": "Глобальный скилл отозван", - "revocationError": "Не удалось отозвать публикацию", - "revocationHistoryTitle": "История отзывов", - "revocationHistoryItem": "{{date}} · {{status}}", - "revocationHistoryLoading": "Загрузка истории отзывов…", - "revocationHistoryError": "Не удалось загрузить историю отзывов. Повторите попытку.", - "revocationStatus": { "PENDING": "Ожидает", "APPROVED": "Отозван", "REJECTED": "Отклонён" }, "promotionErrorTitle": "Не удалось отправить запрос на продвижение", "emptyTitle": "Скиллов пока нет", "emptyDescription": "Опубликуйте свой первый скилл", @@ -723,23 +705,6 @@ "typeSkill": "Рецензии скиллов", "typeProfile": "Рецензии профилей", "tabPending": "Ожидают", - "tabRevocations": "Заявки на отзыв", - "tabRevocationHistory": "История отзывов", - "revocationEmpty": "Нет заявок на отзыв", - "revocationHistoryEmpty": "Нет рассмотренных заявок на отзыв", - "revocationStatus": { "PENDING": "Ожидает", "APPROVED": "Отозван", "REJECTED": "Отклонён" }, - "revocationActors": "Отправитель: {{submitter}} · Рецензент: {{reviewer}}", - "revocationReviewComment": "Комментарий рецензии: {{comment}}", - "revocationLoadError": "Не удалось загрузить заявки на отзыв. Повторите попытку.", - "revocationIds": "Исходный скилл #{{source}} · Глобальный скилл #{{target}}", - "revocationReason": "Причина: {{reason}}", - "approveRevocation": "Одобрить отзыв", - "rejectRevocation": "Отклонить отзыв", - "revocationConfirmTitle": "Подтвердите одобрение отзыва", - "revocationConfirmDescription": "Будут удалены все глобальные версии, оценки и статистика @global/{{slug}}. Адрес может быть использован снова. Командный скилл останется, а установленные файлы нельзя отозвать.", - "revocationApproved": "Отзыв одобрен", - "revocationRejected": "Запрос на отзыв отклонён", - "revocationActionError": "Не удалось обработать запрос на отзыв", "tabApproved": "Одобрены", "tabRejected": "Отклонены", "empty": "Нет задач рецензирования", @@ -810,6 +775,23 @@ "updateReviewHint": "После одобрения новая версия будет добавлена к существующему глобальному скиллу. Проверьте исходную и текущую версии.", "subtitle": "Запросы на продвижение командных скиллов в глобальное пространство имён", "tabPending": "Ожидают", + "tabRevocations": "Заявки на отзыв", + "tabRevocationHistory": "История отзывов", + "revocationEmpty": "Нет заявок на отзыв", + "revocationHistoryEmpty": "Нет рассмотренных заявок на отзыв", + "revocationStatus": { "PENDING": "Ожидает", "APPROVED": "Отозван", "REJECTED": "Отклонён" }, + "revocationActors": "Отправитель: {{submitter}} · Рецензент: {{reviewer}}", + "revocationReviewComment": "Комментарий рецензии: {{comment}}", + "revocationLoadError": "Не удалось загрузить заявки на отзыв. Повторите попытку.", + "revocationIds": "Исходный скилл #{{source}} · Глобальный скилл #{{target}}", + "revocationReason": "Причина: {{reason}}", + "approveRevocation": "Одобрить отзыв", + "rejectRevocation": "Отклонить отзыв", + "revocationConfirmTitle": "Подтвердите одобрение отзыва", + "revocationConfirmDescription": "Будут удалены все глобальные версии, оценки и статистика @global/{{slug}}. Адрес может быть использован снова. Командный скилл останется, а установленные файлы нельзя отозвать.", + "revocationApproved": "Отзыв одобрен", + "revocationRejected": "Запрос на отзыв отклонён", + "revocationActionError": "Не удалось обработать запрос на отзыв", "tabApproved": "Одобрены", "tabRejected": "Отклонены", "commentPlaceholder": "Комментарий рецензии (необязательно)", @@ -1334,6 +1316,24 @@ "submitGlobalUpdate": "Отправить эту версию на глобальное ревью", "globalUpdateConfirmTitle": "Подтвердите обновление глобального скилла", "globalUpdateConfirmDescription": "Отправить командную v{{source}} скилла «{{skill}}» на глобальное ревью. Сейчас последняя глобальная версия — v{{target}}; во время проверки она может измениться. Если версия не конфликтует, после одобрения она станет последней опубликованной, даже если её номер меньше.", + "promotionVersionConflictTitle": "Глобальная версия уже существует", + "promotionVersionConflictDescription": "У глобального скилла уже есть версия с таким номером. Выберите другую опубликованную командную версию.", + "revocationDescription": "Отзыв удалит весь связанный глобальный скилл, включая независимо загруженные версии. Командный скилл останется.", + "requestRevocation": "Запросить отзыв глобальной публикации", + "directRevocation": "Отозвать напрямую как администратор", + "revocationConfirmTitle": "Подтвердите отзыв глобальной публикации", + "revocationConfirmDescription": "Будет удалён @global/{{slug}} для «{{skill}}» со всеми глобальными версиями, оценками и статистикой. Командный скилл останется. Уже установленные файлы нельзя отозвать, а адрес позже может занять другой скилл.", + "revocationReasonLabel": "Причина отзыва", + "revocationReasonPlaceholder": "Причина (необязательно)", + "revocationPending": "Запрос на отзыв ожидает проверки платформой.", + "revocationRequestSuccess": "Запрос на отзыв отправлен", + "revocationDirectSuccess": "Глобальный скилл отозван", + "revocationError": "Не удалось отозвать публикацию", + "revocationHistoryTitle": "История отзывов", + "revocationHistoryItem": "{{date}} · {{status}}", + "revocationHistoryLoading": "Загрузка истории отзывов…", + "revocationHistoryError": "Не удалось загрузить историю отзывов. Повторите попытку.", + "revocationStatus": { "PENDING": "Ожидает", "APPROVED": "Отозван", "REJECTED": "Отклонён" }, "promotionConfirmTitle": "Отправить запрос на продвижение", "promotionConfirmDescription": "Отправить v{{version}} скилла «{{skill}}» на продвижение в глобальное пространство имён?", "promotionSuccessTitle": "Запрос на продвижение отправлен", diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json index fdc33756..7a9869dd 100644 --- a/web/src/i18n/locales/zh.json +++ b/web/src/i18n/locales/zh.json @@ -576,24 +576,6 @@ "promotionDuplicateDescription": "这个版本已经有待处理的提升申请,无需重复提交。", "promotionAlreadyPromotedTitle": "技能已完成提升", "promotionAlreadyPromotedDescription": "这个技能已经提升到全局命名空间,无需重复提交。", - "promotionVersionConflictTitle": "全局版本号已存在", - "promotionVersionConflictDescription": "全局技能已有同号版本。请选择另一个已发布的团队版本。", - "revocationDescription": "撤销会删除整条关联的全局技能,包括独立上传的版本。团队技能保留。", - "requestRevocation": "申请撤销全局发布", - "directRevocation": "管理员直接撤销", - "revocationConfirmTitle": "确认撤销全局发布", - "revocationConfirmDescription": "将删除“{{skill}}”对应的 @global/{{slug}} 及其所有全局版本、评价和统计;团队技能保留。已安装到客户端的文件无法收回,旧地址以后可能被其他技能使用。", - "revocationReasonLabel": "撤销原因", - "revocationReasonPlaceholder": "填写撤销原因(可选)", - "revocationPending": "撤销申请等待平台审核。", - "revocationRequestSuccess": "撤销申请已提交", - "revocationDirectSuccess": "全局技能已撤销", - "revocationError": "撤销操作失败", - "revocationHistoryTitle": "撤销记录", - "revocationHistoryItem": "{{date}} · {{status}}", - "revocationHistoryLoading": "正在读取撤销记录…", - "revocationHistoryError": "无法读取撤销记录,请稍后重试。", - "revocationStatus": { "PENDING": "待审核", "APPROVED": "已撤销", "REJECTED": "已拒绝" }, "promotionErrorTitle": "提交提升申请失败", "emptyTitle": "还没有技能", "emptyDescription": "开始发布你的第一个技能吧", @@ -723,23 +705,6 @@ "typeSkill": "技能审核", "typeProfile": "资料审核", "tabPending": "待审核", - "tabRevocations": "撤销待审核", - "tabRevocationHistory": "撤销历史", - "revocationEmpty": "暂无撤销申请", - "revocationHistoryEmpty": "暂无已处理的撤销记录", - "revocationStatus": { "PENDING": "待审核", "APPROVED": "已撤销", "REJECTED": "已拒绝" }, - "revocationActors": "申请人 {{submitter}} · 审核人 {{reviewer}}", - "revocationReviewComment": "审核意见:{{comment}}", - "revocationLoadError": "无法读取撤销申请,请稍后重试。", - "revocationIds": "来源技能 #{{source}} · 全局技能 #{{target}}", - "revocationReason": "申请原因:{{reason}}", - "approveRevocation": "批准撤销", - "rejectRevocation": "拒绝撤销", - "revocationConfirmTitle": "确认批准撤销", - "revocationConfirmDescription": "批准后将删除 @global/{{slug}} 的全部全局版本、评价和统计,旧地址可能重新被占用;团队技能保留,已安装文件无法收回。", - "revocationApproved": "撤销已批准", - "revocationRejected": "撤销申请已拒绝", - "revocationActionError": "处理撤销申请失败", "tabApproved": "已通过", "tabRejected": "已拒绝", "empty": "暂无审核任务", @@ -810,6 +775,23 @@ "updateReviewHint": "通过后会在现有全局技能新增版本;请核对来源和当前全局版本。", "subtitle": "审核团队技能提升到全局空间的申请", "tabPending": "待审核", + "tabRevocations": "撤销待审核", + "tabRevocationHistory": "撤销历史", + "revocationEmpty": "暂无撤销申请", + "revocationHistoryEmpty": "暂无已处理的撤销记录", + "revocationStatus": { "PENDING": "待审核", "APPROVED": "已撤销", "REJECTED": "已拒绝" }, + "revocationActors": "申请人 {{submitter}} · 审核人 {{reviewer}}", + "revocationReviewComment": "审核意见:{{comment}}", + "revocationLoadError": "无法读取撤销申请,请稍后重试。", + "revocationIds": "来源技能 #{{source}} · 全局技能 #{{target}}", + "revocationReason": "申请原因:{{reason}}", + "approveRevocation": "批准撤销", + "rejectRevocation": "拒绝撤销", + "revocationConfirmTitle": "确认批准撤销", + "revocationConfirmDescription": "批准后将删除 @global/{{slug}} 的全部全局版本、评价和统计,旧地址可能重新被占用;团队技能保留,已安装文件无法收回。", + "revocationApproved": "撤销已批准", + "revocationRejected": "撤销申请已拒绝", + "revocationActionError": "处理撤销申请失败", "tabApproved": "已通过", "tabRejected": "已拒绝", "commentPlaceholder": "审核意见(可选)", @@ -1269,6 +1251,24 @@ "submitGlobalUpdate": "提交此版本到全局审核", "globalUpdateConfirmTitle": "确认更新全局技能", "globalUpdateConfirmDescription": "将“{{skill}}”的团队 v{{source}} 提交全局审核。当前全局最新版本为 v{{target}};审核期间全局版仍可能独立更新。如审核通过且版本号未冲突,此版本将成为最新发布版,即使版本号较小。", + "promotionVersionConflictTitle": "全局版本号已存在", + "promotionVersionConflictDescription": "全局技能已有同号版本。请选择另一个已发布的团队版本。", + "revocationDescription": "撤销会删除整条关联的全局技能,包括独立上传的版本。团队技能保留。", + "requestRevocation": "申请撤销全局发布", + "directRevocation": "管理员直接撤销", + "revocationConfirmTitle": "确认撤销全局发布", + "revocationConfirmDescription": "将删除“{{skill}}”对应的 @global/{{slug}} 及其所有全局版本、评价和统计;团队技能保留。已安装到客户端的文件无法收回,旧地址以后可能被其他技能使用。", + "revocationReasonLabel": "撤销原因", + "revocationReasonPlaceholder": "填写撤销原因(可选)", + "revocationPending": "撤销申请等待平台审核。", + "revocationRequestSuccess": "撤销申请已提交", + "revocationDirectSuccess": "全局技能已撤销", + "revocationError": "撤销操作失败", + "revocationHistoryTitle": "撤销记录", + "revocationHistoryItem": "{{date}} · {{status}}", + "revocationHistoryLoading": "正在读取撤销记录…", + "revocationHistoryError": "无法读取撤销记录,请稍后重试。", + "revocationStatus": { "PENDING": "待审核", "APPROVED": "已撤销", "REJECTED": "已拒绝" }, "promotionConfirmTitle": "确认提交提升申请", "promotionConfirmDescription": "确认将“{{skill}}”的 v{{version}} 提交为提升到全局空间的申请吗?", "promotionSuccessTitle": "提升申请已提交", diff --git a/web/src/pages/dashboard/promotions.tsx b/web/src/pages/dashboard/promotions.tsx index 2c2f423a..787da676 100644 --- a/web/src/pages/dashboard/promotions.tsx +++ b/web/src/pages/dashboard/promotions.tsx @@ -432,13 +432,15 @@ export function PromotionsPage() {