fix: 子卷包装关系手动添加
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import BatchForm from './modules/batch-form.vue';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
@@ -26,6 +27,11 @@ const [FormModal, formModalApi] = useVbenModal({
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
const [BatchFormModal, batchFormModalApi] = useVbenModal({
|
||||
connectedComponent: BatchForm,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
@@ -36,6 +42,11 @@ function handleCreate() {
|
||||
formModalApi.setData(null).open();
|
||||
}
|
||||
|
||||
/** 批量创建子卷包装关系 */
|
||||
function handleBatchCreate() {
|
||||
batchFormModalApi.open();
|
||||
}
|
||||
|
||||
/** 编辑子卷包装关系 */
|
||||
function handleEdit(row: LmsSubPackageRelationApi.SubPackageRelation) {
|
||||
formModalApi.setData(row).open();
|
||||
@@ -127,6 +138,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<BatchFormModal @success="handleRefresh" />
|
||||
<Grid table-title="子卷包装关系列表">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
@@ -138,6 +150,13 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
auth: ['lms:sub-package-relation:create'],
|
||||
onClick: handleCreate,
|
||||
},
|
||||
{
|
||||
label: '批量新增',
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['lms:sub-package-relation:create'],
|
||||
onClick: handleBatchCreate,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.export'),
|
||||
type: 'primary',
|
||||
|
||||
@@ -121,12 +121,9 @@ describe('batch-form-model', () => {
|
||||
});
|
||||
|
||||
expect(result.rows).toEqual([rows[0], rows[2]]);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map([
|
||||
[rows[2]!.clientKey, '第三行失败'],
|
||||
[rows[0]!.clientKey, '第一行失败'],
|
||||
]),
|
||||
);
|
||||
expect(result.safe).toBe(true);
|
||||
expect(result.rowErrors.get(rows[0]!.clientKey)).toBe('第一行失败');
|
||||
expect(result.rowErrors.get(rows[2]!.clientKey)).toBe('第三行失败');
|
||||
});
|
||||
|
||||
it('falls back to one-based row index when the failure client key is unknown', () => {
|
||||
@@ -145,6 +142,7 @@ describe('batch-form-model', () => {
|
||||
});
|
||||
|
||||
expect(result.rows).toEqual([rows[1]]);
|
||||
expect(result.safe).toBe(true);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map([[rows[1]!.clientKey, '第二行失败']]),
|
||||
);
|
||||
@@ -167,6 +165,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -189,6 +188,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -212,6 +212,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -228,6 +229,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -249,6 +251,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -277,6 +280,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -299,6 +303,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -321,6 +326,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -343,6 +349,7 @@ describe('batch-form-model', () => {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
|
||||
expect(result.rows).toEqual(rows);
|
||||
expect(result.safe).toBe(false);
|
||||
expect(result.rowErrors).toEqual(
|
||||
new Map(rows.map((row) => [row.clientKey, generalError])),
|
||||
);
|
||||
@@ -355,6 +362,6 @@ describe('batch-form-model', () => {
|
||||
failures: [],
|
||||
});
|
||||
|
||||
expect(result).toEqual({ rows: [], rowErrors: new Map() });
|
||||
expect(result).toEqual({ rows: [], rowErrors: new Map(), safe: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,11 +79,16 @@ export function validateBatchRows(
|
||||
export function applyBatchResult(
|
||||
rows: BatchFormRow[],
|
||||
result: LmsSubPackageRelationApi.BatchCreateResult,
|
||||
): { rows: BatchFormRow[]; rowErrors: Map<string, string> } {
|
||||
): {
|
||||
rowErrors: Map<string, string>;
|
||||
rows: BatchFormRow[];
|
||||
safe: boolean;
|
||||
} {
|
||||
const generalError = '批量保存结果无法匹配,请核对后重试';
|
||||
const unsafeResult = () => ({
|
||||
rows,
|
||||
rowErrors: new Map(rows.map((item) => [item.clientKey, generalError])),
|
||||
safe: false,
|
||||
});
|
||||
const rowByClientKey = new Map<string, BatchFormRow>();
|
||||
for (const row of rows) {
|
||||
@@ -105,7 +110,7 @@ export function applyBatchResult(
|
||||
}
|
||||
|
||||
if (result.failures.length === 0) {
|
||||
return { rows: [], rowErrors: new Map() };
|
||||
return { rows: [], rowErrors: new Map(), safe: true };
|
||||
}
|
||||
|
||||
const failedClientKeys = new Set<string>();
|
||||
@@ -142,5 +147,6 @@ export function applyBatchResult(
|
||||
return {
|
||||
rows: rows.filter((row) => failedClientKeys.has(row.clientKey)),
|
||||
rowErrors,
|
||||
safe: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
<script lang="ts" setup>
|
||||
import type { BatchFieldErrors, BatchFormRow } from './batch-form-model';
|
||||
|
||||
import type { LmsBoxTypeApi } from '#/api/lms/boxtype';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
FormItem,
|
||||
Input,
|
||||
message,
|
||||
Segmented,
|
||||
Select,
|
||||
} from 'antdv-next';
|
||||
|
||||
import { batchCreateSubPackageRelation } from '#/api/lms/subpackagerelation';
|
||||
import BoxTypeSelectModalComponent from '#/views/lms/boxtype/components/BoxTypeSelectModal.vue';
|
||||
|
||||
import {
|
||||
applyBatchResult,
|
||||
copyBatchRow,
|
||||
createBatchRow,
|
||||
validateBatchRows,
|
||||
} from './batch-form-model';
|
||||
|
||||
const emit = defineEmits<{ success: [] }>();
|
||||
|
||||
const rows = ref<BatchFormRow[]>([createBatchRow()]);
|
||||
const viewMode = ref<'card' | 'table'>('table');
|
||||
const activeClientKey = ref<string>();
|
||||
const fieldErrors = ref(new Map<number, BatchFieldErrors>());
|
||||
const rowErrors = ref(new Map<string, string>());
|
||||
const resultUncertain = ref(false);
|
||||
const viewOptions = [
|
||||
{ label: '▤ 卡片', value: 'card' },
|
||||
{ label: '▦ 表格', value: 'table' },
|
||||
];
|
||||
|
||||
const statusOptions = computed(() =>
|
||||
getDictOptions(DICT_TYPE.SUB_PACKAGE_STATUS).map((item) => ({
|
||||
...item,
|
||||
value: String(item.value),
|
||||
})),
|
||||
);
|
||||
|
||||
function reset() {
|
||||
rows.value = [createBatchRow()];
|
||||
viewMode.value = 'table';
|
||||
activeClientKey.value = undefined;
|
||||
fieldErrors.value = new Map();
|
||||
rowErrors.value = new Map();
|
||||
resultUncertain.value = false;
|
||||
}
|
||||
|
||||
function clearErrors() {
|
||||
fieldErrors.value = new Map();
|
||||
}
|
||||
|
||||
function appendRow() {
|
||||
rows.value.push(createBatchRow());
|
||||
clearErrors();
|
||||
}
|
||||
|
||||
function duplicateRow(index: number) {
|
||||
rows.value.splice(index + 1, 0, copyBatchRow(rows.value[index]!));
|
||||
clearErrors();
|
||||
}
|
||||
|
||||
function removeRow(index: number) {
|
||||
const [removed] = rows.value.splice(index, 1);
|
||||
if (rows.value.length === 0) rows.value.push(createBatchRow());
|
||||
fieldErrors.value = new Map();
|
||||
if (removed) rowErrors.value.delete(removed.clientKey);
|
||||
}
|
||||
|
||||
function clearRows() {
|
||||
rows.value = [createBatchRow()];
|
||||
activeClientKey.value = undefined;
|
||||
fieldErrors.value = new Map();
|
||||
rowErrors.value = new Map();
|
||||
}
|
||||
|
||||
function editField(index: number, field: keyof BatchFormRow) {
|
||||
const errors = fieldErrors.value.get(index);
|
||||
if (errors?.[field]) {
|
||||
const next = { ...errors };
|
||||
delete next[field];
|
||||
const map = new Map(fieldErrors.value);
|
||||
Object.keys(next).length ? map.set(index, next) : map.delete(index);
|
||||
fieldErrors.value = map;
|
||||
}
|
||||
rowErrors.value.delete(rows.value[index]!.clientKey);
|
||||
}
|
||||
|
||||
function fieldError(index: number, field: keyof BatchFormRow) {
|
||||
return fieldErrors.value.get(index)?.[field];
|
||||
}
|
||||
|
||||
const [BoxTypeSelectModal, boxTypeSelectModalApi] = useVbenModal({
|
||||
connectedComponent: BoxTypeSelectModalComponent,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
function selectBoxType(clientKey: string) {
|
||||
activeClientKey.value = clientKey;
|
||||
boxTypeSelectModalApi.setData({ multiple: false }).open();
|
||||
}
|
||||
|
||||
function handleBoxTypeSelect(selectedRows: LmsBoxTypeApi.BoxType[]) {
|
||||
const index = rows.value.findIndex(
|
||||
(item) => item.clientKey === activeClientKey.value,
|
||||
);
|
||||
const selected = selectedRows[0];
|
||||
if (index < 0 || !selected) return;
|
||||
const row = rows.value[index]!;
|
||||
row.boxType = selected.boxType ?? '';
|
||||
row.boxLength = selected.boxLength == null ? '' : String(selected.boxLength);
|
||||
row.boxWidth = selected.boxWidth == null ? '' : String(selected.boxWidth);
|
||||
row.boxHigh = selected.boxHigh == null ? '' : String(selected.boxHigh);
|
||||
editField(index, 'boxType');
|
||||
activeClientKey.value = undefined;
|
||||
}
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (resultUncertain.value) {
|
||||
message.error('上次保存结果无法确认,请刷新列表核对后关闭弹窗');
|
||||
return;
|
||||
}
|
||||
const errors = validateBatchRows(rows.value);
|
||||
fieldErrors.value = errors;
|
||||
rowErrors.value = new Map();
|
||||
if (errors.size > 0) {
|
||||
message.warning('请检查必填项');
|
||||
return;
|
||||
}
|
||||
|
||||
modalApi.lock();
|
||||
try {
|
||||
const result = await batchCreateSubPackageRelation(rows.value);
|
||||
const applied = applyBatchResult(rows.value, result);
|
||||
if (result.successCount > 0) emit('success');
|
||||
if (!applied.safe) {
|
||||
rows.value = applied.rows;
|
||||
rowErrors.value = applied.rowErrors;
|
||||
fieldErrors.value = new Map();
|
||||
resultUncertain.value = true;
|
||||
message.error('保存结果无法确认,请刷新列表核对后关闭弹窗');
|
||||
return;
|
||||
}
|
||||
if (result.failureCount === 0) {
|
||||
await modalApi.close();
|
||||
message.success(`成功新增 ${result.successCount} 条子卷包装关系`);
|
||||
return;
|
||||
}
|
||||
rows.value = applied.rows;
|
||||
rowErrors.value = applied.rowErrors;
|
||||
fieldErrors.value = new Map();
|
||||
message.warning(
|
||||
`成功 ${result.successCount} 条,失败 ${result.failureCount} 条`,
|
||||
);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
if (isOpen) reset();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal title="自由切换批量新增" class="w-[1400px] max-w-[96vw]">
|
||||
<BoxTypeSelectModal @select="handleBoxTypeSelect" />
|
||||
<div class="batch-form">
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-actions">
|
||||
<Button type="primary" @click="appendRow">新增一行</Button>
|
||||
<Button class="clear-button" @click="clearRows">清空全部</Button>
|
||||
</div>
|
||||
<Segmented
|
||||
v-model:value="viewMode"
|
||||
class="view-switch"
|
||||
:options="viewOptions"
|
||||
aria-label="录入视图"
|
||||
/>
|
||||
<span class="record-counter">
|
||||
当前共 <strong>{{ rows.length }}</strong> 条记录
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Alert class="view-tip" type="info" show-icon>
|
||||
<template #message>
|
||||
{{
|
||||
viewMode === 'table'
|
||||
? '表格视图适合批量核对,可横向滚动查看全部字段。'
|
||||
: '卡片视图适合逐条录入和检查,切换后数据自动保留。'
|
||||
}}
|
||||
</template>
|
||||
<template #action>尺寸单位:mm</template>
|
||||
</Alert>
|
||||
|
||||
<div v-if="viewMode === 'table'" class="table-wrap">
|
||||
<table class="batch-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th><th><i>*</i> 木箱唯一码</th><th><i>*</i> 木箱类型</th>
|
||||
<th>木箱长</th><th>木箱宽</th><th>木箱高</th>
|
||||
<th><i>*</i> 保质期(天)</th><th><i>*</i> 入库日期</th><th><i>*</i> 子卷号</th>
|
||||
<th><i>*</i> 状态</th><th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(row, index) in rows" :key="row.clientKey">
|
||||
<tr>
|
||||
<td class="sequence">{{ index + 1 }}</td>
|
||||
<td><Input v-model:value="row.packageBoxSn" :class="{ invalid: fieldError(index, 'packageBoxSn') }" placeholder="请输入木箱唯一码" @update:value="editField(index, 'packageBoxSn')" /><small>{{ fieldError(index, 'packageBoxSn') }}</small></td>
|
||||
<td><Input :value="row.boxType" readonly role="button" tabindex="0" aria-label="选择木箱类型" :class="{ invalid: fieldError(index, 'boxType') }" placeholder="请选择木箱类型" @click="selectBoxType(row.clientKey)" @keydown.enter="selectBoxType(row.clientKey)" @keydown.space.prevent="selectBoxType(row.clientKey)" /><small>{{ fieldError(index, 'boxType') }}</small></td>
|
||||
<td><Input v-model:value="row.boxLength" readonly placeholder="自动带出" /></td>
|
||||
<td><Input v-model:value="row.boxWidth" readonly placeholder="自动带出" /></td>
|
||||
<td><Input v-model:value="row.boxHigh" readonly placeholder="自动带出" /></td>
|
||||
<td><Input v-model:value="row.qualityGuaranPeriod" :class="{ invalid: fieldError(index, 'qualityGuaranPeriod') }" placeholder="请输入保质期" @update:value="editField(index, 'qualityGuaranPeriod')" /><small>{{ fieldError(index, 'qualityGuaranPeriod') }}</small></td>
|
||||
<td><Input v-model:value="row.dateOfFgInbound" type="date" :class="{ invalid: fieldError(index, 'dateOfFgInbound') }" @update:value="editField(index, 'dateOfFgInbound')" /><small>{{ fieldError(index, 'dateOfFgInbound') }}</small></td>
|
||||
<td><Input v-model:value="row.containerName" :class="{ invalid: fieldError(index, 'containerName') }" placeholder="请输入子卷号" @update:value="editField(index, 'containerName')" /><small>{{ fieldError(index, 'containerName') }}</small></td>
|
||||
<td><Select v-model:value="row.status" :options="statusOptions" :class="{ invalid: fieldError(index, 'status') }" @change="editField(index, 'status')" /><small>{{ fieldError(index, 'status') }}</small></td>
|
||||
<td class="operations"><Button type="link" @click="duplicateRow(index)">复制</Button><Button type="link" danger @click="removeRow(index)">删除</Button></td>
|
||||
</tr>
|
||||
<tr v-if="rowErrors.get(row.clientKey)" class="row-error"><td colspan="11">第 {{ index + 1 }} 行:{{ rowErrors.get(row.clientKey) }}</td></tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-else class="card-list">
|
||||
<Card v-for="(row, index) in rows" :key="row.clientKey" size="small">
|
||||
<template #title>第 {{ index + 1 }} 条包装关系</template>
|
||||
<template #extra><Button type="link" @click="duplicateRow(index)">复制</Button><Button type="link" danger @click="removeRow(index)">删除</Button></template>
|
||||
<Alert v-if="rowErrors.get(row.clientKey)" type="error" show-icon :message="rowErrors.get(row.clientKey)" class="row-alert" />
|
||||
<div class="card-grid">
|
||||
<FormItem label="木箱唯一码" required :validate-status="fieldError(index, 'packageBoxSn') ? 'error' : undefined" :help="fieldError(index, 'packageBoxSn')"><Input v-model:value="row.packageBoxSn" @update:value="editField(index, 'packageBoxSn')" /></FormItem>
|
||||
<FormItem label="木箱类型" required :validate-status="fieldError(index, 'boxType') ? 'error' : undefined" :help="fieldError(index, 'boxType')"><Input :value="row.boxType" readonly role="button" tabindex="0" aria-label="选择木箱类型" placeholder="请选择木箱类型" @click="selectBoxType(row.clientKey)" @keydown.enter="selectBoxType(row.clientKey)" @keydown.space.prevent="selectBoxType(row.clientKey)" /></FormItem>
|
||||
<FormItem label="木箱长"><Input v-model:value="row.boxLength" readonly placeholder="自动带出" /></FormItem>
|
||||
<FormItem label="木箱宽"><Input v-model:value="row.boxWidth" readonly placeholder="自动带出" /></FormItem>
|
||||
<FormItem label="木箱高"><Input v-model:value="row.boxHigh" readonly placeholder="自动带出" /></FormItem>
|
||||
<FormItem label="保质期" required :validate-status="fieldError(index, 'qualityGuaranPeriod') ? 'error' : undefined" :help="fieldError(index, 'qualityGuaranPeriod')"><Input v-model:value="row.qualityGuaranPeriod" @update:value="editField(index, 'qualityGuaranPeriod')" /></FormItem>
|
||||
<FormItem label="入库日期" required :validate-status="fieldError(index, 'dateOfFgInbound') ? 'error' : undefined" :help="fieldError(index, 'dateOfFgInbound')"><Input v-model:value="row.dateOfFgInbound" type="date" @update:value="editField(index, 'dateOfFgInbound')" /></FormItem>
|
||||
<FormItem label="子卷号" required :validate-status="fieldError(index, 'containerName') ? 'error' : undefined" :help="fieldError(index, 'containerName')"><Input v-model:value="row.containerName" @update:value="editField(index, 'containerName')" /></FormItem>
|
||||
<FormItem label="状态" required :validate-status="fieldError(index, 'status') ? 'error' : undefined" :help="fieldError(index, 'status')"><Select v-model:value="row.status" :options="statusOptions" @change="editField(index, 'status')" /></FormItem>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.batch-form {
|
||||
display: flex;
|
||||
min-height: min(650px, calc(100vh - 230px));
|
||||
padding: 0 20px 18px;
|
||||
background: #f7f9fc;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
padding: 14px 6px;
|
||||
margin: 0 -6px 18px;
|
||||
background: hsl(var(--background));
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.toolbar-actions :deep(.ant-btn) {
|
||||
height: 36px;
|
||||
padding: 0 18px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.clear-button {
|
||||
color: #1677ff;
|
||||
background: #eef4ff;
|
||||
border-color: #cfe0ff;
|
||||
}
|
||||
|
||||
.view-switch {
|
||||
padding: 3px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.view-switch :deep(.ant-segmented-item) {
|
||||
min-width: 82px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.view-switch :deep(.ant-segmented-item-selected) {
|
||||
color: #1677ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.record-counter {
|
||||
color: hsl(var(--muted-foreground));
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.record-counter strong {
|
||||
margin: 0 4px;
|
||||
color: #1677ff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.view-tip {
|
||||
margin-bottom: 16px;
|
||||
border-color: #cfe0ff;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
flex: 1;
|
||||
min-height: 420px;
|
||||
overflow: auto;
|
||||
background: hsl(var(--background));
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.batch-table {
|
||||
width: 100%;
|
||||
min-width: 1780px;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.batch-table th,
|
||||
.batch-table td {
|
||||
padding: 10px;
|
||||
vertical-align: top;
|
||||
background: hsl(var(--background));
|
||||
border-right: 1px solid hsl(var(--border));
|
||||
border-bottom: 1px solid hsl(var(--border));
|
||||
}
|
||||
|
||||
.batch-table th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
height: 48px;
|
||||
color: #4b5870;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
background: #f3f6fb;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.batch-table th i {
|
||||
color: #ff4d4f;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.batch-table td {
|
||||
min-width: 145px;
|
||||
}
|
||||
|
||||
.batch-table :deep(.ant-input),
|
||||
.batch-table :deep(.ant-select-selector) {
|
||||
min-height: 36px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.batch-table :deep(.ant-input[readonly]) {
|
||||
color: #667085;
|
||||
background: #f2f4f7;
|
||||
}
|
||||
|
||||
.batch-table .sequence {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
min-width: 64px;
|
||||
color: #788196;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.batch-table th:first-child {
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
min-width: 64px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.batch-table th:last-child,
|
||||
.batch-table .operations {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
min-width: 128px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
box-shadow: -5px 0 12px rgb(21 35 62 / 6%);
|
||||
}
|
||||
|
||||
.batch-table th:last-child {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.batch-table small {
|
||||
display: block;
|
||||
min-height: 18px;
|
||||
margin-top: 2px;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
|
||||
.row-error td {
|
||||
color: #ff4d4f;
|
||||
background: #fff2f0;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
display: grid;
|
||||
flex: 1;
|
||||
align-content: start;
|
||||
gap: 16px;
|
||||
min-height: 420px;
|
||||
padding: 2px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.card-list :deep(.ant-card) {
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 8px rgb(23 32 51 / 4%);
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
column-gap: 24px;
|
||||
}
|
||||
|
||||
.card-grid :deep(.ant-input[readonly]) {
|
||||
color: #667085;
|
||||
background: #f2f4f7;
|
||||
}
|
||||
|
||||
.row-alert {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.toolbar {
|
||||
align-items: flex-start;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.record-counter {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user