up
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 22" width="20" height="14">
|
||||||
|
<!-- 红色背景 -->
|
||||||
|
<rect width="33" height="22" fill="#de2910"/>
|
||||||
|
<!-- 大五角星 -->
|
||||||
|
<polygon points="5,1 6.5,4.5 10,4.5 7.5,6.8 8.5,10.5 5,8 1.5,10.5 2.5,6.8 0,4.5 3.5,4.5" fill="#ffde00"/>
|
||||||
|
<!-- 四颗小五角星 -->
|
||||||
|
<polygon points="10,3 10.6,4.3 12,4.3 11,5.2 11.4,6.6 10,5.7 8.6,6.6 9,5.2 8,4.3 9.4,4.3" fill="#ffde00"/>
|
||||||
|
<polygon points="13,1 13.6,2.3 15,2.3 14,3.2 14.4,4.6 13,3.7 11.6,4.6 12,3.2 11,2.3 12.4,2.3" fill="#ffde00"/>
|
||||||
|
<polygon points="15,3 15.6,4.3 17,4.3 16,5.2 16.4,6.6 15,5.7 13.6,6.6 14,5.2 13,4.3 14.4,4.3" fill="#ffde00"/>
|
||||||
|
<polygon points="12.5,5 13.1,6.3 14.5,6.3 13.5,7.2 13.9,8.6 12.5,7.7 11.1,8.6 11.5,7.2 10.5,6.3 11.9,6.3" fill="#ffde00"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 785 B |
@@ -0,0 +1,16 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 22" width="20" height="14">
|
||||||
|
<!-- 红色背景 -->
|
||||||
|
<rect width="33" height="22" fill="#de2910"/>
|
||||||
|
<!-- 白色条带 -->
|
||||||
|
<rect y="7" width="33" height="8" fill="#fff"/>
|
||||||
|
<!-- 紫荆花(简化版) -->
|
||||||
|
<g fill="#fff" transform="translate(6.6,11) scale(0.4)">
|
||||||
|
<ellipse cx="0" cy="-8" rx="4" ry="8" fill="#fff"/>
|
||||||
|
<ellipse cx="7.6" cy="-2.5" rx="4" ry="8" fill="#fff" transform="rotate(72)"/>
|
||||||
|
<ellipse cx="4.7" cy="6.5" rx="4" ry="8" fill="#fff" transform="rotate(144)"/>
|
||||||
|
<ellipse cx="-4.7" cy="6.5" rx="4" ry="8" fill="#fff" transform="rotate(216)"/>
|
||||||
|
<ellipse cx="-7.6" cy="-2.5" rx="4" ry="8" fill="#fff" transform="rotate(288)"/>
|
||||||
|
<!-- 花芯 -->
|
||||||
|
<circle cx="0" cy="0" r="3" fill="#ffdf00"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 799 B |
@@ -0,0 +1,14 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 22" width="20" height="14">
|
||||||
|
<!-- 绿色背景 -->
|
||||||
|
<rect width="33" height="22" fill="#009900"/>
|
||||||
|
<!-- 莲花(简化版) -->
|
||||||
|
<g fill="#fff" transform="translate(16.5,11)">
|
||||||
|
<ellipse cx="0" cy="-5" rx="2" ry="5"/>
|
||||||
|
<ellipse cx="-4" cy="-2" rx="2" ry="5" transform="rotate(-30)"/>
|
||||||
|
<ellipse cx="4" cy="-2" rx="2" ry="5" transform="rotate(30)"/>
|
||||||
|
<ellipse cx="-6" cy="2" rx="2" ry="5" transform="rotate(-60)"/>
|
||||||
|
<ellipse cx="6" cy="2" rx="2" ry="5" transform="rotate(60)"/>
|
||||||
|
<!-- 莲蓬 -->
|
||||||
|
<circle cx="0" cy="0" r="2.5" fill="#ffdf00"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 637 B |
@@ -0,0 +1,19 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 22" width="20" height="14">
|
||||||
|
<!-- 红色条纹 -->
|
||||||
|
<rect y="0" width="33" height="2.75" fill="#b22234"/>
|
||||||
|
<rect y="5.5" width="33" height="2.75" fill="#fff"/>
|
||||||
|
<rect y="8.25" width="33" height="2.75" fill="#b22234"/>
|
||||||
|
<rect y="11" width="33" height="2.75" fill="#fff"/>
|
||||||
|
<rect y="13.75" width="33" height="2.75" fill="#b22234"/>
|
||||||
|
<rect y="16.5" width="33" height="2.75" fill="#fff"/>
|
||||||
|
<rect y="19.25" width="33" height="2.75" fill="#b22234"/>
|
||||||
|
<!-- 蓝色矩形(左上角) -->
|
||||||
|
<rect width="13.2" height="8.25" fill="#3c3b6e"/>
|
||||||
|
<!-- 50颗白星(简化:画5x5网格白点) -->
|
||||||
|
<g fill="#fff">
|
||||||
|
<circle cx="2.2" cy="1.1" r="0.7"/>
|
||||||
|
<circle cx="6.6" cy="1.1" r="0.7"/>
|
||||||
|
<circle cx="2.2" cy="4.4" r="0.7"/>
|
||||||
|
<circle cx="6.6" cy="4.4" r="0.7"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 847 B |
@@ -223,216 +223,145 @@ defineExpose({
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div id="custom-template" style="display: none">
|
<div id="custom-template" style="display: none">
|
||||||
<div class="dz-preview dz-file-preview my-custom-style">
|
<div class="dz-preview dz-file-preview">
|
||||||
<div class="remove-btn" data-dz-remove>
|
<div data-dz-remove class="dz-remove">✕</div>
|
||||||
<!-- <i class="bi bi-x"></i> -->
|
<div class="dz-image"><img data-dz-thumbnail alt="" /></div>
|
||||||
X
|
|
||||||
</div>
|
|
||||||
<div class="dz-image">
|
|
||||||
<img data-dz-thumbnail alt="File preview" />
|
|
||||||
<!-- 缩略图 -->
|
|
||||||
</div>
|
|
||||||
<div class="dz-details">
|
<div class="dz-details">
|
||||||
<div class="dz-filename"><span data-dz-name></span></div>
|
<div class="dz-filename"><span data-dz-name></span></div>
|
||||||
<!-- 文件名 -->
|
|
||||||
<div class="dz-size"><span data-dz-size></span></div>
|
<div class="dz-size"><span data-dz-size></span></div>
|
||||||
<!-- 文件大小 -->
|
|
||||||
</div>
|
|
||||||
<div class="dz-progress">
|
|
||||||
<span class="dz-upload" data-dz-uploadprogress></span>
|
|
||||||
<!-- 进度条 -->
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
||||||
<div class="dz-success-mark" data-dz-successmark>
|
<div class="dz-success-mark" data-dz-successmark>
|
||||||
<svg
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="#22c55e" stroke="#22c55e" stroke-width="3">
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<path d="M9 12l2 2l4 -4" stroke="none"/>
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
class="icon icon-tabler icons-tabler-outline icon-tabler-circle-check"
|
|
||||||
>
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
|
||||||
<path d="M9 12l2 2l4 -4" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<!-- 成功标记 -->
|
|
||||||
<div class="dz-error-mark" data-dz-errormark>
|
<div class="dz-error-mark" data-dz-errormark>
|
||||||
<svg
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="#ef4444" stroke="#ef4444" stroke-width="3">
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<path d="M10 10l4 4m0 -4l-4 4" stroke="none"/>
|
||||||
width="240"
|
|
||||||
height="240"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
class="icon icon-tabler icons-tabler-outline icon-tabler-circle-x"
|
|
||||||
>
|
|
||||||
<path stroke="none" fill="none" d="M0 0h24v24H0z" />
|
|
||||||
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
|
||||||
<path d="M10 10l4 4m0 -4l-4 4" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<!-- 错误标记 -->
|
|
||||||
<div class="dz-error-message"><span data-dz-errormessage></span></div>
|
<div class="dz-error-message"><span data-dz-errormessage></span></div>
|
||||||
<!-- 错误信息 -->
|
|
||||||
|
|
||||||
<!-- 移除按钮 -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-end">{{ files.length }}/{{ maxFiles }}</div>
|
<div class="text-end text-sm text-gray-500">{{ files.length }}/{{ maxFiles }}</div>
|
||||||
<div ref="dropzoneElement" class="dropzone"></div>
|
<div ref="dropzoneElement" class="dropzone mt-2"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.dz_mark {
|
/* 覆盖 Dropzone 默认样式 */
|
||||||
height: 60px;
|
:deep(.dropzone) {
|
||||||
width: 60px;
|
min-height: 120px;
|
||||||
|
border: 2px dashed #dee2e6;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #f8f9fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnail-container {
|
:deep(.dropzone .dz-preview) {
|
||||||
display: flex;
|
margin: 0.5rem;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 15px;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 15px;
|
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 缩略图样式 */
|
|
||||||
.thumbnail {
|
|
||||||
width: var(--thumbnail-size);
|
|
||||||
height: var(--thumbnail-size);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
object-fit: cover;
|
|
||||||
border: 2px solid #e9ecef;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail:hover {
|
|
||||||
transform: scale(1.05);
|
|
||||||
border-color: #6c757d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 缩略图包装器 */
|
|
||||||
.thumbnail-wrapper {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: var(--thumbnail-size);
|
display: inline-block;
|
||||||
height: var(--thumbnail-size);
|
vertical-align: top;
|
||||||
margin-bottom: 10px;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移除按钮 */
|
:deep(.dropzone .dz-remove) {
|
||||||
.remove-btn {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -12px;
|
top: -6px;
|
||||||
right: -12px;
|
left: -6px;
|
||||||
width: 24px;
|
width: 18px;
|
||||||
height: 24px;
|
height: 18px;
|
||||||
border-radius: 50%;
|
background: #ef4444;
|
||||||
background-color: #dc3545;
|
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border-radius: 50%;
|
||||||
display: flex;
|
font-size: 10px;
|
||||||
align-items: center;
|
line-height: 18px;
|
||||||
justify-content: center;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.remove-btn:hover {
|
|
||||||
background-color: #bb2d3b;
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 文件名称 */
|
|
||||||
.file-name {
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 100px;
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-remove:hover) {
|
||||||
|
background: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-image-preview) {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-image) {
|
||||||
|
width: 80px !important;
|
||||||
|
z-index: 0 !important;
|
||||||
|
height: 80px !important;
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-image img) {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-details) {
|
||||||
|
opacity: 1 !important;
|
||||||
|
position: static !important;
|
||||||
|
padding: 0.25rem !important;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.dropzone .dz-filename) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #495057;
|
max-width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 上传区域 */
|
:deep(.dropzone .dz-size) {
|
||||||
.upload-area {
|
font-size: 0.65rem;
|
||||||
border: 2px dashed #dee2e6;
|
color: #9ca3af;
|
||||||
border-radius: 15px;
|
|
||||||
padding: 30px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-area:hover {
|
:deep(.dropzone .dz-success-mark),
|
||||||
border-color: #6c757d;
|
:deep(.dropzone .dz-error-mark) {
|
||||||
background-color: #e9ecef;
|
width: 24px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
margin-left: -12px !important;
|
||||||
|
margin-top: -12px !important;
|
||||||
|
background: rgba(255, 255, 255, 0.9) !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-icon {
|
:deep(.dropzone .dz-success-mark svg),
|
||||||
font-size: 48px;
|
:deep(.dropzone .dz-error-mark svg) {
|
||||||
color: #6c757d;
|
width: 14px !important;
|
||||||
margin-bottom: 10px;
|
height: 14px !important;
|
||||||
|
fill: #22c55e !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-title {
|
:deep(.dropzone .dz-error-mark svg) {
|
||||||
color: #343a40;
|
fill: #ef4444 !important;
|
||||||
border-bottom: 2px solid #e9ecef;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state {
|
:deep(.dropzone .dz-progress) {
|
||||||
text-align: center;
|
position: static !important;
|
||||||
padding: 40px 20px;
|
width: 100% !important;
|
||||||
color: #6c757d;
|
height: 4px !important;
|
||||||
|
border: none !important;
|
||||||
|
background: #e5e7eb !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
margin-top: 0.25rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state i {
|
:deep(.dropzone .dz-progress .dz-upload) {
|
||||||
font-size: 48px;
|
background: #3b82f6 !important;
|
||||||
margin-bottom: 15px;
|
border-radius: 2px !important;
|
||||||
color: #adb5bd;
|
width: 0 !important;
|
||||||
}
|
|
||||||
|
|
||||||
.counter-badge {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
background-color: #0d6efd;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-input {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,49 +1,145 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
/**
|
||||||
|
* 采购订单添加页面
|
||||||
|
*
|
||||||
|
* 功能概述:
|
||||||
|
* - 创建新的采购订单
|
||||||
|
* - 支持上传订单相关图片
|
||||||
|
* - 支持添加多种费用类型(单价、运费)
|
||||||
|
* - 支持选择订单状态、填写快递单号等
|
||||||
|
*
|
||||||
|
* 表单字段:
|
||||||
|
* - title: 订单标题(必填)
|
||||||
|
* - remark: 备注说明
|
||||||
|
* - photos: 订单图片列表
|
||||||
|
* - link: 采购链接
|
||||||
|
* - partname: 配件名称
|
||||||
|
* - styles: 款式标签
|
||||||
|
* - costs: 费用明细列表
|
||||||
|
* - tracking_number: 快递单号
|
||||||
|
* - updatetime: 更新时间
|
||||||
|
* - order_status: 订单状态
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ==================== 依赖导入 ====================
|
||||||
import { reactive, ref, computed, watch } from 'vue'
|
import { reactive, ref, computed, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useToastStore } from '@/stores/toast'
|
import { useToastStore } from '@/stores/toast'
|
||||||
import { usePageTitle } from '@/composables/usePageTitle'
|
import { usePageTitle } from '@/composables/usePageTitle'
|
||||||
import { useValidation } from '@/composables'
|
import { useValidation } from '@/composables'
|
||||||
import { purchaseApi } from '@/api/purchase'
|
import { purchaseApi } from '@/api/purchase'
|
||||||
import tagadder from '@/components/tagadder.vue'
|
|
||||||
import datePicker from '@/components/datePicker.vue'
|
|
||||||
import useDropzone from '@/components/useDropzone.vue'
|
|
||||||
|
|
||||||
|
// 组件导入
|
||||||
|
import tagadder from '@/components/tagadder.vue' // 标签添加组件
|
||||||
|
import datePicker from '@/components/datePicker.vue' // 日期选择组件
|
||||||
|
import useDropzone from '@/components/useDropzone.vue' // 文件上传组件(图片)
|
||||||
|
|
||||||
|
// ==================== 页面初始化 ====================
|
||||||
|
// 设置页面标题,使用 i18n key
|
||||||
usePageTitle('purchase.add_part')
|
usePageTitle('purchase.add_part')
|
||||||
|
|
||||||
|
// 获取国际化实例,用于多语言文本
|
||||||
const { t, locale } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
|
||||||
|
// Toast 消息提示
|
||||||
const toast = useToastStore()
|
const toast = useToastStore()
|
||||||
|
|
||||||
|
// 表单验证工具
|
||||||
const { validate, errors, clearErrors } = useValidation()
|
const { validate, errors, clearErrors } = useValidation()
|
||||||
|
|
||||||
|
// ==================== 常量定义 ====================
|
||||||
|
/**
|
||||||
|
* 备注文字最大长度限制
|
||||||
|
* 超过此长度将显示字符计数警告
|
||||||
|
*/
|
||||||
const textMaxLen = 256
|
const textMaxLen = 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传组件的引用
|
||||||
|
* 用于获取已上传的图片列表
|
||||||
|
*/
|
||||||
const photosRef = ref(null)
|
const photosRef = ref(null)
|
||||||
|
|
||||||
const currencyOptions = { 1: 'RMB', 2: 'MOA', 3: 'HKD', 4: 'USD' }
|
/**
|
||||||
|
* 货币类型选项
|
||||||
|
* key: 数据库中存储的值
|
||||||
|
* value: 显示的货币符号
|
||||||
|
*/
|
||||||
|
const currencyOptions = { 1: 'CNY', 2: 'MOP', 3: 'HKD', 4: 'USD' }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 货币类型对应的国旗图标路径
|
||||||
|
*/
|
||||||
|
const currencyFlags = { 1: '/static/flags/cn.svg', 2: '/static/flags/mo.svg', 3: '/static/flags/hk.svg', 4: '/static/flags/us.svg' }
|
||||||
|
|
||||||
|
// ==================== 费用类型映射 ====================
|
||||||
|
// 费用类型:单价 / 运费
|
||||||
const costType = computed(() => ({
|
const costType = computed(() => ({
|
||||||
1: t('cost_type.unit_price'),
|
1: t('cost_type.unit_price'), // 单价
|
||||||
2: t('cost_type.freight'),
|
2: t('cost_type.freight'), // 运费
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// ==================== 订单状态映射 ====================
|
||||||
|
// 订单的各种状态选项
|
||||||
const orderStatus = computed(() => ({
|
const orderStatus = computed(() => ({
|
||||||
1: t('order_status.pending_order'),
|
1: t('order_status.pending_order'), // 待下单
|
||||||
2: t('order_status.order_placed'),
|
2: t('order_status.order_placed'), // 已下单
|
||||||
3: t('order_status.in_transit'),
|
3: t('order_status.in_transit'), // 运输中
|
||||||
4: t('order_status.completed'),
|
4: t('order_status.completed'), // 已完成
|
||||||
5: t('order_status.refund_requested'),
|
5: t('order_status.refund_requested'), // 退款中
|
||||||
6: t('order_status.returning'),
|
6: t('order_status.returning'), // 退货中
|
||||||
7: t('order_status.refunded'),
|
7: t('order_status.refunded'), // 已退款
|
||||||
8: t('order_status.lost_package'),
|
8: t('order_status.lost_package'), // 丢件
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// ==================== 费用明细管理 ====================
|
||||||
|
/**
|
||||||
|
* 已添加的费用明细列表
|
||||||
|
* 每项包含:类型、数量、单价、总价、货币类型
|
||||||
|
*/
|
||||||
const costEntries = reactive([])
|
const costEntries = reactive([])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新费用条目的临时数据
|
||||||
|
* 用户填写完表单后点击"添加"按钮加入 costEntries
|
||||||
|
*/
|
||||||
const newCost = reactive({
|
const newCost = reactive({
|
||||||
type: '1', int: 1, cost: 0, currencyType: '1',
|
type: '1', // 费用类型:默认"单价"
|
||||||
|
int: 1, // 数量:默认1
|
||||||
|
cost: 0, // 单价:默认0
|
||||||
|
currencyType: '1', // 货币类型:默认人民币
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ==================== 表单数据 ====================
|
||||||
|
/**
|
||||||
|
* 订单表单主数据对象
|
||||||
|
* 包含所有需要提交的字段
|
||||||
|
*/
|
||||||
|
const form = reactive({
|
||||||
|
title: '', // 订单标题(必填)
|
||||||
|
remark: '', // 备注说明
|
||||||
|
photos: [], // 图片列表(上传后由 dropzone 填充)
|
||||||
|
link: '', // 采购链接
|
||||||
|
partname: '', // 配件名称
|
||||||
|
styles: '', // 款式标签
|
||||||
|
costs: [], // 费用明细(提交前由 costEntries 转换)
|
||||||
|
tracking_number: '', // 快递单号
|
||||||
|
updatetime: '', // 更新时间
|
||||||
|
order_status: '1', // 订单状态(默认待下单)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算新费用条目的总价
|
||||||
|
* 总价 = 数量 × 单价,保留2位小数
|
||||||
|
*/
|
||||||
const newCostTotal = computed(() =>
|
const newCostTotal = computed(() =>
|
||||||
parseFloat((newCost.int * newCost.cost).toFixed(2))
|
parseFloat((newCost.int * newCost.cost).toFixed(2))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一条费用明细到列表
|
||||||
|
* 条件:单价必须大于0
|
||||||
|
*/
|
||||||
function addCostEntry() {
|
function addCostEntry() {
|
||||||
if (newCost.cost <= 0) return
|
if (newCost.cost <= 0) return
|
||||||
costEntries.push({
|
costEntries.push({
|
||||||
@@ -53,93 +149,124 @@ function addCostEntry() {
|
|||||||
costt: newCostTotal.value,
|
costt: newCostTotal.value,
|
||||||
currencytype: newCost.currencyType,
|
currencytype: newCost.currencyType,
|
||||||
})
|
})
|
||||||
|
// 添加后重置表单,以便继续添加下一条
|
||||||
newCost.type = '1'
|
newCost.type = '1'
|
||||||
newCost.int = 1
|
newCost.int = 1
|
||||||
newCost.cost = 0
|
newCost.cost = 0
|
||||||
newCost.currencyType = '1'
|
newCost.currencyType = '1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从费用明细列表中移除指定条目
|
||||||
|
* @param {number} index - 要删除的条目索引
|
||||||
|
*/
|
||||||
function removeCostEntry(index) {
|
function removeCostEntry(index) {
|
||||||
costEntries.splice(index, 1)
|
costEntries.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听单价输入,自动保留2位小数
|
||||||
|
* 防止用户输入如 10.999 这样的值
|
||||||
|
*/
|
||||||
watch(() => newCost.cost, (val) => {
|
watch(() => newCost.cost, (val) => {
|
||||||
const fixed = parseFloat(val).toFixed(2)
|
const fixed = parseFloat(val).toFixed(2)
|
||||||
if (parseFloat(fixed) !== val) newCost.cost = parseFloat(fixed)
|
if (parseFloat(fixed) !== val) newCost.cost = parseFloat(fixed)
|
||||||
})
|
})
|
||||||
|
|
||||||
const form = reactive({
|
|
||||||
title: '',
|
|
||||||
remark: '',
|
|
||||||
photos: [],
|
|
||||||
link: '',
|
|
||||||
partname: '',
|
|
||||||
styles: '',
|
|
||||||
costs: [],
|
|
||||||
tracking_number: '',
|
|
||||||
updatetime: '',
|
|
||||||
order_status: '1',
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交按钮 loading 状态
|
||||||
|
* 防止重复提交
|
||||||
|
*/
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// ==================== 表单提交 ====================
|
||||||
|
/**
|
||||||
|
* 处理表单提交
|
||||||
|
* 1. 验证必填字段
|
||||||
|
* 2. 收集图片列表
|
||||||
|
* 3. 转换费用数据(金额从元转为分)
|
||||||
|
* 4. 调用 API 提交数据
|
||||||
|
*/
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
|
// 清空之前的验证错误
|
||||||
clearErrors()
|
clearErrors()
|
||||||
|
|
||||||
|
// 验证标题是否填写
|
||||||
const err = validate('title', form.title, t('purchase_addorder.title'))
|
const err = validate('title', form.title, t('purchase_addorder.title'))
|
||||||
if (!err) return
|
if (!err) return
|
||||||
|
|
||||||
|
// 从 dropzone 组件获取已上传的图片文件名
|
||||||
form.photos = []
|
form.photos = []
|
||||||
if (photosRef.value?.has_some_files) {
|
if (photosRef.value?.has_some_files) {
|
||||||
const result = photosRef.value.get_some_files()
|
const result = photosRef.value.get_some_files()
|
||||||
form.photos = result.map(f => f.name)
|
form.photos = result.map(f => f.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将费用明细转换为提交格式
|
||||||
|
// 注意:金额需要从"元"转为"分"(乘以100)存储
|
||||||
form.costs = costEntries.map(h => ({
|
form.costs = costEntries.map(h => ({
|
||||||
...h,
|
...h,
|
||||||
cost: Math.round(h.cost * 100),
|
cost: Math.round(h.cost * 100),
|
||||||
costt: Math.round(h.costt * 100),
|
costt: Math.round(h.costt * 100),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// 开始 loading
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
|
// 调用采购 API 添加订单
|
||||||
const { errCode } = await purchaseApi.addOrder(form)
|
const { errCode } = await purchaseApi.addOrder(form)
|
||||||
if (errCode === 0) {
|
if (errCode === 0) {
|
||||||
|
// 保存成功,显示成功提示
|
||||||
toast.success(t('message.save_ok'))
|
toast.success(t('message.save_ok'))
|
||||||
} else {
|
} else {
|
||||||
|
// 服务器错误,显示错误提示
|
||||||
toast.error(t('message.server_error'))
|
toast.error(t('message.server_error'))
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// interceptor handled
|
// 错误已被 HTTP 拦截器处理,此处无需额外处理
|
||||||
} finally {
|
} finally {
|
||||||
|
// 无论成功失败,都要关闭 loading
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<!-- 页面容器:居中,最大宽度 6xl,左右内边距,上下内边距 -->
|
||||||
<div class="mx-auto max-w-6xl px-6 py-6">
|
<div class="mx-auto max-w-6xl px-6 py-6">
|
||||||
|
<!-- 主卡片:白色背景,圆角,阴影,支持暗色模式 -->
|
||||||
<div class="flex flex-col gap-6 rounded-xl border border-gray-200 bg-white shadow-lg dark:border-dk-muted dark:bg-dk-card">
|
<div class="flex flex-col gap-6 rounded-xl border border-gray-200 bg-white shadow-lg dark:border-dk-muted dark:bg-dk-card">
|
||||||
<!-- Order Info -->
|
|
||||||
|
<!-- ==================== 订单信息区块 ==================== -->
|
||||||
<div class="border-b border-gray-200 px-6 py-4 dark:border-dk-muted">
|
<div class="border-b border-gray-200 px-6 py-4 dark:border-dk-muted">
|
||||||
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.order_info') }}</h4>
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.order_info') }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 订单信息表单区域 -->
|
||||||
<div class="space-y-4 px-6 py-5">
|
<div class="space-y-4 px-6 py-5">
|
||||||
|
<!-- 标题字段(必填) -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{{ t('purchase_addorder.title') }} <span class="text-red-500">*</span>
|
{{ t('purchase_addorder.part_name') }} <span class="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
v-model="form.title"
|
v-model="form.title"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm outline-none transition-colors focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 dark:border-dk-muted dark:bg-dk-base dark:text-white"
|
class="w-full rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm outline-none transition-colors focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 dark:border-dk-muted dark:bg-dk-base dark:text-white"
|
||||||
:class="errors.title ? 'border-red-500' : 'border-gray-300'"
|
:class="errors.title ? 'border-red-500' : 'border-gray-300'"
|
||||||
:placeholder="t('purchase_addorder.input_title')"
|
:placeholder="t('purchase_addorder.part_name')"
|
||||||
/>
|
/>
|
||||||
|
<!-- 验证错误提示 -->
|
||||||
<span v-if="errors.title" class="mt-1 block text-xs text-red-500">{{ errors.title }}</span>
|
<span v-if="errors.title" class="mt-1 block text-xs text-red-500">{{ errors.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 备注字段 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{{ t('purchase_addorder.remarks') }}
|
{{ t('purchase_addorder.remarks') }}
|
||||||
|
<!-- 字符计数 -->
|
||||||
<span class="text-gray-400">{{ form.remark.length }}/{{ textMaxLen }}</span>
|
<span class="text-gray-400">{{ form.remark.length }}/{{ textMaxLen }}</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -149,17 +276,28 @@ async function handleSubmit() {
|
|||||||
:placeholder="t('purchase_addorder.remarks_text')"
|
:placeholder="t('purchase_addorder.remarks_text')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 图片上传区域 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.photo_remarks') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.photo_remarks') }}</label>
|
||||||
|
<!--
|
||||||
|
useDropzone 组件属性:
|
||||||
|
- acceptFiles="image/*": 只接受图片文件
|
||||||
|
- uploadURL: 上传接口地址
|
||||||
|
- maxFiles="10": 最多10张图片
|
||||||
|
- ref="photosRef": 组件引用,用于获取上传的文件列表
|
||||||
|
-->
|
||||||
<useDropzone acceptFiles="image/*" uploadURL="/api/files/upload/image" maxFiles="10" ref="photosRef" />
|
<useDropzone acceptFiles="image/*" uploadURL="/api/files/upload/image" maxFiles="10" ref="photosRef" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Purchase Channel -->
|
<!-- ==================== 采购渠道区块 ==================== -->
|
||||||
<div class="border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
<div class="border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
||||||
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.purchase_channel') }}</h4>
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.purchase_channel') }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-4 px-6 py-5">
|
<div class="space-y-4 px-6 py-5">
|
||||||
|
<!-- 采购链接 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.link') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.link') }}</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -169,23 +307,19 @@ async function handleSubmit() {
|
|||||||
placeholder="url"
|
placeholder="url"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.part_name') }}</label>
|
<!-- 款式标签 -->
|
||||||
<input
|
|
||||||
v-model="form.partname"
|
|
||||||
type="text"
|
|
||||||
class="w-full rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm outline-none transition-colors focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 dark:border-dk-muted dark:bg-dk-base dark:text-white"
|
|
||||||
:placeholder="t('purchase_addorder.part_name')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.style_remarks') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.style_remarks') }}</label>
|
||||||
|
<!-- tagadder: 支持添加多个标签的组件 -->
|
||||||
<tagadder :placeholder="t('purchase_addorder.add_style')" v-model="form.styles" />
|
<tagadder :placeholder="t('purchase_addorder.add_style')" v-model="form.styles" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- costs table -->
|
<!-- ==================== 费用明细表格 ==================== -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.cost') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.cost') }}</label>
|
||||||
|
|
||||||
|
<!-- 已添加的费用列表表格(有时才显示) -->
|
||||||
<div v-if="costEntries.length" class="mb-4 overflow-x-auto">
|
<div v-if="costEntries.length" class="mb-4 overflow-x-auto">
|
||||||
<table class="w-full text-left text-sm text-gray-900">
|
<table class="w-full text-left text-sm text-gray-900">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -204,8 +338,12 @@ async function handleSubmit() {
|
|||||||
<td class="px-3 py-2 text-gray-500">{{ item.int }}</td>
|
<td class="px-3 py-2 text-gray-500">{{ item.int }}</td>
|
||||||
<td class="px-3 py-2 text-gray-500">{{ item.cost }}</td>
|
<td class="px-3 py-2 text-gray-500">{{ item.cost }}</td>
|
||||||
<td class="px-3 py-2 text-gray-500">{{ item.costt }}</td>
|
<td class="px-3 py-2 text-gray-500">{{ item.costt }}</td>
|
||||||
<td class="px-3 py-2 text-gray-500">{{ currencyOptions[item.currencytype] }}</td>
|
<td class="px-3 py-2 text-gray-500">
|
||||||
|
<img :src="currencyFlags[item.currencytype]" class="inline-block h-4 w-6 align-middle" :alt="currencyOptions[item.currencytype]" />
|
||||||
|
{{ currencyOptions[item.currencytype] }}
|
||||||
|
</td>
|
||||||
<td class="px-3 py-2">
|
<td class="px-3 py-2">
|
||||||
|
<!-- 删除按钮 -->
|
||||||
<button class="rounded px-2 py-1 text-xs font-medium text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20" @click="removeCostEntry(idx)">{{ t('purchase_addorder.remove') }}</button>
|
<button class="rounded px-2 py-1 text-xs font-medium text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20" @click="removeCostEntry(idx)">{{ t('purchase_addorder.remove') }}</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -213,7 +351,9 @@ async function handleSubmit() {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加费用表单:响应式网格布局 -->
|
||||||
<div class="grid grid-cols-2 gap-4 sm:grid-cols-5">
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-5">
|
||||||
|
<!-- 费用类型选择 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.fee_type') }}</label>
|
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.fee_type') }}</label>
|
||||||
<select v-model="newCost.type" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
<select v-model="newCost.type" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
||||||
@@ -222,14 +362,20 @@ async function handleSubmit() {
|
|||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 数量输入 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.input_quantity') }}</label>
|
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.input_quantity') }}</label>
|
||||||
<input v-model.number="newCost.int" type="number" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white" min="1" />
|
<input v-model.number="newCost.int" type="number" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white" min="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 单价输入 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.input_fee') }}</label>
|
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.input_fee') }}</label>
|
||||||
<input v-model="newCost.cost" type="number" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white" step="0.01" min="0" />
|
<input v-model="newCost.cost" type="number" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white" step="0.01" min="0" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 货币类型选择 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.select_currency') }}</label>
|
<label class="mb-1 block text-xs font-medium text-gray-500">{{ t('purchase_addorder.select_currency') }}</label>
|
||||||
<select v-model="newCost.currencyType" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
<select v-model="newCost.currencyType" class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
||||||
@@ -238,6 +384,8 @@ async function handleSubmit() {
|
|||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加按钮(与输入框底部对齐) -->
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<button class="w-full rounded-lg border border-gray-300 bg-blue-600 px-3 py-2 text-sm font-semibold text-blue-100 transition-colors hover:bg-blue-700 focus:ring-2 focus:ring-blue-500/20 dark:border-dk-muted dark:text-white dark:bg-blue-600" @click="addCostEntry">{{ t('purchase_addorder.add') }}</button>
|
<button class="w-full rounded-lg border border-gray-300 bg-blue-600 px-3 py-2 text-sm font-semibold text-blue-100 transition-colors hover:bg-blue-700 focus:ring-2 focus:ring-blue-500/20 dark:border-dk-muted dark:text-white dark:bg-blue-600" @click="addCostEntry">{{ t('purchase_addorder.add') }}</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -245,18 +393,23 @@ async function handleSubmit() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Order Status -->
|
<!-- ==================== 订单状态区块 ==================== -->
|
||||||
<div class="border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
<div class="border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
||||||
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.order_status') }}</h4>
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">{{ t('purchase_addorder.order_status') }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="px-6 py-5">
|
<div class="px-6 py-5">
|
||||||
|
<!-- 三列响应式网格 -->
|
||||||
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<!-- 更新时间(必填) -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{{ t('purchase_addorder.update_time') }} <span class="text-red-500">*</span>
|
{{ t('purchase_addorder.update_time') }} <span class="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<datePicker v-model="form.updatetime" />
|
<datePicker v-model="form.updatetime" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 快递单号 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.tracking_number') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.tracking_number') }}</label>
|
||||||
<input
|
<input
|
||||||
@@ -266,6 +419,8 @@ async function handleSubmit() {
|
|||||||
:placeholder="t('purchase_addorder.input_tracking_number')"
|
:placeholder="t('purchase_addorder.input_tracking_number')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 订单状态下拉框 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.order_status') }}</label>
|
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">{{ t('purchase_addorder.order_status') }}</label>
|
||||||
<select v-model="form.order_status" class="w-full rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
<select v-model="form.order_status" class="w-full rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm dark:border-dk-muted dark:bg-dk-base dark:text-white">
|
||||||
@@ -277,13 +432,15 @@ async function handleSubmit() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- ==================== 底部操作栏 ==================== -->
|
||||||
<div class="flex justify-end border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
<div class="flex justify-end border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
|
||||||
|
<!-- 提交按钮:提交时显示 loading 动画 -->
|
||||||
<button
|
<button
|
||||||
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-blue-700 focus:ring-2 focus:ring-blue-500/20 focus:outline-none disabled:active:scale-100"
|
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-blue-700 focus:ring-2 focus:ring-blue-500/20 focus:outline-none disabled:active:scale-100"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
@click="handleSubmit"
|
@click="handleSubmit"
|
||||||
>
|
>
|
||||||
|
<!-- loading 状态显示旋转图标 -->
|
||||||
<svg v-if="loading" class="h-4 w-4 animate-spin text-white" viewBox="0 0 24 24" fill="none">
|
<svg v-if="loading" class="h-4 w-4 animate-spin text-white" viewBox="0 0 24 24" fill="none">
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
|
||||||
@@ -291,6 +448,7 @@ async function handleSubmit() {
|
|||||||
{{ t('purchase_addorder.submit') }}
|
{{ t('purchase_addorder.submit') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user