This commit is contained in:
csj
2026-09-13 10:12:35 +08:00
parent 45fda4bd6b
commit e1fdb816ab
3 changed files with 21 additions and 13 deletions
+6
View File
@@ -1,5 +1,11 @@
# 管理端接入 # 管理端接入
## 删除材料与不使用
“报销类型”中的垃圾桶会确认后调用材料类型删除接口,立即从全局材料列表及所有报销类型的材料规则中删除该材料,不删除历史报销附件。即使材料已选“不使用”,也保留删除入口。删除失败不会在本机假装移除;成功后保留其他尚未保存的规则编辑。
“不使用”只改变当前报销类型是否需要此材料,需要点击“保存规则”生效,不删除材料类型。
## 多附件兼容 ## 多附件兼容
项目管理详情现在展示每个材料分类下的全部附件,并支持逐份预览、下载和 ZIP 导出。新版本同时解码旧服务的单附件对象和新服务的附件数组;多附件服务上线时需同步重新构建 Mac 应用。本地 OCR 和 Office 导出不受此次改动影响。 项目管理详情现在展示每个材料分类下的全部附件,并支持逐份预览、下载和 ZIP 导出。新版本同时解码旧服务的单附件对象和新服务的附件数组;多附件服务上线时需同步重新构建 Mac 应用。本地 OCR 和 Office 导出不受此次改动影响。
+5 -2
View File
@@ -386,8 +386,11 @@ private final class AdminRedirectGuard: NSObject, URLSessionTaskDelegate, @unche
guard access?.platform == true else { throw AdminFailure(message: "只有平台管理员可以删除上传材料类型") } guard access?.platform == true else { throw AdminFailure(message: "只有平台管理员可以删除上传材料类型") }
let encoded = kind.kind.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? kind.kind let encoded = kind.kind.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? kind.kind
let _: Bool = try await request("/api/admin/upload-kinds/\(encoded)", method: "DELETE") let _: Bool = try await request("/api/admin/upload-kinds/\(encoded)", method: "DELETE")
uploadKinds = try await request("/api/upload-kinds") uploadKinds.removeAll { $0.kind == kind.kind }
policies = try await request("/api/expense-policies") for index in policies.indices {
policies[index].materials.removeAll { $0.kind == kind.kind }
policies[index].requiredKinds.removeAll { $0 == kind.kind }
}
} }
func export(_ ids: Set<String>) async throws { func export(_ ids: Set<String>) async throws {
guard !ids.isEmpty, ids.count <= 20 else { throw AdminFailure(message: "每次请选择 1 至 20 笔申请") } guard !ids.isEmpty, ids.count <= 20 else { throw AdminFailure(message: "每次请选择 1 至 20 笔申请") }
+6 -7
View File
@@ -636,14 +636,17 @@ struct AdminView: View {
} label: { Image(systemName: "pencil") } } label: { Image(systemName: "pencil") }
.buttonStyle(.borderless) .buttonStyle(.borderless)
.help("编辑当前类型材料") .help("编辑当前类型材料")
}
Button { Button {
removeMaterial(policy: policy, kind: kind.kind) confirm("删除材料类型“\(kind.name)”?将从所有报销类型的材料规则中移除,历史报销附件保留。此操作立即生效;仅暂停使用请选择“不使用”并保存规则。") {
try await model.deleteUploadKind(kind)
if editingPolicyMaterialKind == kind.kind { resetPolicyMaterialEditor() } if editingPolicyMaterialKind == kind.kind { resetPolicyMaterialEditor() }
}
} label: { Image(systemName: "trash") } } label: { Image(systemName: "trash") }
.buttonStyle(.borderless) .buttonStyle(.borderless)
.tint(.red) .tint(.red)
.help("从当前报销类型移除") .help("删除材料类型(所有报销类型生效,历史附件保留)")
} .disabled(model.access?.platform != true)
} }
} }
Divider() Divider()
@@ -765,10 +768,6 @@ struct AdminView: View {
} }
policy.wrappedValue.requiredKinds = policy.wrappedValue.materials.filter(\.required).map(\.kind) policy.wrappedValue.requiredKinds = policy.wrappedValue.materials.filter(\.required).map(\.kind)
} }
private func removeMaterial(policy: Binding<AdminExpensePolicy>, kind: String) {
policy.wrappedValue.materials.removeAll { $0.kind == kind }
policy.wrappedValue.requiredKinds = policy.wrappedValue.materials.filter(\.required).map(\.kind)
}
private func resetPolicyMaterialEditor() { private func resetPolicyMaterialEditor() {
editingPolicyMaterialKind = "" editingPolicyMaterialKind = ""
newPolicyMaterialName = "" newPolicyMaterialName = ""