docs: reorganize architecture strategy documentation

Split current project diagnostics into a dedicated analysis document and
trim the main architecture strategy to focus on core guidance. This makes
the documentation easier to navigate and separates observed issues from
recommended architectural principles.docs: reorganize architecture strategy documentation

Split current project diagnostics into a dedicated analysis document and
trim the main architecture strategy to focus on core guidance. This makes
the documentation easier to navigate and separates observed issues from
recommended architectural principles.
This commit is contained in:
skytek_xinliang
2026-05-19 14:13:10 +08:00
parent 9ae91418e0
commit 96b96bcaaa
12 changed files with 1373 additions and 1077 deletions
+125
View File
@@ -0,0 +1,125 @@
import { nextTick, type Ref } from 'vue'
interface UseCrudCommandsOptions<TRecord extends { id: number }, TPayload> {
clearAllErrors: () => void
dialogMode: Ref<'create' | 'edit' | 'view'>
dialogVisible: Ref<boolean>
editingId: Ref<number | null>
fieldErrors: Ref<Record<string, string[]>>
form: Ref<TPayload>
highlightedId: Ref<number | null>
isDirty: Readonly<Ref<boolean>>
isLoading: Ref<boolean>
isSaving: Ref<boolean>
isViewMode: Readonly<Ref<boolean>>
loadDelay?: number
loadSequence: Ref<number>
resetForm: () => void
saveDelay?: number
scrollToField: (field: string) => void
setForm: (payload: TPayload) => void
syncInitialForm: () => void
toFormPayload: (record: TRecord) => TPayload
toSavePayload: (form: TPayload) => TPayload
updateRecord: (id: number, payload: TPayload) => unknown
createRecord: (payload: TPayload) => number
validateForm: () => Array<{ field: string; message: string }>
}
export function useCrudCommands<TRecord extends { id: number }, TPayload>(
options: UseCrudCommandsOptions<TRecord, TPayload>
) {
function openAddDialog() {
options.loadSequence.value += 1
options.dialogMode.value = 'create'
options.editingId.value = null
options.resetForm()
options.isLoading.value = false
options.dialogVisible.value = true
}
function loadRecord(record: TRecord, mode: 'edit' | 'view') {
options.loadSequence.value += 1
const sequence = options.loadSequence.value
options.dialogMode.value = mode
options.editingId.value = record.id
options.dialogVisible.value = true
options.isLoading.value = true
options.clearAllErrors()
window.setTimeout(() => {
if (sequence !== options.loadSequence.value || !options.dialogVisible.value) return
options.setForm(options.toFormPayload(record))
options.syncInitialForm()
options.isLoading.value = false
}, options.loadDelay ?? 350)
}
function openEditDialog(record: TRecord) {
loadRecord(record, 'edit')
}
function openViewDialog(record: TRecord) {
loadRecord(record, 'view')
}
async function requestSaveConfirmation(confirmSaveVisible: Ref<boolean>) {
if (
options.isSaving.value ||
options.isLoading.value ||
!options.isDirty.value ||
options.isViewMode.value
) {
return
}
options.clearAllErrors()
const errors = options.validateForm()
if (errors.length > 0) {
for (const error of errors) {
options.fieldErrors.value[error.field] = [error.message]
}
await nextTick()
const firstError = errors[0]
if (firstError) options.scrollToField(firstError.field)
return
}
confirmSaveVisible.value = true
}
function confirmSave(confirmSaveVisible: Ref<boolean>) {
confirmSaveVisible.value = false
return saveRecord()
}
async function saveRecord() {
if (options.isSaving.value || options.isLoading.value) return
options.isSaving.value = true
await new Promise((resolve) => window.setTimeout(resolve, options.saveDelay ?? 450))
const payload = options.toSavePayload(options.form.value)
if (options.editingId.value) {
const updated = options.updateRecord(options.editingId.value, payload)
if (updated) options.highlightedId.value = options.editingId.value
} else {
const createdId = options.createRecord(payload)
options.highlightedId.value = createdId
}
options.syncInitialForm()
options.dialogVisible.value = false
options.isSaving.value = false
window.setTimeout(() => {
options.highlightedId.value = null
}, 1600)
}
return {
confirmSave,
openAddDialog,
openEditDialog,
openViewDialog,
requestSaveConfirmation,
saveRecord,
}
}