龍魂 · 鸿蒙 ArkTS 实战:Seal Usage Record
核心定位
| 维度 |
说明 |
| 平台 |
鸿蒙 HarmonyOS NEXT · 纯血鸿蒙 |
| 语言 |
ArkTS · 声明式UI |
| 场景 |
印章使用登记 · 审批链 · 用印记录 · 电子签章 |
| 架构 |
龍魂蚁群触角 → 鸿蒙原生能力 |
| 主权 |
数据本地 · 国密SM2/SM3签名 · 区块链存证占位 |
| 安全 |
双人双锁 · 指纹/人脸 · 用印拍照 · GPS定位 |
系统架构
┌─────────────────────────────────────────┐
│ 龍魂系统 · 鸿蒙适配层 │
│ DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️ │
│ UID: 9622 │
├─────────────────────────────────────────┤
│ 鸿蒙 ArkTS 应用层 │
│ │
│ EntryAbility → SealRecordPage │
│ ├── 印章档案建模(AppStorage/LocalStorage)│
│ ├── 用印申请审批(多级·电子签名·国密) │
│ ├── 用印现场记录(拍照·定位·双人确认) │
│ ├── 印章外带追踪(GPS·定时回传·电子围栏) │
│ ├── 历史追溯审计(不可篡改·区块链占位) │
│ └── 办公交互(导出台账·分享·打印用印单) │
├─────────────────────────────────────────┤
│ 鸿蒙系统能力层 │
│ │
│ 生物识别(Biometric) · 相机(Camera) · GPS │
│ 国密算法(Crypto) · 通知(Notification) │
│ 数据存储(RelationalStore) · 文件(File) │
│ 打印(Print) · 分享(Share) · NFC │
└─────────────────────────────────────────┘
状态建模核心
const MASTER_DNA = "ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️";
const MASTER_UID = "9622";
const CONFIRM_SEAL = "#CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z";
export enum SealType {
OFFICIAL = '公章',
FINANCE = '财务专用章',
CONTRACT = '合同专用章',
LEGAL = '法人章',
INVOICE = '发票专用章',
HR = '人事专用章',
PROJECT = '项目专用章',
DEPARTMENT = '部门章',
OTHER = '其他'
}
export enum SealMaterial {
BRONZE = '铜质',
JADE = '玉质',
HORN = '牛角',
WOOD = '木质',
CRYSTAL = '水晶',
METAL = '合金',
OTHER = '其他'
}
export enum SealStatus {
IN_VAULT = '在库',
IN_USE = '使用中',
OUTSIDE = '外带',
MAINTENANCE = '维护中',
FROZEN = '冻结',
DESTROYED = '已销毁'
}
export enum UsageType {
CONTRACT = '合同签署',
FINANCE = '财务票据',
HR = '人事文件',
CERTIFICATE = '证明文书',
AUTHORIZATION = '授权委托',
OFFICIAL = '公文往来',
BANK = '银行业务',
LEGAL = '法律文件',
OTHER = '其他'
}
export enum ApprovalLevel {
LEVEL0 = '免审批',
LEVEL1 = '部门主管',
LEVEL2 = '分管领导',
LEVEL3 = '总经理',
LEVEL4 = '董事会'
}
export class Seal {
id: string;
sealNo: string;
name: string;
type: SealType;
material: SealMaterial;
status: SealStatus;
diameter: number;
shape: '圆形' | '方形' | '椭圆形' | '其他';
pattern: string;
font: string;
custodian: string;
deputyCustodian: string;
department: string;
vaultLocation: string;
safeNo: string;
rfidTag: string;
fingerprintLock: boolean;
faceLock: boolean;
gpsTracker: boolean;
engraveDate: Date;
recordDate: Date;
expiryDate?: Date;
lastUsedDate?: Date;
useCount: number;
destroyDate?: Date;
createdAt: Date;
updatedAt: Date;
dnaSignature: string;
constructor(data: Partial<Seal>) {
this.id = data.id || this.generateId();
this.sealNo = data.sealNo || this.generateSealNo(data.type);
this.name = data.name || '';
this.type = data.type || SealType.OFFICIAL;
this.material = data.material || SealMaterial.BRONZE;
this.status = data.status || SealStatus.IN_VAULT;
this.diameter = data.diameter || 40;
this.shape = data.shape || '圆形';
this.pattern = data.pattern || '';
this.font = data.font || '宋体';
this.custodian = data.custodian || '';
this.deputyCustodian = data.deputyCustodian || '';
this.department = data.department || '';
this.vaultLocation = data.vaultLocation || '';
this.safeNo = data.safeNo || '';
this.rfidTag = data.rfidTag || '';
this.fingerprintLock = data.fingerprintLock || false;
this.faceLock = data.faceLock || false;
this.gpsTracker = data.gpsTracker || false;
this.engraveDate = data.engraveDate || new Date();
this.recordDate = data.recordDate || new Date();
this.expiryDate = data.expiryDate;
this.lastUsedDate = data.lastUsedDate;
this.useCount = data.useCount || 0;
this.destroyDate = data.destroyDate;
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
this.dnaSignature = this.signData();
}
private generateId(): string {
return `SEAL-${MASTER_UID}-${Date.now().toString(36).substr(-6)}`;
}
private generateSealNo(type: SealType): string {
const prefix = type.substring(0, 2);
const date = new Date();
return `${prefix}${date.getFullYear()}${(date.getMonth()+1).toString().padStart(2,'0')}-${Math.floor(Math.random()*999).toString().padStart(3,'0')}`;
}
private signData(): string {
const payload = `${this.id}-${this.sealNo}-${this.custodian}-${this.status}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
updateStatus(newStatus: SealStatus, operator: string): void {
this.status = newStatus;
if (newStatus === SealStatus.IN_USE) {
this.lastUsedDate = new Date();
this.useCount++;
}
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
}
export class SealApplication {
id: string;
appNo: string;
sealId: string;
sealName: string;
sealType: SealType;
applicant: string;
department: string;
applyDate: Date;
usageType: UsageType;
usageDesc: string;
documentName: string;
documentCount: number;
documentPages: number;
urgency: '普通' | '紧急' | '特急';
documentPath?: string;
attachmentPaths: string[];
approvalLevel: ApprovalLevel;
approvals: ApprovalRecord[];
executor?: string;
executeTime?: Date;
executeLocation?: string;
witness?: string;
photos: string[];
gpsLocation?: { lat: number; lng: number };
fingerprintVerify: boolean;
faceVerify: boolean;
result: 'pending' | 'approved' | 'rejected' | 'executed' | 'cancelled';
actualCount?: number;
remarks: string;
createdAt: Date;
updatedAt: Date;
dnaSignature: string;
constructor(data: Partial<SealApplication>) {
this.id = data.id || `APP-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
this.appNo = data.appNo || this.generateAppNo();
this.sealId = data.sealId || '';
this.sealName = data.sealName || '';
this.sealType = data.sealType || SealType.OFFICIAL;
this.applicant = data.applicant || '';
this.department = data.department || '';
this.applyDate = data.applyDate || new Date();
this.usageType = data.usageType || UsageType.OTHER;
this.usageDesc = data.usageDesc || '';
this.documentName = data.documentName || '';
this.documentCount = data.documentCount || 1;
this.documentPages = data.documentPages || 1;
this.urgency = data.urgency || '普通';
this.documentPath = data.documentPath;
this.attachmentPaths = data.attachmentPaths || [];
this.approvalLevel = data.approvalLevel || ApprovalLevel.LEVEL1;
this.approvals = data.approvals || [];
this.executor = data.executor;
this.executeTime = data.executeTime;
this.executeLocation = data.executeLocation;
this.witness = data.witness;
this.photos = data.photos || [];
this.gpsLocation = data.gpsLocation;
this.fingerprintVerify = data.fingerprintVerify || false;
this.faceVerify = data.faceVerify || false;
this.result = data.result || 'pending';
this.actualCount = data.actualCount;
this.remarks = data.remarks || '';
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
this.dnaSignature = this.signData();
}
private generateAppNo(): string {
const date = new Date();
return `YY${date.getFullYear()}${(date.getMonth()+1).toString().padStart(2,'0')}${date.getDate().toString().padStart(2,'0')}-${Math.floor(Math.random()*9999).toString().padStart(4,'0')}`;
}
private signData(): string {
const payload = `${this.id}-${this.appNo}-${this.sealId}-${this.applicant}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
submit(): void {
this.result = 'pending';
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
approve(level: number, approver: string, comment: string, signature: string): void {
this.approvals.push({
level,
approver,
comment,
signature,
timestamp: new Date(),
dnaSignature: this.signApproval(level, approver, signature)
});
const requiredLevels = this.getRequiredLevels();
if (this.approvals.length >= requiredLevels.length) {
this.result = 'approved';
}
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
reject(approver: string, comment: string): void {
this.result = 'rejected';
this.approvals.push({
level: this.getCurrentLevel(),
approver,
comment,
signature: 'REJECTED',
timestamp: new Date(),
dnaSignature: this.signApproval(this.getCurrentLevel(), approver, 'REJECT')
});
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
execute(executor: string, witness: string, photos: string[], location: {lat: number, lng: number}): void {
this.executor = executor;
this.witness = witness;
this.photos = photos;
this.gpsLocation = location;
this.executeTime = new Date();
this.executeLocation = `${location.lat.toFixed(6)},${location.lng.toFixed(6)}`;
this.result = 'executed';
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
private getRequiredLevels(): number[] {
switch (this.approvalLevel) {
case ApprovalLevel.LEVEL0: return [];
case ApprovalLevel.LEVEL1: return [1];
case ApprovalLevel.LEVEL2: return [1, 2];
case ApprovalLevel.LEVEL3: return [1, 2, 3];
case ApprovalLevel.LEVEL4: return [1, 2, 3, 4];
default: return [1];
}
}
private getCurrentLevel(): number {
return this.approvals.length + 1;
}
private signApproval(level: number, approver: string, signature: string): string {
const payload = `${this.id}-L${level}-${approver}-${signature}-${Date.now()}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
getApprovalProgress(): { current: number; total: number; percentage: number } {
const total = this.getRequiredLevels().length;
const current = this.approvals.filter(a => a.signature !== 'REJECTED').length;
return {
current,
total,
percentage: total > 0 ? Math.round((current / total) * 100) : 100
};
}
}
export interface ApprovalRecord {
level: number;
approver: string;
comment: string;
signature: string;
timestamp: Date;
dnaSignature: string;
}
export class SealOutRecord {
id: string;
sealId: string;
sealName: string;
borrower: string;
borrowerDept: string;
borrowDate: Date;
expectedReturn: Date;
actualReturn?: Date;
purpose: string;
destination: string;
escort: string;
gpsTrack: GpsPoint[];
checkInRecords: CheckInRecord[];
status: 'out' | 'returned' | 'overdue';
dnaSignature: string;
constructor(data: Partial<SealOutRecord>) {
this.id = data.id || `OUT-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
this.sealId = data.sealId || '';
this.sealName = data.sealName || '';
this.borrower = data.borrower || '';
this.borrowerDept = data.borrowerDept || '';
this.borrowDate = data.borrowDate || new Date();
this.expectedReturn = data.expectedReturn || new Date(Date.now() + 24*60*60*1000);
this.actualReturn = data.actualReturn;
this.purpose = data.purpose || '';
this.destination = data.destination || '';
this.escort = data.escort || '';
this.gpsTrack = data.gpsTrack || [];
this.checkInRecords = data.checkInRecords || [];
this.status = data.status || 'out';
this.dnaSignature = this.signData();
}
private signData(): string {
const payload = `${this.id}-${this.sealId}-${this.borrower}-${this.status}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
addGpsPoint(lat: number, lng: number, accuracy: number): void {
this.gpsTrack.push({
lat, lng, accuracy,
timestamp: new Date(),
dnaSignature: this.signGps(lat, lng)
});
}
checkIn(location: string, photoPath: string, operator: string): void {
this.checkInRecords.push({
timestamp: new Date(),
location,
photoPath,
operator,
dnaSignature: this.signCheckIn(location, operator)
});
}
returnSeal(returner: string, witness: string): void {
this.actualReturn = new Date();
this.status = 'returned';
this.dnaSignature = this.signData();
}
isOverdue(): boolean {
return this.status === 'out' && new Date() > this.expectedReturn;
}
private signGps(lat: number, lng: number): string {
return `SM3-${lat.toFixed(6)}-${lng.toFixed(6)}-${Date.now()}`;
}
private signCheckIn(location: string, operator: string): string {
return `SM3-${location}-${operator}-${Date.now()}`;
}
}
export interface GpsPoint {
lat: number;
lng: number;
accuracy: number;
timestamp: Date;
dnaSignature: string;
}
export interface CheckInRecord {
timestamp: Date;
location: string;
photoPath: string;
operator: string;
dnaSignature: string;
}
@Observed
export class SealState {
seals: Seal[] = [];
applications: SealApplication[] = [];
outRecords: SealOutRecord[] = [];
currentUser: string = '';
currentDept: string = '';
userRole: 'admin' | 'custodian' | 'applicant' | 'approver' | 'witness' = 'applicant';
filterStatus: SealStatus | '全部' = '全部';
filterType: SealType | '全部' = '全部';
searchQuery: string = '';
alertOverdue: boolean = true;
alertLowStock: boolean = true;
alertPending: boolean = true;
get filteredSeals(): Seal[] {
let result = this.seals;
if (this.filterStatus !== '全部') {
result = result.filter(s => s.status === this.filterStatus);
}
if (this.filterType !== '全部') {
result = result.filter(s => s.type === this.filterType);
}
if (this.searchQuery) {
const q = this.searchQuery.toLowerCase();
result = result.filter(s =>
s.name.toLowerCase().includes(q) ||
s.sealNo.toLowerCase().includes(q) ||
s.custodian.toLowerCase().includes(q) ||
s.department.toLowerCase().includes(q)
);
}
return result.sort((a, b) => b.useCount - a.useCount);
}
get pendingApprovals(): SealApplication[] {
return this.applications.filter(a => a.result === 'pending');
}
get myApplications(): SealApplication[] {
return this.applications.filter(a => a.applicant === this.currentUser);
}
get activeOutRecords(): SealOutRecord[] {
return this.outRecords.filter(r => r.status === 'out');
}
get overdueRecords(): SealOutRecord[] {
return this.outRecords.filter(r => r.isOverdue());
}
get statistics(): SealStats {
return {
totalSeals: this.seals.length,
inVault: this.seals.filter(s => s.status === SealStatus.IN_VAULT).length,
inUse: this.seals.filter(s => s.status === SealStatus.IN_USE).length,
outside: this.seals.filter(s => s.status === SealStatus.OUTSIDE).length,
totalApplications: this.applications.length,
pendingCount: this.pendingApprovals.length,
todayExecutions: this.applications.filter(a => {
if (!a.executeTime) return false;
const today = new Date();
return a.executeTime.getDate() === today.getDate() &&
a.executeTime.getMonth() === today.getMonth() &&
a.executeTime.getFullYear() === today.getFullYear();
}).length,
overdueCount: this.overdueRecords.length
};
}
addSeal(seal: Seal): void {
this.seals.push(seal);
this.persist();
}
removeSeal(id: string): void {
const idx = this.seals.findIndex(s => s.id === id);
if (idx >= 0) {
this.seals.splice(idx, 1);
this.persist();
}
}
updateSeal(id: string, data: Partial<Seal>): void {
const idx = this.seals.findIndex(s => s.id === id);
if (idx >= 0) {
const old = this.seals[idx];
this.seals[idx] = new Seal({ ...old, ...data, id: old.id });
this.persist();
}
}
submitApplication(app: SealApplication): void {
this.applications.push(app);
this.persist();
}
approveApplication(appId: string, level: number, approver: string, comment: string, signature: string): void {
const app = this.applications.find(a => a.id === appId);
if (app) {
app.approve(level, approver, comment, signature);
this.persist();
}
}
executeApplication(appId: string, executor: string, witness: string, photos: string[], location: {lat: number, lng: number}): void {
const app = this.applications.find(a => a.id === appId);
if (app) {
app.execute(executor, witness, photos, location);
const seal = this.seals.find(s => s.id === app.sealId);
if (seal) {
seal.updateStatus(SealStatus.IN_USE, executor);
}
this.persist();
}
}
registerOut(record: SealOutRecord): void {
this.outRecords.push(record);
const seal = this.seals.find(s => s.id === record.sealId);
if (seal) {
seal.updateStatus(SealStatus.OUTSIDE, record.borrower);
}
this.persist();
}
returnSeal(recordId: string, returner: string, witness: string): void {
const record = this.outRecords.find(r => r.id === recordId);
if (record) {
record.returnSeal(returner, witness);
const seal = this.seals.find(s => s.id === record.sealId);
if (seal) {
seal.updateStatus(SealStatus.IN_VAULT, returner);
}
this.persist();
}
}
private persist(): void {
AppStorage.setOrCreate('seal_seals', JSON.stringify(this.seals));
AppStorage.setOrCreate('seal_applications', JSON.stringify(this.applications));
AppStorage.setOrCreate('seal_out_records', JSON.stringify(this.outRecords));
}
load(): void {
const seals = AppStorage.get<string>('seal_seals');
if (seals) {
try {
const parsed = JSON.parse(seals);
this.seals = parsed.map((s: any) => new Seal(s));
} catch (e) {
console.error('加载印章数据失败', e);
}
}
const apps = AppStorage.get<string>('seal_applications');
if (apps) {
try {
const parsed = JSON.parse(apps);
this.applications = parsed.map((a: any) => new SealApplication(a));
} catch (e) {
console.error('加载申请数据失败', e);
}
}
const outs = AppStorage.get<string>('seal_out_records');
if (outs) {
try {
const parsed = JSON.parse(outs);
this.outRecords = parsed.map((o: any) => new SealOutRecord(o));
} catch (e) {
console.error('加载外带记录失败', e);
}
}
}
}
export interface SealStats {
totalSeals: number;
inVault: number;
inUse: number;
outside: number;
totalApplications: number;
pendingCount: number;
todayExecutions: number;
overdueCount: number;
}
export const sealState = new SealState();
AppStorage.setOrCreate('sealState', sealState);
主页面实现
import { Seal, SealType, SealStatus, SealApplication, SealOutRecord, ApprovalLevel, UsageType, SealState, sealState, SealStats } from '../models/SealModel';
import { SealDetailDialog } from '../components/SealDetailDialog';
import { ApplicationDialog } from '../components/ApplicationDialog';
import { ApprovalDialog } from '../components/ApprovalDialog';
import { ExecuteDialog } from '../components/ExecuteDialog';
import { OutRecordDialog } from '../components/OutRecordDialog';
import { AlertBanner } from '../components/AlertBanner';
import { SealDatabase } from '../database/SealDatabase';
@Entry
@Component
struct SealRecordPage {
@StorageLink('sealState') sealState: SealState = sealState;
@State private selectedTab: number = 0;
@State private showSealDialog: boolean = false;
@State private showAppDialog: boolean = false;
@State private showApprovalDialog: boolean = false;
@State private showExecuteDialog: boolean = false;
@State private showOutDialog: boolean = false;
@State private editingSeal: Seal | null = null;
@State private editingApp: SealApplication | null = null;
@State private showSearch: boolean = false;
@State private searchText: string = '';
@State private showAlerts: boolean = false;
@State private scanMode: boolean = false;
aboutToAppear() {
this.sealState.load();
SealDatabase.init();
this.scheduleAlerts();
}
build() {
Column() {
this.HeaderBuilder()
if (this.getAlertCount() > 0 && !this.showAlerts) {
this.AlertBannerBuilder()
}
if (this.showAlerts) {
AlertBanner({
alerts: this.getAllAlerts(),
onClose: () => { this.showAlerts = false; }
})
}
this.StatsBuilder()
this.TabBuilder()
if (this.showSearch) {
this.SearchBuilder()
}
this.ContentBuilder()
this.FooterBuilder()
}
.width('100%')
.height('100%')
.backgroundColor('#0a0a0a')
}
@Builder
HeaderBuilder() {
Row() {
Text('🐉')
.fontSize(28)
.margin({ right: 8 })
Column() {
Text('龍魂印章管理')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#c41e3a')
Text(`UID:${MASTER_UID} · ${this.sealState.seals.length}枚印章`)
.fontSize(12)
.fontColor('#666')
}
.alignItems(HorizontalAlign.Start)
Blank()
Badge({
value: this.getAlertCount().toString(),
position: BadgePosition.RightTop,
style: { badgeSize: 18, badgeColor: '#c41e3a' }
}) {
Button() {
Text('🔔')
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor(this.getAlertCount() > 0 ? 'rgba(196,30,58,0.2)' : '#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.showAlerts = !this.showAlerts;
})
}
Button() {
Text('📷')
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor('#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.startScan();
})
Button() {
Text(this.showSearch ? '✕' : '🔍')
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor('#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.showSearch = !this.showSearch;
if (!this.showSearch) {
this.sealState.searchQuery = '';
}
})
Button() {
Text('+')
.fontSize(24)
.fontColor('#fff')
}
.type(ButtonType.Circle)
.backgroundColor('#c41e3a')
.width(40)
.height(40)
.onClick(() => {
this.editingSeal = null;
this.showSealDialog = true;
})
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
@Builder
AlertBannerBuilder() {
Row() {
Text('⚠️')
.fontSize(24)
.margin({ right: 8 })
Column() {
Text(`${this.getAlertCount()} 条预警待处理`)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#ffcc00')
Text(this.getAlertPreview())
.fontSize(12)
.fontColor('#ffcc00')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('查看')
.fontSize(12)
.fontColor('#0a0a0a')
.backgroundColor('#ffcc00')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.onClick(() => {
this.showAlerts = true;
})
}
.width('100%')
.padding(12)
.backgroundColor('rgba(255,204,0,0.1)')
.border({ width: { bottom: 1 }, color: 'rgba(255,204,0,0.3)' })
}
@Builder
StatsBuilder() {
Row() {
this.StatCard('印章总数', this.sealState.statistics.totalSeals.toString(), '#fff')
this.StatCard('在库', this.sealState.statistics.inVault.toString(), '#00ff00')
this.StatCard('使用中', this.sealState.statistics.inUse.toString(), '#ffcc00')
this.StatCard('外带', this.sealState.statistics.outside.toString(), '#ff6600')
this.StatCard('今日用印', this.sealState.statistics.todayExecutions.toString(), '#c41e3a')
}
.width('100%')
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
.justifyContent(FlexAlign.SpaceAround)
}
@Builder
StatCard(label: string, value: string, color: string) {
Column() {
Text(value)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor(color)
Text(label)
.fontSize(11)
.fontColor('#888')
.margin({ top: 4 })
}
.padding(8)
.backgroundColor('#1a1a1a')
.borderRadius(8)
.width('18%')
}
@Builder
TabBuilder() {
Row() {
ForEach([
{ label: '印章档案', icon: '🔏', count: 0 },
{ label: '用印申请', icon: '📝', count: this.sealState.pendingApprovals.length },
{ label: '执行记录', icon: '✅', count: 0 },
{ label: '外带追踪', icon: '📍', count: this.sealState.activeOutRecords.length }
], (item: {label: string, icon: string, count: number}, index: number) => {
Column() {
Text(`${item.icon} ${item.label}${item.count > 0 ? `(${item.count})` : ''}`)
.fontSize(13)
.fontWeight(this.selectedTab === index ? FontWeight.Bold : FontWeight.Normal)
.fontColor(this.selectedTab === index ? '#c41e3a' : '#888')
if (this.selectedTab === index) {
Divider()
.strokeWidth(2)
.color('#c41e3a')
.width(20)
.margin({ top: 4 })
}
}
.padding({ top: 12, bottom: 12, left: 16, right: 16 })
.onClick(() => {
this.selectedTab = index;
})
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
@Builder
SearchBuilder() {
Row() {
TextInput({ placeholder: '搜索印章/编号/保管人/部门...', text: $$this.searchText })
.width('100%')
.height(40)
.backgroundColor('#2a2a2a')
.fontColor('#fff')
.placeholderColor('#666')
.borderRadius(8)
.padding({ left: 12, right: 12 })
.onChange((value: string) => {
this.sealState.searchQuery = value;
})
}
.width('100%')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.backgroundColor('#1a1a1a')
}
@Builder
ContentBuilder() {
if (this.selectedTab === 0) {
this.SealListBuilder()
} else if (this.selectedTab === 1) {
this.ApplicationListBuilder()
} else if (this.selectedTab === 2) {
this.RecordListBuilder()
} else {
this.OutTrackBuilder()
}
}
@Builder
SealListBuilder() {
List() {
ForEach(this.sealState.filteredSeals, (seal: Seal) => {
ListItem() {
this.SealCardBuilder(seal)
}
.swipeAction({ end: this.SealSwipeBuilder(seal) })
.onClick(() => {
this.editingSeal = seal;
this.showSealDialog = true;
})
}, (seal: Seal) => seal.id)
}
.width('100%')
.layoutWeight(1)
.divider({ strokeWidth: 1, color: '#222' })
.scrollBar(BarState.Auto)
.edgeEffect(EdgeEffect.Spring)
.padding({ bottom: 16 })
}
@Builder
SealCardBuilder(seal: Seal) {
Row() {
Stack() {
Column() {
Text('印')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor(
seal.status === SealStatus.IN_VAULT ? '#00ff00' :
seal.status === SealStatus.IN_USE ? '#ffcc00' :
seal.status === SealStatus.OUTSIDE ? '#ff6600' :
seal.status === SealStatus.FROZEN ? '#888' :
'#ff0000'
)
}
.width(48)
.height(48)
.backgroundColor('#2a2a2a')
.borderRadius(8)
.justifyContent(FlexAlign.Center)
Text(
seal.status === SealStatus.IN_VAULT ? '库' :
seal.status === SealStatus.IN_USE ? '用' :
seal.status === SealStatus.OUTSIDE ? '外' :
seal.status === SealStatus.FROZEN ? '冻' : '废'
)
.fontSize(9)
.fontColor('#fff')
.backgroundColor(
seal.status === SealStatus.IN_VAULT ? '#00aa00' :
seal.status === SealStatus.IN_USE ? '#ffaa00' :
seal.status === SealStatus.OUTSIDE ? '#ff6600' :
seal.status === SealStatus.FROZEN ? '#666' : '#ff0000'
)
.borderRadius(4)
.padding({ left: 3, right: 3 })
.position({ x: 32, y: -4 })
}
.width(48)
.height(48)
.margin({ right: 12 })
Column() {
Row() {
Text(seal.name)
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor('#fff')
.layoutWeight(1)
Text(seal.sealNo)
.fontSize(11)
.fontColor('#666')
.fontFamily('monospace')
}
.width('100%')
Row() {
Text(`${seal.type} · ${seal.material} · ${seal.diameter}mm${seal.shape}`)
.fontSize(12)
.fontColor('#888')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Text(`${seal.useCount}次`)
.fontSize(12)
.fontColor('#888')
}
.width('100%')
.margin({ top: 4 })
Row() {
Text(`👤${seal.custodian}`)
.fontSize(11)
.fontColor('#666')
Text(`📍${seal.vaultLocation}`)
.fontSize(11)
.fontColor('#666')
.margin({ left: 8 })
Blank()
Row() {
if (seal.fingerprintLock) {
Text('🔐')
.fontSize(12)
.margin({ right: 4 })
}
if (seal.faceLock) {
Text('👤')
.fontSize(12)
.margin({ right: 4 })
}
if (seal.gpsTracker) {
Text('📡')
.fontSize(12)
}
}
}
.width('100%')
.margin({ top: 6 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(16)
.backgroundColor(
seal.status === SealStatus.OUTSIDE ? 'rgba(255,102,0,0.05)' :
seal.status === SealStatus.IN_USE ? 'rgba(255,204,0,0.05)' :
'#0a0a0a'
)
.borderRadius(8)
.margin({ left: 12, right: 12, top: 8 })
}
@Builder
SealSwipeBuilder(seal: Seal) {
Row() {
Button() {
Text('申请')
.fontColor('#fff')
.fontSize(12)
}
.type(ButtonType.Capsule)
.backgroundColor('#0066cc')
.width(60)
.height('100%')
.margin({ right: 4 })
.onClick(() => {
this.startApplication(seal);
})
Button() {
Text('外带')
.fontColor('#fff')
.fontSize(12)
}
.type(ButtonType.Capsule)
.backgroundColor('#ff6600')
.width(60)
.height('100%')
.margin({ right: 4 })
.onClick(() => {
this.startOutRecord(seal);
})
Button() {
Text('删除')
.fontColor('#fff')
.fontSize(12)
}
.type(ButtonType.Capsule)
.backgroundColor('#ff0000')
.width(60)
.height('100%')
.onClick(() => {
AlertDialog.show({
title: '确认删除',
message: `删除 ${seal.name}?此操作不可恢复`,
primaryButton: {
value: '删除',
action: () => {
this.sealState.removeSeal(seal.id);
}
},
secondaryButton: {
value: '取消',
action: () => {}
}
});
})
}
.width(200)
.height('100%')
.padding({ left: 4 })
}
@Builder
ApplicationListBuilder() {
List() {
ForEach(this.sealState.applications.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()), (app: SealApplication) => {
ListItem() {
this.ApplicationCardBuilder(app)
}
.onClick(() => {
this.editingApp = app;
if (app.result === 'pending') {
this.showApprovalDialog = true;
} else {
this.showExecuteDialog = true;
}
})
}, (app: SealApplication) => app.id)
}
.width('100%')
.layoutWeight(1)
.divider({ strokeWidth: 1, color: '#222' })
.scrollBar(BarState.Auto)
.padding({ bottom: 16 })
}
@Builder
ApplicationCardBuilder(app: SealApplication) {
Row() {
Column() {
Text(
app.result === 'pending' ? '⏳' :
app.result === 'approved' ? '✅' :
app.result === 'rejected' ? '❌' :
app.result === 'executed' ? '📋' : '✕'
)
.fontSize(24)
}
.width(40)
.height(40)
.margin({ right: 12 })
.justifyContent(FlexAlign.Center)
Column() {
Row() {
Text(app.documentName)
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor('#fff')
.layoutWeight(1)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(app.urgency)
.fontSize(11)
.fontColor(
app.urgency === '特急' ? '#ff0000' :
app.urgency === '紧急' ? '#ffcc00' : '#888'
)
.backgroundColor(
app.urgency === '特急' ? 'rgba(255,0,0,0.1)' :
app.urgency === '紧急' ? 'rgba(255,204,0,0.1)' : '#2a2a2a'
)
.borderRadius(4)
.padding({ left: 6, right: 6 })
}
.width('100%')
Row() {
Text(`${app.sealName} · ${app.usageType}`)
.fontSize(12)
.fontColor('#888')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Text(`${app.documentCount}份${app.documentPages}页`)
.fontSize(12)
.fontColor('#888')
}
.width('100%')
.margin({ top: 4 })
Row() {
Text(`👤${app.applicant}`)
.fontSize(11)
.fontColor('#666')
Text(`📅${app.applyDate.toLocaleDateString()}`)
.fontSize(11)
.fontColor('#666')
.margin({ left: 8 })
Blank()
if (app.result === 'pending') {
const progress = app.getApprovalProgress();
Stack() {
Row()
.width(60)
.height(4)
.backgroundColor('#333')
.borderRadius(2)
Row()
.width(`${progress.percentage}%`)
.height(4)
.backgroundColor('#c41e3a')
.borderRadius(2)
}
.width(60)
.height(4)
Text(`${progress.current}/${progress.total}`)
.fontSize(10)
.fontColor('#c41e3a')
.margin({ left: 4 })
}
}
.width('100%')
.margin({ top: 6 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(16)
.backgroundColor(
app.result === 'pending' ? 'rgba(196,30,58,0.05)' :
app.result === 'rejected' ? 'rgba(255,0,0,0.05)' :
'#0a0a0a'
)
.borderRadius(8)
.margin({ left: 12, right: 12, top: 8 })
}
@Builder
RecordListBuilder() {
List() {
ForEach(
this.sealState.applications.filter(a => a.result === 'executed').sort((a, b) =>
(b.executeTime?.getTime() || 0) - (a.executeTime?.getTime() || 0)
),
(app: SealApplication) => {
ListItem() {
this.RecordCardBuilder(app)
}
},
(app: SealApplication) => app.id
)
}
.width('100%')
.layoutWeight(1)
.divider({ strokeWidth: 1, color: '#222' })
.scrollBar(BarState.Auto)
.padding({ bottom: 16 })
}
@Builder
RecordCardBuilder(app: SealApplication) {
Row() {
Column() {
Text('📋')
.fontSize(24)
}
.width(40)
.height(40)
.margin({ right: 12 })
.justifyContent(FlexAlign.Center)
Column() {
Row() {
Text(app.documentName)
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor('#fff')
.layoutWeight(1)
Text(`✅已执行`)
.fontSize(11)
.fontColor('#00ff00')
.backgroundColor('rgba(0,255,0,0.1)')
.borderRadius(4)
.padding({ left: 6, right: 6 })
}
.width('100%')
Row() {
Text(`${app.sealName} · ${app.executor}`)
.fontSize(12)
.fontColor('#888')
.layoutWeight(1)
Text(`${app.actualCount || app.documentCount}份`)
.fontSize(12)
.fontColor('#888')
}
.width('100%')
.margin({ top: 4 })
Row() {
Text(`📅${app.executeTime?.toLocaleString() || ''}`)
.fontSize(11)
.fontColor('#666')
if (app.gpsLocation) {
Text(`📍${app.gpsLocation.lat.toFixed(4)},${app.gpsLocation.lng.toFixed(4)}`)
.fontSize(11)
.fontColor('#666')
.margin({ left: 8 })
}
Blank()
Text(`👁️${app.witness}`)
.fontSize(11)
.fontColor('#666')
}
.width('100%')
.margin({ top: 6 })
if (app.photos.length > 0) {
Row() {
ForEach(app.photos.slice(0, 3), (photo: string) => {
Image(photo)
.width(40)
.height(40)
.borderRadius(4)
.objectFit(ImageFit.Cover)
.margin({ right: 4 })
})
if (app.photos.length > 3) {
Text(`+${app.photos.length - 3}`)
.fontSize(12)
.fontColor('#888')
.width(40)
.height(40)
.backgroundColor('#2a2a2a')
.borderRadius(4)
.textAlign(TextAlign.Center)
}
}
.width('100%')
.margin({ top: 8 })
}
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(16)
.backgroundColor('#0a0a0a')
.borderRadius(8)
.margin({ left: 12, right: 12, top: 8 })
}
@Builder
OutTrackBuilder() {
List() {
ForEach(this.sealState.activeOutRecords, (record: SealOutRecord) => {
ListItem() {
this.OutRecordCardBuilder(record)
}
}, (record: SealOutRecord) => record.id)
}
.width('100%')
.layoutWeight(1)
.divider({ strokeWidth: 1, color: '#222' })
.scrollBar(BarState.Auto)
.padding({ bottom: 16 })
}
@Builder
OutRecordCardBuilder(record: SealOutRecord) {
Row() {
Column() {
Text('📍')
.fontSize(24)
}
.width(40)
.height(40)
.margin({ right: 12 })
.justifyContent(FlexAlign.Center)
Column() {
Row() {
Text(record.sealName)
.fontSize(15)
.fontWeight(FontWeight.Medium)
.fontColor('#fff')
.layoutWeight(1)
if (record.isOverdue()) {
Text('超期')
.fontSize(11)
.fontColor('#ff0000')
.backgroundColor('rgba(255,0,0,0.1)')
.borderRadius(4)
.padding({ left: 6, right: 6 })
} else {
Text('外带中')
.fontSize(11)
.fontColor('#ff6600')
.backgroundColor('rgba(255,102,0,0.1)')
.borderRadius(4)
.padding({ left: 6, right: 6 })
}
}
.width('100%')
Row() {
Text(`借出: ${record.borrower} · ${record.borrowDate.toLocaleDateString()}`)
.fontSize(12)
.fontColor('#888')
.layoutWeight(1)
Text(`预计归还: ${record.expectedReturn.toLocaleDateString()}`)
.fontSize(12)
.fontColor(record.isOverdue() ? '#ff0000' : '#888')
}
.width('100%')
.margin({ top: 4 })
Row() {
Text(`📍${record.destination}`)
.fontSize(11)
.fontColor('#666')
.layoutWeight(1)
Text(`👤陪同: ${record.escort}`)
.fontSize(11)
.fontColor('#666')
}
.width('100%')
.margin({ top: 6 })
if (record.gpsTrack.length > 0) {
Row() {
Text(`📡 GPS轨迹: ${record.gpsTrack.length}个点`)
.fontSize(11)
.fontColor('#666')
Text(`最新: ${record.gpsTrack[record.gpsTrack.length - 1].lat.toFixed(4)},${record.gpsTrack[record.gpsTrack.length - 1].lng.toFixed(4)}`)
.fontSize(11)
.fontColor('#666')
.margin({ left: 8 })
}
.width('100%')
.margin({ top: 4 })
}
if (record.checkInRecords.length > 0) {
Row() {
Text(`📝 回传: ${record.checkInRecords.length}次`)
.fontSize(11)
.fontColor('#666')
Text(`最新: ${record.checkInRecords[record.checkInRecords.length - 1].timestamp.toLocaleString()}`)
.fontSize(11)
.fontColor('#666')
.margin({ left: 8 })
}
.width('100%')
.margin({ top: 4 })
}
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(16)
.backgroundColor(
record.isOverdue() ? 'rgba(255,0,0,0.05)' : 'rgba(255,102,0,0.05)'
)
.borderRadius(8)
.margin({ left: 12, right: 12, top: 8 })
}
@Builder
FooterBuilder() {
Row() {
Button('📝 用印申请')
.fontSize(13)
.fontColor('#fff')
.backgroundColor('#0066cc')
.borderRadius(8)
.padding({ left: 16, right: 16 })
.onClick(() => {
this.showAppDialog = true;
})
Button('📋 执行登记')
.fontSize(13)
.fontColor('#fff')
.backgroundColor('#c41e3a')
.borderRadius(8)
.padding({ left: 16, right: 16 })
.onClick(() => {
this.showExecuteDialog = true;
})
Button('📍 外带登记')
.fontSize(13)
.fontColor('#fff')
.backgroundColor('#ff6600')
.borderRadius(8)
.padding({ left: 16, right: 16 })
.onClick(() => {
this.showOutDialog = true;
})
Button('📊 导出台账')
.fontSize(13)
.fontColor('#ccc')
.backgroundColor('#1a1a1a')
.border({ width: 1, color: '#444' })
.borderRadius(8)
.padding({ left: 16, right: 16 })
.onClick(() => {
this.exportLedger();
})
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#1a1a1a')
.border({ width: { top: 1 }, color: '#333' })
.justifyContent(FlexAlign.SpaceAround)
}
private getAlertCount(): number {
return this.getAllAlerts().length;
}
private getAllAlerts(): AlertItem[] {
const alerts: AlertItem[] = [];
this.sealState.overdueRecords.forEach(r => {
alerts.push({
type: 'overdue',
level: 'critical',
title: `${r.sealName} 外带超期`,
message: `借出人: ${r.borrower},预计归还: ${r.expectedReturn.toLocaleDateString()}`,
timestamp: new Date()
});
});
if (this.sealState.pendingApprovals.length > 0) {
alerts.push({
type: 'pending',
level: 'warning',
title: `${this.sealState.pendingApprovals.length} 条用印申请待审批`,
message: `请尽快处理`,
timestamp: new Date()
});
}
return alerts;
}
private getAlertPreview(): string {
const alerts = this.getAllAlerts();
return alerts.slice(0, 2).map(a => a.title).join('、');
}
private startScan() {
}
private startApplication(seal: Seal) {
this.editingSeal = seal;
this.showAppDialog = true;
}
private startOutRecord(seal: Seal) {
this.editingSeal = seal;
this.showOutDialog = true;
}
private exportLedger() {
}
private scheduleAlerts() {
}
}
const MASTER_DNA = "ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️";
const MASTER_UID = "9622";
interface AlertItem {
type: 'overdue' | 'pending' | 'low_stock' | 'expired';
level: 'critical' | 'warning' | 'info';
title: string;
message: string;
timestamp: Date;
}
数据库持久化
import { relationalStore } from '@kit.ArkData';
const STORE_NAME = 'LongHunSeal.db';
const TABLE_SEALS = 'seals';
const TABLE_APPLICATIONS = 'applications';
const TABLE_APPROVALS = 'approvals';
const TABLE_OUT_RECORDS = 'out_records';
const TABLE_GPS_TRACKS = 'gps_tracks';
export class SealDatabase {
private static store: relationalStore.RdbStore | null = null;
static async init(): Promise<void> {
const config: relationalStore.StoreConfig = {
name: STORE_NAME,
securityLevel: relationalStore.SecurityLevel.S3,
encrypt: true
};
this.store = await relationalStore.getRdbStore(getContext(), config);
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS ${TABLE_SEALS} (
id TEXT PRIMARY KEY,
seal_no TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
type TEXT,
material TEXT,
status TEXT,
diameter INTEGER,
shape TEXT,
pattern TEXT,
font TEXT,
custodian TEXT,
deputy_custodian TEXT,
department TEXT,
vault_location TEXT,
safe_no TEXT,
rfid_tag TEXT,
fingerprint_lock INTEGER,
face_lock INTEGER,
gps_tracker INTEGER,
engrave_date INTEGER,
record_date INTEGER,
expiry_date INTEGER,
last_used_date INTEGER,
use_count INTEGER,
destroy_date INTEGER,
created_at INTEGER,
updated_at INTEGER,
dna_signature TEXT
)
`);
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS ${TABLE_APPLICATIONS} (
id TEXT PRIMARY KEY,
app_no TEXT NOT NULL UNIQUE,
seal_id TEXT,
seal_name TEXT,
seal_type TEXT,
applicant TEXT,
department TEXT,
apply_date INTEGER,
usage_type TEXT,
usage_desc TEXT,
document_name TEXT,
document_count INTEGER,
document_pages INTEGER,
urgency TEXT,
document_path TEXT,
attachment_paths TEXT,
approval_level TEXT,
executor TEXT,
execute_time INTEGER,
execute_location TEXT,
witness TEXT,
photos TEXT,
gps_lat REAL,
gps_lng REAL,
fingerprint_verify INTEGER,
face_verify INTEGER,
result TEXT,
actual_count INTEGER,
remarks TEXT,
created_at INTEGER,
updated_at INTEGER,
dna_signature TEXT
)
`);
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS ${TABLE_APPROVALS} (
id TEXT PRIMARY KEY,
application_id TEXT,
level INTEGER,
approver TEXT,
comment TEXT,
signature TEXT,
timestamp INTEGER,
dna_signature TEXT
)
`);
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS ${TABLE_OUT_RECORDS} (
id TEXT PRIMARY KEY,
seal_id TEXT,
seal_name TEXT,
borrower TEXT,
borrower_dept TEXT,
borrow_date INTEGER,
expected_return INTEGER,
actual_return INTEGER,
purpose TEXT,
destination TEXT,
escort TEXT,
status TEXT,
created_at INTEGER,
dna_signature TEXT
)
`);
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS ${TABLE_GPS_TRACKS} (
id TEXT PRIMARY KEY,
record_id TEXT,
lat REAL,
lng REAL,
accuracy REAL,
timestamp INTEGER,
dna_signature TEXT
)
`);
}
}
模块清单
| 文件 |
路径 |
说明 |
| 数据模型 |
entry/src/main/ets/models/SealModel.ets |
Seal/SealApplication/SealOutRecord |
| 主页面 |
entry/src/main/ets/pages/SealRecordPage.ets |
完整UI |
| 数据库 |
entry/src/main/ets/database/SealDatabase.ets |
关系型存储 |
| 印章详情 |
entry/src/main/ets/components/SealDetailDialog.ets |
增改印章 |
| 申请弹窗 |
entry/src/main/ets/components/ApplicationDialog.ets |
用印申请 |
| 审批弹窗 |
entry/src/main/ets/components/ApprovalDialog.ets |
多级审批 |
| 执行弹窗 |
entry/src/main/ets/components/ExecuteDialog.ets |
现场执行 |
| 外带弹窗 |
entry/src/main/ets/components/OutRecordDialog.ets |
外带登记 |
| 预警面板 |
entry/src/main/ets/components/AlertBanner.ets |
预警列表 |
鸿蒙特性使用
| 特性 |
用途 |
API |
| ArkTS声明式UI |
界面构建 |
@Component @Entry |
| 状态管理 |
数据响应 |
@State @Observed @StorageLink |
| 关系型数据库 |
本地加密存储 |
relationalStore S3级别 |
| 生物识别 |
用印验证 |
biometricAuth |
| 相机 |
现场拍照 |
cameraPicker |
| GPS |
外带定位 |
geoLocationManager |
| 扫码 |
印章识别 |
scanBarcode |
| NFC |
RFID读取 |
tagSession |
| 国密算法 |
电子签名 |
cryptoFramework SM2/SM3 |
| 通知 |
预警提醒 |
notificationManager |
| 打印 |
用印单打印 |
print |
| 分享 |
台账导出 |
share |
安全机制
| 层级 |
机制 |
说明 |
| 物理 |
双人双锁 |
保管人+副保管人 |
| 生物 |
指纹+人脸 |
用印验证 |
| 电子 |
国密签名 |
SM2/SM3电子签名 |
| 流程 |
多级审批 |
1-4级审批链 |
| 现场 |
拍照+GPS+监印 |
执行记录 |
| 外带 |
GPS追踪+定时回传 |
电子围栏 |
| 审计 |
不可篡改 |
区块链占位 |
龍魂标识
| 位置 |
内容 |
| 应用名称 |
龍魂印章管理 |
| 标题栏 |
🐉 龍魂印章管理 |
| 底部标识 |
来自龍魂印章管理 UID9622 |
| 数据签名 |
SM3-哈希 |
| DNA |
ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️ |
🐉 龍魂 · 鸿蒙 ArkTS 实战:Seal Usage Record 交付完成
DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️
UID: 9622
确认码: #CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z
时间: 2026-07-14 06:12
模块: 9核心文件
特性: 印章档案 · 用印申请 · 多级审批 · 现场执行 · 外带追踪 · GPS定位 · 国密签名 · 双人双锁 · 生物验证
所有评论(0)