Merge branch 'long-0507'

This commit is contained in:
2026-05-07 15:04:23 +08:00
7 changed files with 9807 additions and 19 deletions
+9731
View File
File diff suppressed because it is too large Load Diff
@@ -23,10 +23,10 @@
</div>
<div class="daily-matrix__toolbar-right">
<el-button :disabled="readOnly" type="primary" @click="openQuickAdd('blood')">+血糖</el-button>
<el-button :disabled="readOnly" @click="openQuickAdd('diet')">+饮食</el-button>
<el-button :disabled="readOnly" @click="openQuickAdd('exercise')">+运动</el-button>
<el-button :disabled="readOnly" @click="openQuickAdd('tracking')">+备注</el-button>
<el-button :disabled="!canEditDailyRecord" type="primary" @click="openQuickAdd('blood')">+血糖</el-button>
<el-button :disabled="!canEditDailyRecord" @click="openQuickAdd('diet')">+饮食</el-button>
<el-button :disabled="!canEditDailyRecord" @click="openQuickAdd('exercise')">+运动</el-button>
<el-button :disabled="!canEditDailyRecord" @click="openQuickAdd('tracking')">+备注</el-button>
<el-button @click="fetchTracking">刷新</el-button>
</div>
</div>
@@ -160,7 +160,7 @@
</el-form>
<template #footer>
<el-button @click="bloodDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="bloodSubmitting" @click="submitBlood">确定</el-button>
<el-button type="primary" :loading="bloodSubmitting" :disabled="!canEditDailyRecord" @click="submitBlood">确定</el-button>
</template>
</el-dialog>
@@ -202,7 +202,7 @@
</el-form>
<template #footer>
<el-button @click="dietDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="dietSubmitting" @click="submitDiet">确定</el-button>
<el-button type="primary" :loading="dietSubmitting" :disabled="!canEditDailyRecord" @click="submitDiet">确定</el-button>
</template>
</el-dialog>
@@ -247,7 +247,7 @@
</el-form>
<template #footer>
<el-button @click="exerciseDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="exerciseSubmitting" @click="submitExercise">确定</el-button>
<el-button type="primary" :loading="exerciseSubmitting" :disabled="!canEditDailyRecord" @click="submitExercise">确定</el-button>
</template>
</el-dialog>
@@ -385,6 +385,7 @@ interface TrackingNoteRecord {
type RangeMode = '7' | '30' | 'custom'
type DialogKind = 'blood' | 'diet' | 'exercise' | 'tracking'
const DAILY_RECORD_PERMS = ['tcm.diagnosis/dailyRecord']
const props = withDefaults(defineProps<Props>(), {
age: undefined,
@@ -396,7 +397,9 @@ const diagnosisId = computed(() => Number(props.diagnosisId || 0))
const patientId = computed(() => Number(props.patientId || 0))
const readOnly = computed(() => !!props.readOnly)
const patientName = computed(() => props.patientName || '')
const canViewTodoList = computed(() => hasPermission(['tcm.diagnosisTodo/lists']))
const hasDailyRecordPermission = computed(() => hasPermission(DAILY_RECORD_PERMS))
const canEditDailyRecord = computed(() => hasDailyRecordPermission.value && !readOnly.value)
const canViewTodoList = computed(() => hasDailyRecordPermission.value)
const loading = ref(false)
const rangeMode = ref<RangeMode>('7')
@@ -849,6 +852,7 @@ function handleCustomRangeChange() {
}
function openQuickAdd(kind: DialogKind) {
if (!canEditDailyRecord.value) return
const date = visibleDates.value[0] || formatDate(new Date())
if (kind === 'blood') {
bloodForm.value = createBloodForm(date)
@@ -876,7 +880,7 @@ function openQuickAdd(kind: DialogKind) {
}
function handleCellClick(metric: string, date: string) {
if (readOnly.value) return
if (!canEditDailyRecord.value) return
if (['fasting', 'postprandial', 'other', 'bp', 'western', 'insulin'].includes(metric)) {
const source = bloodByDate.value.get(date)
bloodForm.value = source ? { ...createBloodForm(date), ...source } : createBloodForm(date)
@@ -1014,7 +1018,7 @@ function getTrackingPreview(content: string) {
}
function isCellClickable(metric: string, date: string) {
if (readOnly.value) return false
if (!canEditDailyRecord.value) return false
if (metric !== 'tracking') return true
return date === todayDate.value || !!getTrackingContent(date)
}
@@ -3,9 +3,9 @@
<div class="toolbar">
<el-button
type="primary"
:disabled="!props.diagnosisId || !!props.readOnly"
:disabled="!props.diagnosisId || !!props.readOnly || !hasDailyRecordPermission"
@click="handleAdd"
v-perms="['tcm.diagnosisTodo/add']"
v-perms="DAILY_RECORD_PERMS"
>
+ 新增待办
</el-button>
@@ -55,7 +55,7 @@
link
type="danger"
@click="handleCancel(row)"
v-perms="['tcm.diagnosisTodo/cancel']"
v-perms="DAILY_RECORD_PERMS"
>
取消
</el-button>
@@ -114,8 +114,12 @@
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { diagnosisTodoLists, diagnosisTodoAdd, diagnosisTodoCancel } from '@/api/tcm'
import { computed } from 'vue'
import { hasPermission } from '@/utils/perm'
import feedback from '@/utils/feedback'
const DAILY_RECORD_PERMS = ['tcm.diagnosis/dailyRecord']
interface Props {
diagnosisId: number | null | undefined
patientId?: number | null
@@ -124,6 +128,7 @@ interface Props {
}
const props = defineProps<Props>()
const hasDailyRecordPermission = computed(() => hasPermission(DAILY_RECORD_PERMS))
// pager 与项目内 <pagination v-model="pager" /> 约定的字段保持一致
const pager = reactive({
@@ -137,7 +142,7 @@ const pager = reactive({
const filterStatus = ref<number | ''>('')
const fetchList = async () => {
if (!props.diagnosisId || Number(props.diagnosisId) <= 0) {
if (!props.diagnosisId || Number(props.diagnosisId) <= 0 || !hasDailyRecordPermission.value) {
pager.lists = []
pager.count = 0
return
@@ -221,7 +226,7 @@ const disablePastDate = (date: Date) => {
}
const handleAdd = () => {
if (!props.diagnosisId || props.readOnly) {
if (!props.diagnosisId || props.readOnly || !hasDailyRecordPermission.value) {
feedback.msgWarning('诊单未保存,无法添加待办')
return
}
@@ -260,6 +265,7 @@ const handleAddSubmit = async () => {
// ========== 取消 ==========
const handleCancel = async (row: any) => {
if (!hasDailyRecordPermission.value || props.readOnly) return
try {
await feedback.confirm(`确认取消「${row.remind_time_text} · ${truncate(row.content, 30)}」吗?`)
} catch {
+11 -1
View File
@@ -573,7 +573,13 @@
</div>
<el-empty v-else description="请先保存诊单后查看" />
</el-tab-pane>
<el-tab-pane label="日常记录" name="daily" :disabled="!formData.id" lazy>
<el-tab-pane
v-if="hasDailyRecordPermission"
label="日常记录"
name="daily"
:disabled="!formData.id"
lazy
>
<daily-matrix
v-if="formData.id"
:diagnosis-id="Number(formData.id)"
@@ -736,6 +742,7 @@ const submitting = ref(false)
/** 拥有后手机号可正常编辑,失焦不再强制脱敏 */
const hasPhonePlainPermission = computed(() => hasPermission(['tcm.diagnosis/phonePlain']))
const hasDailyRecordPermission = computed(() => hasPermission(['tcm.diagnosis/dailyRecord']))
/** 编辑且无明文权限:只读脱敏,点击切换查看完整号 */
const showPhoneMaskedEdit = computed(() => mode.value === 'edit' && !hasPhonePlainPermission.value)
const phoneRevealUnlocked = ref(false)
@@ -790,6 +797,9 @@ watch([visible, activeTab], () => {
if (activeTab.value === 'appointmentRecords' && !hasPermission(['doctor.appointment/lists'])) {
activeTab.value = 'basic'
}
if (activeTab.value === 'daily' && !hasDailyRecordPermission.value) {
activeTab.value = 'basic'
}
})
@@ -82,7 +82,7 @@ class AuthMiddleware
$AdminUris = $adminAuthCache->getAdminUri() ?? [];
$AdminUris = $this->formatUrl($AdminUris);
if (in_array($accessUri, $AdminUris)) {
if (in_array($accessUri, $AdminUris) || $this->matchPermissionAlias($accessUri, $AdminUris)) {
return $next($request);
}
return JsonService::fail('权限不足,无法访问或操作');
@@ -103,6 +103,25 @@ class AuthMiddleware
}, $data);
}
/**
* 日常记录权限域:前端统一收口到 tcm.diagnosis/dailyRecord
* 但待办/跟踪备注接口仍保留历史路由名,故在鉴权层做精确别名映射。
*/
private function matchPermissionAlias(string $accessUri, array $adminUris): bool
{
if (!in_array('tcm.diagnosis/dailyrecord', $adminUris, true)) {
return false;
}
return in_array($accessUri, [
'tcm.diagnosistodo/lists',
'tcm.diagnosistodo/add',
'tcm.diagnosistodo/cancel',
'tcm.diagnosis/trackingnotes',
'tcm.diagnosis/addtrackingnote',
], true);
}
/**
* 面诊进度专用:auth.admin/lists、doctor.appointment/lists + progress_board=1,不校验菜单权限
*/
@@ -118,4 +137,4 @@ class AuthMiddleware
return in_array($c, ['auth.admin', 'doctor.appointment'], true);
}
}
}
@@ -31,7 +31,8 @@ use app\common\model\tcm\DiagnosisTodo;
* cancel() → status=2 (已取消,仅 status=0 可取消)
*
* 鉴权:
* add:诊单需存在;数据权限交由路由层「tcm.diagnosisTodo/add」节点 + 前端 tab disabled 控制
* add:诊单需存在;数据权限交由路由层统一「tcm.diagnosis/dailyRecord」权限域控制
* 并兼容历史 diagnosisTodo/* 接口路由。
* cancel:仅创建人本人或超级管理员 (role_id=1) 可取消,且仅 status=0 时。
*
* @package app\adminapi\logic\tcm
@@ -0,0 +1,17 @@
# 2026-05-07
# (perms=tcm.diagnosis/lists)
# tcm.diagnosis/dailyRecord ////
SET @diag_menu_id := (SELECT id FROM zyt_system_menu WHERE perms = 'tcm.diagnosis/lists' LIMIT 1);
INSERT INTO zyt_system_menu (
pid, type, name, icon, sort, perms, paths, component,
selected, params, is_cache, is_show, is_disable, create_time, update_time
)
SELECT
@diag_menu_id, 'A', '日常记录', '', 59,
'tcm.diagnosis/dailyRecord', '', '',
'', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
FROM DUAL
WHERE @diag_menu_id IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.diagnosis/dailyRecord');