管理后台前后端逻辑、UI美化
This commit is contained in:
@@ -29,39 +29,69 @@
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.common.fields.site" prop="center_id" required>
|
||||
<el-select v-model="form.center_id" :disabled="isEdit" :placeholder="TEXT.common.placeholders.select" class="full-width">
|
||||
<el-select
|
||||
v-model="form.center_id"
|
||||
:disabled="isEdit || isReadOnly"
|
||||
:placeholder="TEXT.common.placeholders.select"
|
||||
class="full-width"
|
||||
>
|
||||
<el-option
|
||||
v-for="site in sites"
|
||||
:key="site.id"
|
||||
:label="site.name || TEXT.common.fallback"
|
||||
:value="site.id"
|
||||
:disabled="!site.is_active"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.contractAmount" prop="contract_amount" required>
|
||||
<el-input-number v-model="form.contract_amount" :min="0" :precision="2" :step="1000" class="full-width" controls-position="right" />
|
||||
<el-input-number
|
||||
v-model="form.contract_amount"
|
||||
:disabled="isReadOnly"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1000"
|
||||
class="full-width"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.contractCases" prop="contract_cases" required>
|
||||
<el-input-number v-model="form.contract_cases" :min="0" :step="1" class="full-width" controls-position="right" />
|
||||
<el-input-number v-model="form.contract_cases" :disabled="isReadOnly" :min="0" :step="1" class="full-width" controls-position="right" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.actualCases" prop="actual_cases">
|
||||
<el-input-number v-model="form.actual_cases" :min="0" :step="1" class="full-width" controls-position="right" />
|
||||
<el-input-number v-model="form.actual_cases" :disabled="isReadOnly" :min="0" :step="1" class="full-width" controls-position="right" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.settlementAmount" prop="settlement_amount">
|
||||
<el-input-number v-model="form.settlement_amount" :min="0" :precision="2" :step="1000" class="full-width" controls-position="right" />
|
||||
<el-input-number
|
||||
v-model="form.settlement_amount"
|
||||
:disabled="isReadOnly"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1000"
|
||||
class="full-width"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.finalPaymentAmount" prop="final_payment_amount">
|
||||
<el-input-number v-model="form.final_payment_amount" :min="0" :precision="2" :step="1000" class="full-width" controls-position="right" />
|
||||
<el-input-number
|
||||
v-model="form.final_payment_amount"
|
||||
:disabled="isReadOnly"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1000"
|
||||
class="full-width"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -71,7 +101,7 @@
|
||||
<template #header>
|
||||
<div class="card-header actions-header">
|
||||
<span class="header-title">{{ TEXT.modules.feeContracts.paymentTitle }}</span>
|
||||
<el-button type="primary" @click="addPayment">
|
||||
<el-button type="primary" :disabled="isReadOnly" @click="addPayment">
|
||||
<el-icon class="el-icon--left"><Plus /></el-icon>
|
||||
{{ TEXT.common.actions.add }}
|
||||
</el-button>
|
||||
@@ -90,7 +120,7 @@
|
||||
<span class="seq-circle">{{ index + 1 }}</span>
|
||||
<span class="seq-text">{{ TEXT.modules.feeContracts.paymentSeqUnit }}</span>
|
||||
</div>
|
||||
<el-button link type="danger" @click="removePayment(index)">
|
||||
<el-button link type="danger" :disabled="isReadOnly" @click="removePayment(index)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -98,13 +128,13 @@
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="TEXT.common.fields.amount" :error="paymentErrors[index]?.amount">
|
||||
<el-input-number v-model="payment.amount" :min="0" :precision="2" class="full-width" controls-position="right" />
|
||||
<el-input-number v-model="payment.amount" :disabled="isReadOnly" :min="0" :precision="2" class="full-width" controls-position="right" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.paidFlag" :error="paymentErrors[index]?.paid_date">
|
||||
<div class="status-control">
|
||||
<el-checkbox v-model="payment.is_paid" @change="() => onPaidToggle(payment)">
|
||||
<el-checkbox v-model="payment.is_paid" :disabled="isReadOnly" @change="() => onPaidToggle(payment)">
|
||||
{{ TEXT.modules.feeContracts.isPaid }}
|
||||
</el-checkbox>
|
||||
<el-date-picker
|
||||
@@ -113,6 +143,7 @@
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
:placeholder="TEXT.common.placeholders.select"
|
||||
:disabled="isReadOnly"
|
||||
class="status-picker"
|
||||
size="small"
|
||||
/>
|
||||
@@ -122,7 +153,7 @@
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="TEXT.modules.feeContracts.verifiedFlag" :error="paymentErrors[index]?.verified_date">
|
||||
<div class="status-control">
|
||||
<el-checkbox v-model="payment.is_verified" @change="() => onVerifiedToggle(payment)">
|
||||
<el-checkbox v-model="payment.is_verified" :disabled="isReadOnly" @change="() => onVerifiedToggle(payment)">
|
||||
{{ TEXT.modules.feeContracts.isVerified }}
|
||||
</el-checkbox>
|
||||
<el-date-picker
|
||||
@@ -131,6 +162,7 @@
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
:placeholder="TEXT.common.placeholders.select"
|
||||
:disabled="isReadOnly"
|
||||
class="status-picker"
|
||||
size="small"
|
||||
/>
|
||||
@@ -140,7 +172,7 @@
|
||||
</el-row>
|
||||
|
||||
<el-form-item :label="TEXT.common.fields.remark" class="mb-0">
|
||||
<el-input v-model="payment.remark" type="textarea" :rows="2" :placeholder="TEXT.common.placeholders.input" />
|
||||
<el-input v-model="payment.remark" :disabled="isReadOnly" type="textarea" :rows="2" :placeholder="TEXT.common.placeholders.input" />
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="paymentErrors[index]?.verification" class="payment-error">
|
||||
@@ -162,6 +194,7 @@
|
||||
:entity-type="'contract_fee'"
|
||||
:entity-id="form.id"
|
||||
:groups="attachmentGroups"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
|
||||
<StateEmpty v-else :description="TEXT.modules.feeContracts.uploadHint" class="compact-empty" />
|
||||
@@ -169,7 +202,7 @@
|
||||
|
||||
<div class="footer-actions">
|
||||
<el-button @click="goBack">{{ TEXT.common.actions.cancel }}</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="submit" class="save-btn">
|
||||
<el-button type="primary" :loading="saving" :disabled="isReadOnly" @click="submit" class="save-btn">
|
||||
{{ TEXT.common.actions.save }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -207,6 +240,14 @@ const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const errorMessage = ref("");
|
||||
const sites = ref<any[]>([]);
|
||||
const siteActiveMap = computed(() => {
|
||||
const map: Record<string, boolean> = {};
|
||||
sites.value.forEach((site) => {
|
||||
if (site?.id) map[site.id] = !!site.is_active;
|
||||
});
|
||||
return map;
|
||||
});
|
||||
const isReadOnly = computed(() => isEdit.value && !!form.center_id && siteActiveMap.value[form.center_id] === false);
|
||||
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
@@ -302,6 +343,10 @@ const loadDetail = async () => {
|
||||
};
|
||||
|
||||
const addPayment = () => {
|
||||
if (isReadOnly.value) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
payments.value.push({
|
||||
tempId: `${Date.now()}-${Math.random()}`,
|
||||
amount: 0,
|
||||
@@ -314,6 +359,10 @@ const addPayment = () => {
|
||||
};
|
||||
|
||||
const removePayment = (index: number) => {
|
||||
if (isReadOnly.value) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
const payment = payments.value[index];
|
||||
if (payment?.id) {
|
||||
removedPaymentIds.value.push(payment.id);
|
||||
@@ -322,6 +371,7 @@ const removePayment = (index: number) => {
|
||||
};
|
||||
|
||||
const onPaidToggle = (payment: any) => {
|
||||
if (isReadOnly.value) return;
|
||||
if (!payment.is_paid) {
|
||||
payment.paid_date = "";
|
||||
payment.is_verified = false;
|
||||
@@ -330,6 +380,7 @@ const onPaidToggle = (payment: any) => {
|
||||
};
|
||||
|
||||
const onVerifiedToggle = (payment: any) => {
|
||||
if (isReadOnly.value) return;
|
||||
if (payment.is_verified && !payment.is_paid) {
|
||||
payment.is_paid = true;
|
||||
}
|
||||
@@ -367,6 +418,14 @@ const validatePayments = () => {
|
||||
|
||||
const submit = async () => {
|
||||
if (!study.currentStudy?.id) return;
|
||||
if (isReadOnly.value) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
if (form.center_id && siteActiveMap.value[form.center_id] === false) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
const formOk = await formRef.value?.validate?.().catch(() => false);
|
||||
if (!formOk) return;
|
||||
if (!validatePayments()) {
|
||||
|
||||
Reference in New Issue
Block a user