合并工序看板重排、订单开工与派工列表展示调整。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
tzy 2026-08-03 10:53:13 +08:00
parent 44ca42ce18
commit cf7a8e9cd6
6 changed files with 545 additions and 178 deletions

View File

@ -125,7 +125,11 @@ export const orderItemApi = {
//派工
assignWork(data: any) {
return request({ url: '/biz/orderItem/assignWork', method: 'post', data })
},
},
// 开工
startWork(id: number) {
return request({ url: `/biz/orderItem/${id}/startWork`, method: 'post' })
},
//根据生产编号查询预生产订单
preCreation(data: any) {
return request({ url: '/biz/orderItem/preCreation', method: 'post', data })

View File

@ -475,6 +475,18 @@ export const orderProcessPlanApi = {
})
},
/**
*
* orderItemId + planId sort10/20/30
*/
reorder(data: ProcessPlanReorderPayload) {
return request({
url: '/biz/orderProcessPlan/reorder',
method: 'put',
data,
})
},
}
/** 委外可选工序项 */
@ -515,3 +527,16 @@ export interface OutsourcingCreate {
remark?: string
}
/** 工序重排明细 */
export interface ProcessPlanReorderItem {
planId: number
/** 可选;不传则按数组顺序由后端分配 sort */
sort?: number
}
/** 订单级工序重排请求 */
export interface ProcessPlanReorderPayload {
orderItemId: number
items: ProcessPlanReorderItem[]
}

View File

@ -37,10 +37,10 @@
<n-button type="error" :disabled="kingdeeLoading" @click="reCrawlReorderForm">
重新读取数据
</n-button>
<n-button type="primary" :disabled="kingdeeLoading" @click="handleSaveDraft">
<n-button type="primary" :disabled="kingdeeLoading" :loading="actionLoading" @click="handleSaveDraft">
保存草稿
</n-button>
<n-button type="info" :disabled="kingdeeLoading" @click="handleSyncOrderAndPlan">
<n-button type="info" :disabled="kingdeeLoading" :loading="actionLoading" @click="handleSyncOrderAndPlan">
同步订单计划
</n-button>
<n-button @click="$emit('close-modal')">关闭</n-button>
@ -332,26 +332,29 @@ function handleGanttSchedule() {
router.push('/biz/orderProject/gantt')
}
//
// loading
async function handleSyncOrderAndPlan() {
if (!props.selectedId) return
if (!props.selectedId || actionLoading.value) return
actionLoading.value = true
try {
// processRoutes children
const draftData = kingdeeTableData.value.map(mo => {
const { processRoutes, ...rest } = mo
return { ...rest, children: processRoutes } as KingdeePrdMo
})
emit('synchronizationCallback', props.selectedId, draftData, (res) => {
if("success" === res){
message.success('同步订单计划成功')
emit('close-modal')
}
const res = await new Promise<unknown>((resolve, reject) => {
emit('synchronizationCallback', props.selectedId, draftData, (result: unknown, err?: unknown) => {
if (err) reject(err)
else resolve(result)
})
kingdeeModalVisible.value = false
} catch (error) {
})
if (res === 'success') {
message.success('同步订单计划成功')
emit('close-modal')
}
} catch {
//
} finally {
actionLoading.value = false

View File

@ -1,102 +1,95 @@
<template>
<div class="page-container">
<n-card>
<!-- 搜索表单 -->
<div class="search-form">
<n-form inline :model="searchForm" label-placement="left">
<n-form-item label="生产令号">
<n-input v-model:value="searchForm.productionCode" placeholder="请输入生产令号" clearable />
</n-form-item>
<n-form-item label="物料编码">
<n-input v-model:value="searchForm.code" placeholder="请输入物料编码" clearable />
</n-form-item>
<n-form-item label="项目名称">
<n-input v-model:value="searchForm.projectName" placeholder="请输入产品名称" clearable />
</n-form-item>
<n-form-item label="开始时间">
<n-date-picker v-model:value="searchForm.beginTime" type="datetime" clearable />
</n-form-item>
<n-form-item label="结束时间">
<n-date-picker v-model:value="searchForm.endTime" type="datetime" clearable />
</n-form-item>
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSearch">
<template #icon><n-icon><SearchOutline /></n-icon></template>
搜索
</n-button>
<n-button @click="handleReset">
<template #icon><n-icon><RefreshOutline /></n-icon></template>
重置
</n-button>
</n-space>
</n-form-item>
</n-form>
</div>
<div class="order-layout">
<!-- 左侧生产令号 -->
<n-card class="order-tree-card" size="small">
<template #header>
<div class="order-tree-header">生产令号</div>
</template>
<div class="order-search">
<n-input v-model:value="projectTreeSearch" placeholder="搜索生产令号" clearable size="small">
<template #prefix>
<n-icon><SearchOutline /></n-icon>
</template>
</n-input>
</div>
<div class="order-tree-wrapper">
<n-tree
:data="projectTreeData"
:pattern="projectTreeSearch"
:selected-keys="selectedProjectKeys"
:node-props="projectNodeProps"
key-field="id"
label-field="label"
selectable
block-line
/>
</div>
</n-card>
<!-- 工具栏 -->
<div class="table-toolbar">
<n-space>
<!--<n-button
size="small"
type="primary"
@click="handleAdd"
<!-- 右侧生产订单列表 -->
<n-card class="order-list-card" size="small">
<template #header>
<div class="card-header">
<span>{{ selectedProjectLabel ? `${selectedProjectLabel}】生产订单` : '全部生产订单' }}</span>
</div>
</template>
<!-- 搜索表单 -->
<div class="search-form">
<n-form inline :model="searchForm" label-placement="left">
<n-form-item label="物料编码">
<n-input v-model:value="searchForm.code" placeholder="请输入物料编码" clearable />
</n-form-item>
<n-form-item label="开始时间">
<n-date-picker v-model:value="searchForm.beginTime" type="datetime" clearable />
</n-form-item>
<n-form-item label="结束时间">
<n-date-picker v-model:value="searchForm.endTime" type="datetime" clearable />
</n-form-item>
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSearch">
<template #icon><n-icon><SearchOutline /></n-icon></template>
搜索
</n-button>
<n-button @click="handleReset">
<template #icon><n-icon><RefreshOutline /></n-icon></template>
重置
</n-button>
</n-space>
</n-form-item>
</n-form>
</div>
<n-data-table
size="small"
remote
striped
:border="false"
:single-line="false"
:columns="columns"
:data="tableData"
:loading="loading"
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #icon><n-icon><AddOutline /></n-icon></template>
新增/补单
</n-button>
<n-button @click="importModalVisible = true">
<template #icon><n-icon><CloudUploadOutline /></n-icon></template>
导入
</n-button>
<n-button @click="handleExport">
<template #icon><n-icon><DownloadOutline /></n-icon></template>
导出{{ selectedIds.length > 0 ? `(${selectedIds.length})` : '' }}
</n-button>
<n-button type="error" :disabled="selectedIds.length === 0" @click="handleBatchDelete">
<template #icon><n-icon><TrashOutline /></n-icon></template>
删除
</n-button> -->
</n-space>
</div>
<!-- 表格 -->
<!--
:row-key="(row) => row.id"
:scroll-x="1200"
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
@update:checked-row-keys="handleCheck"
:pagination="pagination"
-->
<!--flex-height-->
<n-data-table
size="small"
remote
striped
:border="false"
:single-line="false"
:columns="columns"
:data="tableData"
:loading="loading"
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div>
</n-card>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div>
</n-card>
</div>
<!-- 新增/编辑弹窗 -->
<n-modal
@ -385,8 +378,9 @@
</template>
<script setup lang="ts">
import { ref, reactive, h, computed, onMounted } from 'vue'
import { NButton, NSpace, NIcon, NTag, useMessage, useDialog, type UploadCustomRequestOptions} from 'naive-ui'
import { ref, reactive, h, computed, onMounted, type HTMLAttributes } from 'vue'
import { NButton, NSpace, NIcon, NTag, useMessage, useDialog, type UploadCustomRequestOptions, type TreeOption } from 'naive-ui'
import { SearchOutline, RefreshOutline, CreateOutline, PlayOutline, DocumentTextOutline } from '@vicons/ionicons5'
import { orderItemApi, type OrderItem } from '@/api/orderItem'
import { useUserStore } from '@/stores/user'
import { VueDraggable } from 'vue-draggable-plus'
@ -413,7 +407,6 @@ const hasPermission = (permission: string) => userStore.hasPermission(permission
//
const searchForm = reactive<any>({
productionCode: '',
code: '',
projectName: '',
orderCode: '',
@ -423,6 +416,56 @@ const searchForm = reactive<any>({
endTime: null as number | null,
})
//
type ProjectTreeNode = {
id: number
label: string
projectCode: string
projectName: string
}
const projectTreeSearch = ref('')
const projectTreeData = ref<ProjectTreeNode[]>([])
const selectedProjectKeys = ref<Array<string | number>>([])
const selectedProjectId = ref<number | undefined>(undefined)
const selectedProjectLabel = ref('')
const projectNodeProps = ({ option }: { option: TreeOption }): HTMLAttributes => {
return {
onClick() {
const id = option.id as number
if (selectedProjectId.value === id) {
selectedProjectId.value = undefined
selectedProjectKeys.value = []
selectedProjectLabel.value = ''
} else {
selectedProjectId.value = id
selectedProjectKeys.value = [id]
selectedProjectLabel.value = (option.projectCode as string) || (option.label as string) || ''
}
pagination.page = 1
loadData()
}
}
}
async function loadProjectTree() {
try {
const data = await orderItemApi.xmoptions({})
projectTreeData.value = (Array.isArray(data) ? data : []).map((item: any) => {
const projectCode = item?.additionParams?.projectCode || ''
const projectName = item?.label || ''
return {
id: Number(item.value),
label: projectCode || projectName,
projectCode,
projectName,
}
}).filter((n: ProjectTreeNode) => n.id && n.label)
} catch {
projectTreeData.value = []
}
}
//
@ -487,7 +530,7 @@ const columns = computed(() => [
{
align:'center',
title: '生产令号',
key: 'productionCode',
key: 'mainCode',
width: '140'
},
{
@ -607,7 +650,10 @@ const columns = computed(() => [
align:'center',
title: '是否开工',
key: 'starter',
width:"120"
width:"120",
render(row: any) {
return row.starter === 1 ? '已开工' : '未开工'
}
},
{
align:'center',
@ -619,51 +665,45 @@ const columns = computed(() => [
align:'center',
title: '操作',
key: 'actions',
width: 190,
width: 260,
fixed:"right",
render(row:any) {
const buttons: ReturnType<typeof h>[] = []
const buttons:any = []
if(hasPermission('biz:orderItem:edit')){
buttons.push(h(NButton, {
size: 'small',
type:'primary',
ghost:true,
onClick: () => { handleEdit(row) } },
{ default: () => '编辑'}
))
}
// if(hasPermission('biz:orderItem:assign')){
// buttons.push(h(NButton, {
// size: 'small',
// type:'success',
// ghost:true,
// onClick: () => { disphand(row) } },
// { default: () => ''}
// ))
// }
if(hasPermission('biz:orderItem:reorderForm')){
buttons.push(h(NButton, {
size: 'small',
type:'info',
ghost:true,
onClick: () => handleReorderForm(row, false) }, //, disabled: row.starter !==1
{ default: () => '补单'}
))
}
if (hasPermission('biz:orderItem:edit')) {
buttons.push(h(NButton, {
size: 'small',
quaternary: true,
onClick: () => handleEdit(row),
}, {
default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' 编辑'],
}))
}
// 线
if (hasPermission('biz:orderItem:startWork') && row.starter !== 1 && row.parentId && row.routeCode) {
buttons.push(h(NButton, {
size: 'small',
quaternary: true,
type: 'warning',
onClick: () => handleStartWork(row),
}, {
default: () => [h(NIcon, null, { default: () => h(PlayOutline) }), ' 开工'],
}))
}
if (hasPermission('biz:orderItem:reorderForm')) {
buttons.push(h(NButton, {
size: 'small',
quaternary: true,
type: 'info',
onClick: () => handleReorderForm(row, false),
}, {
default: () => [h(NIcon, null, { default: () => h(DocumentTextOutline) }), ' 补单'],
}))
}
return buttons.length > 0 ? h(NSpace, {justify:'center'}, { default: () => buttons }) : '-'
// return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'nowrap' } }, [
// h(NButton, { size: 'small', quaternary: true, onClick: () => handleEdit(row) }, {
// default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' ']
// }),
// h(NButton, { size: 'small', quaternary: true, type: 'error', onClick: () => handleDelete(row) }, {
// default: () => [h(NIcon, null, { default: () => h(TrashOutline) }), ' ']
// })
// ])
return buttons.length > 0
? h('div', { style: { display: 'flex', alignItems: 'center', gap: '4px', flexWrap: 'nowrap', justifyContent: 'center' } }, buttons)
: '-'
}
}
])
@ -688,12 +728,9 @@ async function loadData() {
const res = await orderItemApi.page({
page: pagination.page,
pageSize: pagination.pageSize,
productionCode: searchForm.productionCode || undefined,
code: searchForm.code,
projectName: searchForm.projectName,
orderCode: searchForm.orderCode,
routeCode: searchForm.routeCode,
proWorkshop: searchForm.proWorkshop,
projectId: selectedProjectId.value,
code: searchForm.code || undefined,
projectName: searchForm.projectName || undefined,
beginTime: searchForm.beginTime,
endTime: searchForm.endTime
})
@ -712,7 +749,6 @@ function handleSearch() {
//
function handleReset() {
searchForm.productionCode = ''
searchForm.code = ''
searchForm.projectName = ''
searchForm.orderCode = ''
@ -720,6 +756,10 @@ function handleReset() {
searchForm.proWorkshop = ''
searchForm.beginTime = null
searchForm.endTime = null
selectedProjectId.value = undefined
selectedProjectKeys.value = []
selectedProjectLabel.value = ''
projectTreeSearch.value = ''
handleSearch()
}
@ -872,19 +912,14 @@ async function holdTemporarilySave(id: number, data: KingdeePrdMo[]) {
// }
// }
//
async function synchronizationSave(id: number, data: KingdeePrdMo[], callback:Function) {
// callback
async function synchronizationSave(id: number, data: KingdeePrdMo[], callback: Function) {
try {
// processRoutes children
await orderItemApi.synchronizationSave(id, data)
.then((rps:any) =>{
callback(rps)
}).catch((res) => {
callback(res)
})
const rps = await orderItemApi.synchronizationSave(id, data)
callback(rps)
} catch (error) {
//
}
callback(null, error)
}
}
@ -1092,6 +1127,25 @@ function handleDelete(row: OrderItem) {
})
}
//
function handleStartWork(row: OrderItem) {
dialog.warning({
title: '提示',
content: `确定开工订单【${row.orderCode || row.name}】?开工后将生成工单。`,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
try {
await orderItemApi.startWork(row.id!)
message.success('开工成功')
loadData()
} catch (error) {
//
}
}
})
}
//
function handleBatchDelete() {
dialog.warning({
@ -1182,6 +1236,7 @@ async function loadDictOptions() {
}
onMounted(() => {
loadProjectTree()
loadData()
loadDictOptions()
@ -1192,6 +1247,41 @@ onMounted(() => {
</script>
<style scoped>
.order-layout {
display: flex;
gap: 12px;
height: 100%;
}
.order-tree-card {
width: 280px;
flex-shrink: 0;
}
.order-tree-header {
font-weight: bold;
}
.order-search {
margin-bottom: 10px;
}
.order-tree-wrapper {
height: calc(100vh - 280px);
overflow-y: auto;
}
.order-list-card {
flex: 1;
min-width: 0;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.search-form {
margin-bottom: 16px;
}

View File

@ -139,7 +139,14 @@
<div class="col-actions">
<n-button text type="primary" size="tiny" @click="openDetail(order)">详情</n-button>
<n-button text type="info" size="tiny" @click="openPlmModel(order)">模型</n-button>
<n-button text type="primary" size="tiny" disabled title="订单级编辑待支持">编辑</n-button>
<!-- 订单级编辑打开工序顺序重排弹窗不进单工序编辑 -->
<n-button
text
type="primary"
size="tiny"
:disabled="!hasPermission('biz:orderProcessPlan:edit')"
@click="openReorder(order)"
>编辑</n-button>
<n-dropdown :options="moreOptions" trigger="click" @select="(k) => onMoreSelect(k, order)">
<n-button text size="tiny">更多</n-button>
</n-dropdown>
@ -271,7 +278,81 @@
</n-spin>
</n-modal>
<!-- 新增/编辑 -->
<!-- 订单级工序顺序重排拖拽 / 上移下移只提交 planId 顺序 -->
<n-modal
v-model:show="reorderVisible"
preset="card"
title="调整工序顺序"
style="width: 640px"
:mask-closable="false"
@after-leave="resetReorder"
>
<n-spin :show="reorderLoading">
<n-alert type="info" style="margin-bottom: 12px">
拖拽行或使用上移/下移调整顺序保存后按 102030 重写工序号存在派工工单或已有转出数量的工序不可调整
</n-alert>
<div v-if="reorderOrderMeta" class="reorder-meta">
<span>令号{{ reorderOrderMeta.mainCode || '-' }}</span>
<span>物料{{ reorderOrderMeta.materialName || '-' }}</span>
<span>数量{{ reorderOrderMeta.quantity ?? '-' }}</span>
</div>
<div v-if="!reorderList.length && !reorderLoading" class="reorder-empty">暂无工序可调整</div>
<VueDraggable
v-else
v-model="reorderList"
:animation="150"
handle=".reorder-drag-handle"
class="reorder-list"
>
<div
v-for="(proc, idx) in reorderList"
:key="proc.planId ?? idx"
class="reorder-item"
>
<n-icon class="reorder-drag-handle" size="18" :depth="3">
<MenuOutline />
</n-icon>
<span class="reorder-index">{{ idx + 1 }}</span>
<div class="reorder-body">
<div class="reorder-title">
<em v-if="proc.operNumber != null">{{ proc.operNumber }}</em>
{{ proc.processName || '-' }}
</div>
<div class="reorder-sub">
{{ proc.processCode || '-' }} · {{ proc.workOrderCode || '-' }}
</div>
</div>
<n-space :size="4">
<n-button
size="tiny"
quaternary
:disabled="idx === 0"
@click="moveReorderItem(idx, -1)"
>上移</n-button>
<n-button
size="tiny"
quaternary
:disabled="idx === reorderList.length - 1"
@click="moveReorderItem(idx, 1)"
>下移</n-button>
</n-space>
</div>
</VueDraggable>
</n-spin>
<template #footer>
<n-space justify="end">
<n-button @click="reorderVisible = false">取消</n-button>
<n-button
type="primary"
:loading="reorderSubmitLoading"
:disabled="!reorderList.length"
@click="submitReorder"
>保存顺序</n-button>
</n-space>
</template>
</n-modal>
<!-- 新增/编辑单工序字段顺序请用上方重排弹窗 -->
<n-modal v-model:show="modalVisible" preset="card" :title="modalTitle" style="width: 800px">
<n-form ref="formRef" :model="formData" :rules="formRules" label-placement="left" label-width="120px">
<n-grid :cols="2">
@ -286,8 +367,9 @@
</n-form-item>
</n-gi>
<n-gi>
<!-- 顺序请走订单行编辑重排避免单条改 sort 撞号断链 -->
<n-form-item label="工序顺序" path="sort">
<n-input v-model:value="formData.sort" placeholder="请输入工序顺序" />
<n-input v-model:value="formData.sort" placeholder="请通过订单编辑调整顺序" disabled />
</n-form-item>
</n-gi>
<n-gi>
@ -590,7 +672,9 @@ import {
DownloadOutline, ChevronDownOutline, CheckmarkCircleOutline, CheckmarkCircle,
EllipseOutline, TimeOutline, PrintOutline, SyncOutline, PeopleOutline,
GitBranchOutline, CloseCircleOutline, LockClosedOutline, TrashOutline, EyeSharp,
MenuOutline,
} from '@vicons/ionicons5'
import { VueDraggable } from 'vue-draggable-plus'
import {
orderProcessPlanApi,
toOrderProcessPlanPayload,
@ -632,6 +716,15 @@ const detailVisible = ref(false)
const detailLoading = ref(false)
const detailData = ref<OrderProcessPlanVO | null>(null)
/** 订单级工序重排弹窗状态 */
const reorderVisible = ref(false)
const reorderLoading = ref(false)
const reorderSubmitLoading = ref(false)
const reorderOrderItemId = ref<number | null>(null)
const reorderOrderMeta = ref<OrderProcessPlanVO | null>(null)
/** 弹窗内可拖拽的工序列表(按当前展示顺序) */
const reorderList = ref<ProcessPlanItemVO[]>([])
const modalVisible = ref(false)
const modalTitle = ref('')
const formRef = ref()
@ -1032,6 +1125,79 @@ async function openDetail(order: OrderProcessPlanVO) {
}
}
/** 打开订单级工序顺序调整(拉详情,按 operNumber 排序后供拖拽) */
async function openReorder(order: OrderProcessPlanVO) {
if (!order.orderItemId) {
message.warning('缺少生产订单id')
return
}
reorderVisible.value = true
reorderLoading.value = true
reorderOrderItemId.value = order.orderItemId
reorderOrderMeta.value = order
reorderList.value = []
try {
const detail = await orderProcessPlanApi.detail(order.orderItemId)
reorderOrderMeta.value = detail
// operNumber sort
reorderList.value = sortedProcessList(detail.processList).map((p) => ({ ...p }))
if (!reorderList.value.length) {
message.warning('当前订单暂无工序计划')
}
} catch {
//
reorderList.value = sortedProcessList(order.processList).map((p) => ({ ...p }))
} finally {
reorderLoading.value = false
}
}
function resetReorder() {
reorderOrderItemId.value = null
reorderOrderMeta.value = null
reorderList.value = []
reorderSubmitLoading.value = false
}
/** 上移 / 下移delta: -1 上移,+1 下移) */
function moveReorderItem(index: number, delta: number) {
const next = index + delta
if (next < 0 || next >= reorderList.value.length) return
const list = [...reorderList.value]
const [item] = list.splice(index, 1)
list.splice(next, 0, item)
reorderList.value = list
}
/** 提交重排:只传 orderItemId + planId 顺序 */
async function submitReorder() {
if (!reorderOrderItemId.value) {
message.warning('缺少生产订单id')
return
}
if (!reorderList.value.length) {
message.warning('暂无工序可保存')
return
}
const missing = reorderList.value.some((p) => p.planId == null)
if (missing) {
message.error('存在缺少 planId 的工序,请刷新后重试')
return
}
reorderSubmitLoading.value = true
try {
await orderProcessPlanApi.reorder({
orderItemId: reorderOrderItemId.value,
items: reorderList.value.map((p) => ({ planId: p.planId! })),
})
message.success('工序顺序已更新')
reorderVisible.value = false
loadData()
} finally {
reorderSubmitLoading.value = false
}
}
function handleAdd() {
modalTitle.value = '新增工序计划'
Object.assign(formData, defaultFormData)
@ -1512,4 +1678,83 @@ onMounted(loadData)
font-size: 12px;
color: #8c8c8c;
}
.reorder-meta {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-bottom: 12px;
font-size: 13px;
color: #595959;
}
.reorder-empty {
padding: 24px 0;
text-align: center;
color: #8c8c8c;
font-size: 13px;
}
.reorder-list {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 420px;
overflow-y: auto;
}
.reorder-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
background: #fafbfc;
border: 1px solid #eef0f3;
border-radius: 8px;
}
.reorder-drag-handle {
cursor: grab;
flex-shrink: 0;
color: #8c8c8c;
}
.reorder-drag-handle:active {
cursor: grabbing;
}
.reorder-index {
width: 22px;
text-align: center;
font-size: 13px;
font-weight: 600;
color: #2080f0;
flex-shrink: 0;
}
.reorder-body {
flex: 1;
min-width: 0;
}
.reorder-title {
font-size: 14px;
font-weight: 600;
color: #1a1a1a;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.reorder-title em {
font-style: normal;
margin-right: 6px;
color: #2080f0;
}
.reorder-sub {
margin-top: 2px;
font-size: 12px;
color: #8c8c8c;
}
</style>

View File

@ -18,7 +18,7 @@
:data="AssingWorkTableData"
:loading="tableLoading"
:row-key="RowKey"
:scroll-x="600"
:scroll-x="1800"
:max-height="1000"
size="small"
style="margin-bottom:15px"