up
This commit is contained in:
@@ -47,3 +47,29 @@
|
|||||||
- 前端:状态选 `parts_ordered` 时显示采购订单搜索框(防抖300ms),输入框获取焦点自动搜索
|
- 前端:状态选 `parts_ordered` 时显示采购订单搜索框(防抖300ms),输入框获取焦点自动搜索
|
||||||
- 时间线每条 commit 下方展示关联的采购订单链接(点击跳转到采购详情页)
|
- 时间线每条 commit 下方展示关联的采购订单链接(点击跳转到采购详情页)
|
||||||
|
|
||||||
|
## 今日功能迭代
|
||||||
|
|
||||||
|
**ConfirmDialog 组件 v-model 修复**:
|
||||||
|
- 组件使用 `v-if="modelValue"` 控制弹窗显示,但外部只用了 `v-if` 控制组件存在,没有传入 `modelValue` prop
|
||||||
|
- 修复:在所有使用 ConfirmDialog 的地方改用 `v-model="xxx"` 绑定
|
||||||
|
- 涉及文件:ShowWorkOrder.vue、AddEditWorkOrder.vue、ShowOrder.vue
|
||||||
|
|
||||||
|
**ShowWorkOrder.vue 进度删除功能**:
|
||||||
|
- 新增删除按钮(新样式:带边框和背景色的文字按钮)
|
||||||
|
- 每条 commit 加边框和背景色,便于区分
|
||||||
|
- 最新状态不显示删除按钮
|
||||||
|
- 权限判断:工单创建者 OR 进度创建者 OR 管理员
|
||||||
|
- 删除后前端直接移除该 commit,保持滚动位置
|
||||||
|
|
||||||
|
**useDropzone v-model 问题修复**:
|
||||||
|
- useDropzone 组件没有实现 v-model,是通过 `return_files()` 方法暴露文件
|
||||||
|
- 修复:添加 `ref="commitDropzoneRef"`,通过 `commitDropzoneRef.value?.return_files()` 获取文件
|
||||||
|
- 只筛选 `is_upload === true` 的文件获取 hash
|
||||||
|
|
||||||
|
**采购订单状态记录删除功能**:
|
||||||
|
- 后端:apiPurchase.go 新增 `/delete_commit` 接口,权限判断同工单
|
||||||
|
- 前端:ShowOrder.vue 新增删除按钮,样式和逻辑同工单页面
|
||||||
|
- 新增翻译:purchase.confirm_delete_commit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -350,6 +350,54 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
ReturnJson(ctx, "apiOK", nil)
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 删除状态记录
|
||||||
|
r.POST("/delete_commit", func(ctx *gin.Context) {
|
||||||
|
isAuth, user, data := AuthenticationAuthority(ctx)
|
||||||
|
if !isAuth {
|
||||||
|
ReturnJson(ctx, "userCookieError", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type FromDeleteCommit struct {
|
||||||
|
OrderID uint `json:"orderId"`
|
||||||
|
CommitID uint `json:"commitId"`
|
||||||
|
}
|
||||||
|
var from FromDeleteCommit
|
||||||
|
if err := decodeJSON(data, &from); err != nil || from.OrderID == 0 || from.CommitID == 0 {
|
||||||
|
ReturnJson(ctx, "jsonErr", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取订单信息
|
||||||
|
var order TabPurchaseOrder
|
||||||
|
if err := models.DB.Where("id = ?", from.OrderID).First(&order).Error; err != nil {
|
||||||
|
ReturnJson(ctx, "order_not_found", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取进度信息
|
||||||
|
var commit TabPurchaseCommit
|
||||||
|
if err := models.DB.Where("id = ? AND order_id = ?", from.CommitID, from.OrderID).First(&commit).Error; err != nil {
|
||||||
|
ReturnJson(ctx, "commit_not_found", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限判断:订单创建者 或 进度创建者 或 管理员
|
||||||
|
isOrderCreator := user.ID == order.UserID
|
||||||
|
isCommitCreator := user.ID == commit.UserID
|
||||||
|
isAdmin := slices.Contains(purchaseAdmins, user.ID)
|
||||||
|
|
||||||
|
if !isOrderCreator && !isCommitCreator && !isAdmin {
|
||||||
|
ReturnJson(ctx, "no_permission", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除进度
|
||||||
|
models.DB.Where("id = ?", from.CommitID).Delete(&TabPurchaseCommit{})
|
||||||
|
|
||||||
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
|
})
|
||||||
|
|
||||||
r.POST("/getorders", func(ctx *gin.Context) {
|
r.POST("/getorders", func(ctx *gin.Context) {
|
||||||
isAuth, _, data := AuthenticationAuthority(ctx)
|
isAuth, _, data := AuthenticationAuthority(ctx)
|
||||||
if isAuth {
|
if isAuth {
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ func ApiWorkOrder(r *gin.RouterGroup) {
|
|||||||
|
|
||||||
// commits
|
// commits
|
||||||
var commits []TabWorkOrderCommit
|
var commits []TabWorkOrderCommit
|
||||||
models.DB.Where("work_order_id = ?", from.ID).Order("created_at ASC").Find(&commits)
|
models.DB.Where("work_order_id = ?", from.ID).Order("created_at DESC").Find(&commits)
|
||||||
|
|
||||||
// 为每条 commit 附加图片和采购订单
|
// 为每条 commit 附加图片和采购订单
|
||||||
type CommitWithPhotos struct {
|
type CommitWithPhotos struct {
|
||||||
@@ -566,6 +566,58 @@ func ApiWorkOrder(r *gin.RouterGroup) {
|
|||||||
ReturnJson(ctx, "apiOK", nil)
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 删除进度
|
||||||
|
r.POST("/delete_commit", func(ctx *gin.Context) {
|
||||||
|
isAuth, user, data := AuthenticationAuthority(ctx)
|
||||||
|
if !isAuth {
|
||||||
|
ReturnJson(ctx, "userCookieError", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type FromDeleteCommit struct {
|
||||||
|
WorkOrderID uint `json:"workOrderId"`
|
||||||
|
CommitID uint `json:"commitId"`
|
||||||
|
}
|
||||||
|
var from FromDeleteCommit
|
||||||
|
if err := decodeJSON(data, &from); err != nil || from.WorkOrderID == 0 || from.CommitID == 0 {
|
||||||
|
ReturnJson(ctx, "jsonErr", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取工单信息
|
||||||
|
var order TabWorkOrder
|
||||||
|
if err := models.DB.Where("id = ?", from.WorkOrderID).First(&order).Error; err != nil {
|
||||||
|
ReturnJson(ctx, "order_not_found", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取进度信息
|
||||||
|
var commit TabWorkOrderCommit
|
||||||
|
if err := models.DB.Where("id = ? AND work_order_id = ?", from.CommitID, from.WorkOrderID).First(&commit).Error; err != nil {
|
||||||
|
ReturnJson(ctx, "commit_not_found", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限判断:工单创建者 或 进度创建者 或 管理员
|
||||||
|
isOrderCreator := user.ID == order.UserID
|
||||||
|
isCommitCreator := user.ID == commit.UserID
|
||||||
|
isAdmin := slices.Contains(workOrderAdmins, user.ID)
|
||||||
|
|
||||||
|
if !isOrderCreator && !isCommitCreator && !isAdmin {
|
||||||
|
ReturnJson(ctx, "no_permission", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联的采购订单绑定
|
||||||
|
models.DB.Where("commit_id = ?", from.CommitID).Delete(&TabWorkOrderPurchaseOrderBind{})
|
||||||
|
// 删除关联的图片
|
||||||
|
models.DB.Where("commit_id = ?", from.CommitID).Delete(&TabWorkOrderCommitFileBind{})
|
||||||
|
// 删除进度记录
|
||||||
|
models.DB.Where("id = ?", from.CommitID).Delete(&commit)
|
||||||
|
|
||||||
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
|
})
|
||||||
|
|
||||||
// 获取工单数量统计
|
// 获取工单数量统计
|
||||||
r.POST("/count", func(ctx *gin.Context) {
|
r.POST("/count", func(ctx *gin.Context) {
|
||||||
isAuth, _, _ := AuthenticationAuthority(ctx)
|
isAuth, _, _ := AuthenticationAuthority(ctx)
|
||||||
|
|||||||
@@ -35,4 +35,9 @@ export const purchaseApi = {
|
|||||||
deleteOrder(id) {
|
deleteOrder(id) {
|
||||||
return api.post('/purchase/deleteorder', { id })
|
return api.post('/purchase/deleteorder', { id })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 删除状态记录 */
|
||||||
|
deleteCommit(orderId, commitId) {
|
||||||
|
return api.post('/purchase/delete_commit', { orderId, commitId })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,4 +40,9 @@ export const workOrderApi = {
|
|||||||
searchPurchaseOrders(search = '', limit = 5) {
|
searchPurchaseOrders(search = '', limit = 5) {
|
||||||
return api.post('/work_order/search_purchase_orders', { search, limit })
|
return api.post('/work_order/search_purchase_orders', { search, limit })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 删除进度 */
|
||||||
|
deleteCommit(workOrderId, commitId) {
|
||||||
|
return api.post('/work_order/delete_commit', { workOrderId, commitId })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,8 @@
|
|||||||
"upload_photos": "Upload Photos",
|
"upload_photos": "Upload Photos",
|
||||||
"commit_create": "Order created",
|
"commit_create": "Order created",
|
||||||
"edit_order": "Edit Order",
|
"edit_order": "Edit Order",
|
||||||
"submit_changes":"Submit changes"
|
"submit_changes":"Submit changes",
|
||||||
|
"confirm_delete_commit": "Are you sure you want to delete this progress?"
|
||||||
},
|
},
|
||||||
"work_order": {
|
"work_order": {
|
||||||
"list_title": "Work Order List",
|
"list_title": "Work Order List",
|
||||||
@@ -146,6 +147,7 @@
|
|||||||
"back_to_list": "Back to List",
|
"back_to_list": "Back to List",
|
||||||
"not_found": "Work order not found",
|
"not_found": "Work order not found",
|
||||||
"confirm_delete": "Are you sure you want to delete this work order? This action cannot be undone.",
|
"confirm_delete": "Are you sure you want to delete this work order? This action cannot be undone.",
|
||||||
|
"confirm_delete_commit": "Are you sure you want to delete this progress?",
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
"save_changes": "Save Changes"
|
"save_changes": "Save Changes"
|
||||||
},
|
},
|
||||||
@@ -292,6 +294,7 @@
|
|||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"save_success": "Saved successfully",
|
"save_success": "Saved successfully",
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
|
"submitting": "Submitting...",
|
||||||
"loading": "Loading..."
|
"loading": "Loading..."
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
|||||||
@@ -108,7 +108,8 @@
|
|||||||
"upload_photos": "上传图片",
|
"upload_photos": "上传图片",
|
||||||
"commit_create": "订单创建",
|
"commit_create": "订单创建",
|
||||||
"edit_order": "编辑订单",
|
"edit_order": "编辑订单",
|
||||||
"submit_changes":"提交修改"
|
"submit_changes":"提交修改",
|
||||||
|
"confirm_delete_commit": "确定要删除此进度吗?"
|
||||||
},
|
},
|
||||||
"work_order": {
|
"work_order": {
|
||||||
"list_title": "工单列表",
|
"list_title": "工单列表",
|
||||||
@@ -146,6 +147,7 @@
|
|||||||
"back_to_list": "返回列表",
|
"back_to_list": "返回列表",
|
||||||
"not_found": "工单不存在",
|
"not_found": "工单不存在",
|
||||||
"confirm_delete": "确定要删除此工单吗?此操作不可撤销。",
|
"confirm_delete": "确定要删除此工单吗?此操作不可撤销。",
|
||||||
|
"confirm_delete_commit": "确定要删除此进度吗?",
|
||||||
"submit": "提交",
|
"submit": "提交",
|
||||||
"save_changes": "保存修改"
|
"save_changes": "保存修改"
|
||||||
},
|
},
|
||||||
@@ -292,6 +294,7 @@
|
|||||||
"delete_ok": "删除成功",
|
"delete_ok": "删除成功",
|
||||||
"save_success": "保存成功",
|
"save_success": "保存成功",
|
||||||
"submit": "提交",
|
"submit": "提交",
|
||||||
|
"submitting": "提交中...",
|
||||||
"loading": "加载中..."
|
"loading": "加载中..."
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { usePageTitle } from "@/composables/usePageTitle";
|
|||||||
import { purchaseApi } from "@/api/purchase";
|
import { purchaseApi } from "@/api/purchase";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { useUsersStore } from "@/stores/users";
|
import { useUsersStore } from "@/stores/users";
|
||||||
|
import ConfirmDialog from "@/components/ConfirmDialog.vue";
|
||||||
import {
|
import {
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
IconExternalLink,
|
IconExternalLink,
|
||||||
@@ -44,6 +45,47 @@ const pendingComment = ref("");
|
|||||||
const pendingPhotos = ref([]); // { hash, url, uploading, error }
|
const pendingPhotos = ref([]); // { hash, url, uploading, error }
|
||||||
const photoInputRef = ref(null);
|
const photoInputRef = ref(null);
|
||||||
|
|
||||||
|
// 删除进度相关
|
||||||
|
const showDeleteConfirm = ref(false);
|
||||||
|
const pendingDeleteCommitId = ref(null);
|
||||||
|
|
||||||
|
// 判断是否可以删除进度
|
||||||
|
function canDeleteCommit(commit, index) {
|
||||||
|
// 最新状态(第0条)不显示删除按钮
|
||||||
|
if (index === 0) return false;
|
||||||
|
// 订单创建者
|
||||||
|
if (order.value?.UserID === userStore.user?.ID) return true;
|
||||||
|
// 进度创建者
|
||||||
|
if (commit.userId === userStore.user?.ID) return true;
|
||||||
|
// 管理员
|
||||||
|
if (userStore.user?.Type === 'admin') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDeleteCommit(commitId) {
|
||||||
|
pendingDeleteCommitId.value = commitId;
|
||||||
|
showDeleteConfirm.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmDeleteCommit() {
|
||||||
|
if (!pendingDeleteCommitId.value) return;
|
||||||
|
try {
|
||||||
|
const { errCode } = await purchaseApi.deleteCommit(orderId.value, pendingDeleteCommitId.value);
|
||||||
|
if (errCode === 0) {
|
||||||
|
toast.success(t("message.delete_ok"));
|
||||||
|
// 前端直接移除该 commit,保持滚动位置
|
||||||
|
commits.value = commits.value.filter(c => c.id !== pendingDeleteCommitId.value);
|
||||||
|
} else {
|
||||||
|
toast.error(t("message.server_error"));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
toast.error(t("message.server_error"));
|
||||||
|
} finally {
|
||||||
|
pendingDeleteCommitId.value = null;
|
||||||
|
showDeleteConfirm.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 状态选项
|
// 状态选项
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
{ value: "pending", labelKey: "status_pending", color: "yellow" },
|
{ value: "pending", labelKey: "status_pending", color: "yellow" },
|
||||||
@@ -644,9 +686,9 @@ onMounted(fetchOrder);
|
|||||||
class="divide-y divide-gray-50 px-6 py-2 dark:divide-dk-muted/50"
|
class="divide-y divide-gray-50 px-6 py-2 dark:divide-dk-muted/50"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="commit in commits"
|
v-for="(commit, index) in commits"
|
||||||
:key="commit.id"
|
:key="commit.id"
|
||||||
class="flex items-start gap-3 py-3"
|
class="flex items-start gap-3 py-3 rounded-lg border border-gray-100 bg-gray-50/50 px-4 my-2 dark:border-dk-muted dark:bg-dk-base/30"
|
||||||
>
|
>
|
||||||
<!-- 左侧:头像 + 用户名 -->
|
<!-- 左侧:头像 + 用户名 -->
|
||||||
<div class="flex w-20 flex-shrink-0 flex-col items-center gap-1">
|
<div class="flex w-20 flex-shrink-0 flex-col items-center gap-1">
|
||||||
@@ -697,6 +739,15 @@ onMounted(fetchOrder);
|
|||||||
<span class="ml-auto text-xs text-gray-400">{{
|
<span class="ml-auto text-xs text-gray-400">{{
|
||||||
formatDate(commit.createdAt)
|
formatDate(commit.createdAt)
|
||||||
}}</span>
|
}}</span>
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<button
|
||||||
|
v-if="canDeleteCommit(commit, index)"
|
||||||
|
class="ml-2 rounded-lg border border-red-200 bg-red-50 px-3 py-1 text-xs font-medium text-red-600 transition-colors hover:bg-red-100 hover:border-red-300 dark:border-red-900/50 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50"
|
||||||
|
@click="handleDeleteCommit(commit.id)"
|
||||||
|
>
|
||||||
|
<IconTrash :size="14" class="mr-1 inline align-middle" />
|
||||||
|
删除
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="commit.comment"
|
v-if="commit.comment"
|
||||||
@@ -899,6 +950,14 @@ onMounted(fetchOrder);
|
|||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- 删除进度确认弹窗 -->
|
||||||
|
<ConfirmDialog
|
||||||
|
v-model="showDeleteConfirm"
|
||||||
|
:message="t('purchase.confirm_delete_commit')"
|
||||||
|
danger
|
||||||
|
@confirm="confirmDeleteCommit"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -259,9 +259,9 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
<!-- 删除确认弹窗 -->
|
<!-- 删除确认弹窗 -->
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
v-if="showDeleteConfirm"
|
v-model="showDeleteConfirm"
|
||||||
:message="t('work_order.confirm_delete')"
|
:message="t('work_order.confirm_delete')"
|
||||||
|
danger
|
||||||
@confirm="doDelete"
|
@confirm="doDelete"
|
||||||
@cancel="showDeleteConfirm = false"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useUserStore } from '@/stores/user'
|
|||||||
import { useUsersStore } from '@/stores/users'
|
import { useUsersStore } from '@/stores/users'
|
||||||
import { workOrderApi } from '@/api/work_order'
|
import { workOrderApi } from '@/api/work_order'
|
||||||
import useDropzone from '@/components/useDropzone.vue'
|
import useDropzone from '@/components/useDropzone.vue'
|
||||||
|
import ConfirmDialog from '@/components/ConfirmDialog.vue'
|
||||||
import {
|
import {
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
IconCheck,
|
IconCheck,
|
||||||
@@ -39,7 +40,7 @@ const notFound = ref(false)
|
|||||||
const submittingCommit = ref(false)
|
const submittingCommit = ref(false)
|
||||||
const commitStatus = ref('pending')
|
const commitStatus = ref('pending')
|
||||||
const commitComment = ref('')
|
const commitComment = ref('')
|
||||||
const commitPhotos = ref([])
|
const commitDropzoneRef = ref(null)
|
||||||
|
|
||||||
// 采购订单关联相关
|
// 采购订单关联相关
|
||||||
const purchaseSearchQuery = ref('')
|
const purchaseSearchQuery = ref('')
|
||||||
@@ -54,7 +55,7 @@ const purchaseDropdownRef = ref(null)
|
|||||||
const canSubmit = computed(() => {
|
const canSubmit = computed(() => {
|
||||||
const hasSelectedOrders = selectedPurchaseOrders.value.length > 0
|
const hasSelectedOrders = selectedPurchaseOrders.value.length > 0
|
||||||
const hasComment = !!commitComment.value
|
const hasComment = !!commitComment.value
|
||||||
const hasPhotos = commitPhotos.value.length > 0
|
const hasPhotos = commitDropzoneRef.value?.return_files().filter(f => f.is_upload).length > 0
|
||||||
// 订单、备注、上传图片都为空时才禁止提交
|
// 订单、备注、上传图片都为空时才禁止提交
|
||||||
return hasSelectedOrders || hasComment || hasPhotos
|
return hasSelectedOrders || hasComment || hasPhotos
|
||||||
})
|
})
|
||||||
@@ -138,18 +139,22 @@ async function handleCommit() {
|
|||||||
submittingCommit.value = true
|
submittingCommit.value = true
|
||||||
try {
|
try {
|
||||||
const purchaseOrderIds = selectedPurchaseOrders.value.map(p => p.id)
|
const purchaseOrderIds = selectedPurchaseOrders.value.map(p => p.id)
|
||||||
|
// 从 dropzone 获取已上传的文件 hash
|
||||||
|
const uploadedPhotos = commitDropzoneRef.value?.return_files()
|
||||||
|
.filter(f => f.is_upload)
|
||||||
|
.map(f => f.hash) ?? []
|
||||||
const { errCode } = await workOrderApi.commit(
|
const { errCode } = await workOrderApi.commit(
|
||||||
orderId.value,
|
orderId.value,
|
||||||
commitStatus.value,
|
commitStatus.value,
|
||||||
commitComment.value,
|
commitComment.value,
|
||||||
commitPhotos.value,
|
uploadedPhotos,
|
||||||
purchaseOrderIds,
|
purchaseOrderIds,
|
||||||
)
|
)
|
||||||
if (errCode === 0) {
|
if (errCode === 0) {
|
||||||
toast.success(t('message.save_ok'))
|
toast.success(t('message.save_ok'))
|
||||||
commitComment.value = ''
|
commitComment.value = ''
|
||||||
commitPhotos.value = []
|
|
||||||
selectedPurchaseOrders.value = []
|
selectedPurchaseOrders.value = []
|
||||||
|
// 清空 dropzone(刷新组件即可)
|
||||||
await fetchOrder()
|
await fetchOrder()
|
||||||
} else {
|
} else {
|
||||||
toast.error(t('message.server_error'))
|
toast.error(t('message.server_error'))
|
||||||
@@ -161,6 +166,47 @@ async function handleCommit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 删除进度 ====================
|
||||||
|
const showDeleteCommitConfirm = ref(false)
|
||||||
|
const pendingDeleteCommitId = ref(null)
|
||||||
|
|
||||||
|
function handleDeleteCommit(commitId) {
|
||||||
|
pendingDeleteCommitId.value = commitId
|
||||||
|
showDeleteCommitConfirm.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmDeleteCommit() {
|
||||||
|
if (!pendingDeleteCommitId.value) return
|
||||||
|
try {
|
||||||
|
const { errCode } = await workOrderApi.deleteCommit(orderId.value, pendingDeleteCommitId.value)
|
||||||
|
if (errCode === 0) {
|
||||||
|
toast.success(t('message.delete_ok'))
|
||||||
|
// 前端直接移除该 commit,保持滚动位置
|
||||||
|
commits.value = commits.value.filter(c => c.ID !== pendingDeleteCommitId.value)
|
||||||
|
} else {
|
||||||
|
toast.error(t('message.server_error'))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
toast.error(t('message.server_error'))
|
||||||
|
} finally {
|
||||||
|
pendingDeleteCommitId.value = null
|
||||||
|
showDeleteCommitConfirm.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否可以删除进度
|
||||||
|
function canDeleteCommit(commit, index) {
|
||||||
|
// 最新状态(第0条)不显示删除按钮
|
||||||
|
if (index === 0) return false
|
||||||
|
// 订单创建者
|
||||||
|
if (order.value?.UserID === userStore.user?.ID) return true
|
||||||
|
// 进度创建者
|
||||||
|
if (commit.UserID === userStore.user?.ID) return true
|
||||||
|
// 管理员
|
||||||
|
if (userStore.user?.Type === 'admin') return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 快捷切换状态 ====================
|
// ==================== 快捷切换状态 ====================
|
||||||
async function quickChangeStatus(newStatus) {
|
async function quickChangeStatus(newStatus) {
|
||||||
if (newStatus === order.value?.CurrentStatus) return
|
if (newStatus === order.value?.CurrentStatus) return
|
||||||
@@ -492,7 +538,7 @@ onUnmounted(() => {
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-1 block text-xs font-medium text-gray-400">{{ t('work_order.commit_photos_label') }}</label>
|
<label class="mb-1 block text-xs font-medium text-gray-400">{{ t('work_order.commit_photos_label') }}</label>
|
||||||
<useDropzone
|
<useDropzone
|
||||||
v-model="commitPhotos"
|
ref="commitDropzoneRef"
|
||||||
:maxFiles="10"
|
:maxFiles="10"
|
||||||
:maxSize="10 * 1024 * 1024"
|
:maxSize="10 * 1024 * 1024"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@@ -502,11 +548,11 @@ onUnmounted(() => {
|
|||||||
<!-- 第四行:提交 -->
|
<!-- 第四行:提交 -->
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button
|
<button
|
||||||
:disabled="isCommitting || !canSubmit"
|
:disabled="submittingCommit || !canSubmit"
|
||||||
class="rounded-lg bg-blue-600 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
|
class="rounded-lg bg-blue-600 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
@click="handleCommit"
|
@click="handleCommit"
|
||||||
>
|
>
|
||||||
{{ isCommitting ? '提交中...' : t('work_order.commit_submit') }}
|
{{ submittingCommit ? t('message.submitting') : t('work_order.commit_submit') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -516,9 +562,9 @@ onUnmounted(() => {
|
|||||||
<div v-if="commits.length === 0" class="py-4 text-sm text-gray-400">{{ t('work_order.no_commits') }}</div>
|
<div v-if="commits.length === 0" class="py-4 text-sm text-gray-400">{{ t('work_order.no_commits') }}</div>
|
||||||
<ol v-else class="relative border-l border-gray-200 dark:border-dk-muted">
|
<ol v-else class="relative border-l border-gray-200 dark:border-dk-muted">
|
||||||
<li
|
<li
|
||||||
v-for="commit in [...commits].reverse()"
|
v-for="(commit, index) in commits"
|
||||||
:key="commit.ID"
|
:key="commit.ID"
|
||||||
class="mb-6 ml-4"
|
class="mb-6 ml-4 rounded-lg border border-gray-100 bg-gray-50/50 px-4 py-3 dark:border-dk-muted dark:bg-dk-base/30"
|
||||||
>
|
>
|
||||||
<!-- 时间线圆点 -->
|
<!-- 时间线圆点 -->
|
||||||
<div
|
<div
|
||||||
@@ -545,6 +591,15 @@ onUnmounted(() => {
|
|||||||
</span>
|
</span>
|
||||||
<!-- 时间 -->
|
<!-- 时间 -->
|
||||||
<time class="text-xs text-gray-400">{{ formatDate(commit.CreatedAt) }}</time>
|
<time class="text-xs text-gray-400">{{ formatDate(commit.CreatedAt) }}</time>
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<button
|
||||||
|
v-if="canDeleteCommit(commit, index)"
|
||||||
|
class="ml-auto rounded-lg border border-red-200 bg-red-50 px-3 py-1.5 text-xs font-medium text-red-600 transition-colors hover:bg-red-100 hover:border-red-300 dark:border-red-900/50 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50"
|
||||||
|
@click="handleDeleteCommit(commit.ID)"
|
||||||
|
>
|
||||||
|
<IconTrash :size="14" class="mr-1 inline align-middle" />
|
||||||
|
删除
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 备注文字 -->
|
<!-- 备注文字 -->
|
||||||
@@ -606,4 +661,12 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 删除进度确认弹窗 -->
|
||||||
|
<ConfirmDialog
|
||||||
|
v-model="showDeleteCommitConfirm"
|
||||||
|
:message="t('work_order.confirm_delete_commit')"
|
||||||
|
danger
|
||||||
|
@confirm="confirmDeleteCommit"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user