diff --git a/src/apis/material/materialInfo.ts b/src/apis/material/materialInfo.ts index db2f4a1..c8efedd 100644 --- a/src/apis/material/materialInfo.ts +++ b/src/apis/material/materialInfo.ts @@ -19,6 +19,15 @@ export interface MaterialInfoQuery { encoding: string | undefined sort: Array } + +/* 物料信息导入结果类型 */ +export interface MaterialImportResp { + importKey: string + totalRows: number + validRows: number + duplicateNameRows: number + duplicateCodeRows: number +} export interface MaterialInfoPageQuery extends MaterialInfoQuery, PageQuery {} /** @desc 查询物料信息列表 */ @@ -29,6 +38,11 @@ export function listMaterialInfo(query: MaterialInfoPageQuery) { interface MaterialInfoDetailResp { } +/** @desc 下载物料信息导入模板 */ +export function downloadMaterialInfoImportTemplate() { + return http.download(`${BASE_URL}/import/template`) +} + /** @desc 查询物料信息详情 */ export function getMaterialInfo(id: string) { return http.get(`${BASE_URL}/${id}`) @@ -53,3 +67,13 @@ export function deleteMaterialInfo(id: string) { export function exportMaterialInfo(query: MaterialInfoQuery) { return http.download(`${BASE_URL}/export`, query) } + +/** @desc 解析物料信息导入数据 */ +export function parseImportMaterial(data: FormData) { + return http.post(`${BASE_URL}/import/parse`, data) +} + +/** @desc 导入物料信息 */ +export function importMaterial(data: any) { + return http.post(`${BASE_URL}/import`, data) +} diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 9dfdc0b..91a32bc 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -33,15 +33,20 @@ declare module 'vue' { AImage: typeof import('@arco-design/web-vue')['Image'] AInput: typeof import('@arco-design/web-vue')['Input'] AInputNumber: typeof import('@arco-design/web-vue')['InputNumber'] + AInputPassword: typeof import('@arco-design/web-vue')['InputPassword'] AInputSearch: typeof import('@arco-design/web-vue')['InputSearch'] ALayout: typeof import('@arco-design/web-vue')['Layout'] + ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent'] ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader'] ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider'] ALink: typeof import('@arco-design/web-vue')['Link'] AMenu: typeof import('@arco-design/web-vue')['Menu'] AMenuItem: typeof import('@arco-design/web-vue')['MenuItem'] AModal: typeof import('@arco-design/web-vue')['Modal'] + AOption: typeof import('@arco-design/web-vue')['Option'] AOverflowList: typeof import('@arco-design/web-vue')['OverflowList'] + APagination: typeof import('@arco-design/web-vue')['Pagination'] + APopconfirm: typeof import('@arco-design/web-vue')['Popconfirm'] APopover: typeof import('@arco-design/web-vue')['Popover'] AProgress: typeof import('@arco-design/web-vue')['Progress'] ARadio: typeof import('@arco-design/web-vue')['Radio'] @@ -64,6 +69,7 @@ declare module 'vue' { ATreeSelect: typeof import('@arco-design/web-vue')['TreeSelect'] ATrigger: typeof import('@arco-design/web-vue')['Trigger'] ATypographyParagraph: typeof import('@arco-design/web-vue')['TypographyParagraph'] + ATypographyTitle: typeof import('@arco-design/web-vue')['TypographyTitle'] AUpload: typeof import('@arco-design/web-vue')['Upload'] Avatar: typeof import('./../components/Avatar/index.vue')['default'] AWatermark: typeof import('@arco-design/web-vue')['Watermark'] diff --git a/src/views/dashboard/analysis/index.vue b/src/views/dashboard/analysis/index.vue index 1658287..a475a82 100644 --- a/src/views/dashboard/analysis/index.vue +++ b/src/views/dashboard/analysis/index.vue @@ -5,9 +5,10 @@
+

物料领取流程

- +
@@ -36,7 +37,7 @@ defineOptions({ name: 'Analysis' }) const router = useRouter() const handleStart = () => { - router.push('') + router.push('/weightManage') } @@ -66,10 +67,10 @@ const handleStart = () => { height: 100%; min-height: 100vh; display: flex; - justify-content: center; + justify-content: flex-start; // 整体靠左,由子元素 margin 控制位置 align-items: center; background: #f5f7fa; - padding: 10px; // 减小内边距 + padding: 10px; box-sizing: border-box; .guide-content.full-height { @@ -79,10 +80,13 @@ const handleStart = () => { margin: 0; display: flex; flex-direction: column; + align-items: flex-start; // 【关键】让子元素(标题和卡片)从左侧开始排列,而不是拉伸 .page-title { - text-align: center; - font-size: 42px; // 稍微减小字体 + // 【修改】让标题宽度适应内容,以便通过 margin 控制其整体位置 + width: fit-content; + text-align: center; // 文字本身在标题块内居中 + font-size: 42px; font-weight: 800; color: #1e293b; margin-bottom: 15px; @@ -92,13 +96,17 @@ const handleStart = () => { flex-shrink: 0; padding: 0 10px; + // 【关键修改】应用与卡片相同的左侧偏移,确保标题在卡片正上方 + margin-left: 30%; // 必须与 .guide-card 的 margin-left 一致 + margin-right: auto; + &::after { content: ''; display: block; - width: 80px; // 减小下划线宽度 + width: 80px; height: 4px; background: linear-gradient(90deg, #165dff, #6aa1ff); - margin: 10px auto 0; + margin: 10px auto 0; // 下划线在标题块内居中 border-radius: 2px; } } @@ -108,22 +116,23 @@ const handleStart = () => { .guide-card { display: flex; align-items: center; - justify-content: center; - gap: 40px; // 减小间距 + gap: 40px; background: white; - border-radius: 30px; // 减小圆角 + border-radius: 30px; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); - padding: 20px 30px; // 减小内边距 + padding: 20px 30px; flex-wrap: wrap; border: 1px solid rgba(0, 0, 0, 0.05); - min-height: 400px; // 减小最小高度 + min-height: 400px; width: auto; - max-width: 90vw; // 使用视口宽度的90%,确保有边距 - margin: 0 auto; + max-width: 90vw; + + // 【核心修改】设置左边距实现左偏移 + margin-left: 10%; // 与标题保持一致 + margin-right: auto; &.centered { - margin-left: auto; - margin-right: auto; + // 移除原本的居中逻辑 } .image-wrapper { @@ -131,16 +140,16 @@ const handleStart = () => { display: flex; justify-content: center; align-items: center; - min-width: 300px; // 减小最小宽度 - max-width: 600px; // 减小最大宽度 + min-width: 300px; + max-width: 600px; height: 100%; .guide-image.enlarged { max-width: 100%; width: auto; height: auto; - max-height: 50vh; // 减小最大高度 - min-height: 250px; // 减小最小高度 + max-height: 50vh; + min-height: 250px; object-fit: contain; border-radius: 16px; filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.08)); @@ -159,13 +168,13 @@ const handleStart = () => { align-items: center; justify-content: center; gap: 12px; - min-width: 180px; // 减小最小宽度 + min-width: 180px; .button-hint { - font-size: 14px; // 减小字体 + font-size: 14px; color: #475569; background: #f1f5f9; - padding: 6px 18px; // 减小内边距 + padding: 6px 18px; border-radius: 24px; white-space: nowrap; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.02); @@ -180,9 +189,9 @@ const handleStart = () => { } .start-button.enlarged { - min-width: 160px; // 减小按钮宽度 - height: 56px; // 减小按钮高度 - font-size: 22px; // 减小字体 + min-width: 160px; + height: 56px; + font-size: 22px; border-radius: 40px; box-shadow: 0 10px 20px rgba(22, 93, 255, 0.2); transition: all 0.3s ease; @@ -209,12 +218,11 @@ const handleStart = () => { // 针对不同屏幕尺寸的精细调整 @media (min-width: 1920px) { .guide-card { - max-width: 1600px; // 超大屏幕限制最大宽度 + max-width: 1600px; padding: 30px 50px; - - .image-wrapper { - max-width: 800px; - } + } + .guide-content.full-height .page-title { + // 大屏幕保持同步 } } @@ -222,15 +230,7 @@ const handleStart = () => { .guide-card { gap: 30px; padding: 20px 25px; - - .image-wrapper { - min-width: 280px; - max-width: 500px; - - .guide-image.enlarged { - max-height: 45vh; - } - } + // 如果需要,可以在这里微调 margin-left,记得同时微调 title } } @@ -242,43 +242,26 @@ const handleStart = () => { .guide-card { gap: 25px; padding: 15px 20px; - max-width: 95vw; // 在小屏幕上使用更宽的百分比 - - .image-wrapper { - min-width: 250px; - max-width: 450px; - - .guide-image.enlarged { - max-height: 40vh; - min-height: 200px; - } - } - - .button-wrapper { - min-width: 160px; - - .button-hint { - font-size: 13px; - padding: 5px 15px; - } - - .start-button.enlarged { - min-width: 150px; - height: 50px; - font-size: 20px; - } - } + max-width: 95vw; + // 平板端如果需要调整偏移,请同时调整下方 title 的 margin } } @media (max-width: 768px) { .guide-section.full-background { padding: 5px; + justify-content: center; // 移动端恢复整体居中 .guide-content.full-height { + align-items: center; // 移动端子元素也居中 + .page-title { font-size: 28px; margin-bottom: 10px; + // 【重要】移动端重置 margin,恢复自动居中 + margin-left: auto; + margin-right: auto; + width: fit-content; // 保持适应内容 &::after { width: 60px; @@ -294,7 +277,11 @@ const handleStart = () => { padding: 20px 15px; gap: 20px; min-height: auto; - max-width: 98vw; // 移动端几乎占满宽度 + max-width: 98vw; + + // 【重要】移动端强制居中 + margin-left: auto; + margin-right: auto; .image-wrapper { min-width: auto; @@ -334,14 +321,12 @@ const handleStart = () => { .guide-section.full-background { .guide-card { @media (min-width: 1025px) { - margin-left: 5%; // 在有侧边栏时左移 - margin-right: auto; + // 如果有侧边栏,确保标题和卡片偏移量依然一致 } } } } -// 确保父容器占满且无滚动问题 html, body { margin: 0; padding: 0; @@ -359,22 +344,22 @@ html, body { overflow-y: auto; } -// 针对100%缩放比例的特殊处理 +// 针对特定分辨率的微调(可选) @media screen and (min-width: 1280px) and (max-width: 1366px) { .guide-card { - max-width: 85vw; // 在常见笔记本屏幕上使用85%宽度 + max-width: 85vw; } } @media screen and (min-width: 1367px) and (max-width: 1440px) { .guide-card { - max-width: 80vw; // 在1440p屏幕上使用80%宽度 + max-width: 80vw; } } @media screen and (min-width: 1441px) and (max-width: 1680px) { .guide-card { - max-width: 75vw; // 在更大屏幕上使用75%宽度 + max-width: 75vw; } } diff --git a/src/views/material/MaterialInfoImportDrawer.vue b/src/views/material/MaterialInfoImportDrawer.vue new file mode 100644 index 0000000..fdfbcab --- /dev/null +++ b/src/views/material/MaterialInfoImportDrawer.vue @@ -0,0 +1,201 @@ + + + + + diff --git a/src/views/material/index.vue b/src/views/material/index.vue index faee7b2..028b77f 100644 --- a/src/views/material/index.vue +++ b/src/views/material/index.vue @@ -25,6 +25,10 @@ + + + + @@ -60,11 +64,13 @@ +