更新
This commit is contained in:
parent
b0cef59523
commit
4e1cc94bb1
|
@ -57,6 +57,7 @@
|
|||
"vue": "2.6.12",
|
||||
"vue-count-to": "1.0.13",
|
||||
"vue-cropper": "0.5.5",
|
||||
"vue-masonry-css": "^1.0.3",
|
||||
"vue-meta": "2.4.0",
|
||||
"vue-router": "3.4.9",
|
||||
"vuedraggable": "2.24.3",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<template>
|
||||
<div class="component-upload-image">
|
||||
<div
|
||||
class="component-upload-image"
|
||||
@mouseenter="handleMouseEnter"
|
||||
@mouseleave="handleMouseLeave"
|
||||
>
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadImgUrl"
|
||||
|
@ -18,6 +22,7 @@
|
|||
:class="{hide: this.fileList.length >= this.limit}"
|
||||
class="image-upload"
|
||||
:style="cssVars"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
|
@ -46,6 +51,7 @@
|
|||
|
||||
<script>
|
||||
import { getToken } from '@/utils/auth'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -91,7 +97,8 @@ export default {
|
|||
headers: {
|
||||
Authorization: "Bearer " + getToken(),
|
||||
},
|
||||
fileList: []
|
||||
fileList: [],
|
||||
isListening: false // 新增:标记是否正在监听粘贴事件
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
@ -133,6 +140,71 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
// 新增:鼠标进入处理
|
||||
handleMouseEnter() {
|
||||
if (!this.isListening) {
|
||||
document.addEventListener('paste', this.handlePaste);
|
||||
this.isListening = true;
|
||||
}
|
||||
},
|
||||
// 新增:鼠标离开处理
|
||||
handleMouseLeave() {
|
||||
if (this.isListening) {
|
||||
document.removeEventListener('paste', this.handlePaste);
|
||||
this.isListening = false;
|
||||
}
|
||||
},
|
||||
// 粘贴图片上传
|
||||
handlePaste(event) {
|
||||
// 阻止默认行为
|
||||
event.preventDefault();
|
||||
|
||||
const items = event.clipboardData?.items;
|
||||
|
||||
if (!items) {
|
||||
this.$modal.msgError('当前浏览器不支持粘贴上传');
|
||||
return;
|
||||
}
|
||||
|
||||
let file = null;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
file = items[i].getAsFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
this.$modal.msgError('粘贴内容中不包含图片');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否超出数量限制
|
||||
if (this.fileList.length >= this.limit) {
|
||||
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 handleBeforeUpload 进行文件验证
|
||||
const valid = this.handleBeforeUpload(file);
|
||||
if (valid !== false) {
|
||||
// 手动上传文件
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
// 发起上传请求
|
||||
axios.post(this.uploadImgUrl, formData, {
|
||||
headers: {
|
||||
...this.headers,
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
}).then(res => {
|
||||
this.handleUploadSuccess(res.data, file);
|
||||
}).catch(() => {
|
||||
this.handleUploadError();
|
||||
});
|
||||
}
|
||||
},
|
||||
// 上传前loading加载
|
||||
handleBeforeUpload(file) {
|
||||
let isImg = false;
|
||||
|
@ -248,6 +320,14 @@ export default {
|
|||
height: var(--height);
|
||||
}
|
||||
|
||||
::v-deep .el-upload-dragger {
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 图片操作按钮容器 */
|
||||
::v-deep .el-upload-list__item-actions {
|
||||
display: flex;
|
||||
|
|
|
@ -1,59 +1,53 @@
|
|||
<template>
|
||||
<div class="order-flow" v-loading="loading">
|
||||
<el-row :gutter="20" v-if="!isEmpty(list)">
|
||||
<el-col :span="6" v-for="order in list" :key="order.id">
|
||||
<div class="waterfall-container" v-if="!isEmpty(list)" ref="container">
|
||||
<div
|
||||
v-for="(order, index) in list"
|
||||
:key="order.id"
|
||||
class="waterfall-item"
|
||||
:style="itemPositions[index]"
|
||||
>
|
||||
<el-card class="order-card" shadow="hover">
|
||||
<!-- 主图区域 -->
|
||||
<div class="order-main-image">
|
||||
<image-preview :src="order.picture" :width="200" :height="200" />
|
||||
</div>
|
||||
<div class="order-header">
|
||||
<!-- 主图区域 -->
|
||||
<div class="order-main-image">
|
||||
<image-preview :src="order.picture" :width="100" :height="100" />
|
||||
</div>
|
||||
|
||||
<!-- 订单信息区域 -->
|
||||
<div class="order-info">
|
||||
<div class="info-row">
|
||||
<span class="label">订单号:</span>
|
||||
<span class="value">{{ order.orderNo }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">客户名称:</span>
|
||||
<span class="value">{{ order.customer }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">数量:</span>
|
||||
<span class="value">{{ order.num }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">装量:</span>
|
||||
<span class="value">{{ order.reportNum }}/{{ order.num }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">特殊要求:</span>
|
||||
<span class="value">{{ order.remark }}</span>
|
||||
<!-- 订单信息区域 -->
|
||||
<div @click="handleOrderClick(order)">
|
||||
<el-descriptions :column="2" size="small">
|
||||
<el-descriptions-item label="订单" :span="2">{{ order.orderNo | dv}}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户" :span="2">{{ order.customer | dv}}</el-descriptions-item>
|
||||
<el-descriptions-item label="特殊要求" :span="2">{{ order.remark | dv}}</el-descriptions-item>
|
||||
<el-descriptions-item label="数量">{{ order.num | dv}}</el-descriptions-item>
|
||||
<el-descriptions-item label="装量">{{ order.storeNum | dv}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-container">
|
||||
<el-progress :percentage="order.progress" :color="ProgressColors" :format="ProgressFormat" style="width: 100%;" :stroke-width="10"/>
|
||||
</div>
|
||||
|
||||
<!-- 子产品列表 -->
|
||||
<div class="sub-products">
|
||||
<div
|
||||
class="sub-product"
|
||||
v-for="(prod, index) in order.orderProdList"
|
||||
:key="index"
|
||||
>
|
||||
<el-checkbox :value="prod.source === 1" disabled
|
||||
>子产品{{ index + 1 }}</el-checkbox
|
||||
>
|
||||
<div class="sub-product" v-for="(prod, index) in order.prodList" :key="index">
|
||||
<image-preview class="prod-image" :src="prod.picture" :width="28" :height="28" />
|
||||
<span class="prod-name">{{ prod.name | dv }}</span>
|
||||
<dict-tag class="prod-type" :value="prod.workType" :options="dict.type.order_prod_work_type" size="mini"/>
|
||||
<div class="prod-progress">
|
||||
<el-progress
|
||||
:percentage="prod.progress || 0"
|
||||
:color="ProgressColors"
|
||||
:format="ProgressFormat"
|
||||
:stroke-width="6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无进行中的订单" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -66,6 +60,7 @@ import { isEmpty } from '@/utils/index'
|
|||
|
||||
export default {
|
||||
name: 'OrderFlowList',
|
||||
dicts: ['order_prod_work_type'],
|
||||
props: {
|
||||
},
|
||||
data() {
|
||||
|
@ -73,28 +68,127 @@ export default {
|
|||
ProgressColors,
|
||||
list: [],
|
||||
queryParams: {
|
||||
pageSize: 10,
|
||||
pageSize: 12,
|
||||
pageNum: 1,
|
||||
status: OrderStatus.RELEASED,
|
||||
needProd: true,
|
||||
needProdProgress: true,
|
||||
orderByColumn: "createTime",
|
||||
isAsc: "desc"
|
||||
},
|
||||
loading: false,
|
||||
total: 0,
|
||||
itemPositions: [],
|
||||
columnWidth: 300,
|
||||
columnCount: 4,
|
||||
columnHeights: [],
|
||||
resizeObserver: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
mounted() {
|
||||
this.initWaterfall()
|
||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||
if (this.$refs.container) {
|
||||
this.resizeObserver.observe(this.$refs.container)
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect()
|
||||
this.resizeObserver = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleOrderClick(order) {
|
||||
this.$router.push({ path: `/view/order/${order.id}` })
|
||||
},
|
||||
ProgressFormat,
|
||||
isEmpty,
|
||||
getList() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
listOrder(this.queryParams).then(res => {
|
||||
this.list = res.rows;
|
||||
this.total = res.total;
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.$nextTick(() => {
|
||||
this.initWaterfall()
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
initWaterfall() {
|
||||
this.$nextTick(() => {
|
||||
const container = this.$refs.container
|
||||
if (!container) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.resizeObserver && !this.isObserving) {
|
||||
this.resizeObserver.observe(container)
|
||||
this.isObserving = true
|
||||
}
|
||||
|
||||
// 根据容器宽度计算列数,最大4列
|
||||
const containerWidth = container.clientWidth
|
||||
const minColumnWidth = 300 // 最小列宽
|
||||
this.columnCount = Math.min(4, Math.max(1, Math.floor(containerWidth / minColumnWidth)))
|
||||
|
||||
// 计算实际列宽,平均分配容器宽度
|
||||
this.columnWidth = (containerWidth - (this.columnCount + 1) * 8) / this.columnCount // 8px是padding的值
|
||||
|
||||
// 初始化列高度数组
|
||||
this.columnHeights = new Array(this.columnCount).fill(0)
|
||||
|
||||
// 计算每个卡片的位置
|
||||
this.layoutItems()
|
||||
})
|
||||
},
|
||||
layoutItems() {
|
||||
const items = this.$refs.container?.getElementsByClassName('waterfall-item')
|
||||
if (!items) return
|
||||
|
||||
this.columnHeights = new Array(this.columnCount).fill(0)
|
||||
this.itemPositions = []
|
||||
|
||||
Array.from(items).forEach((item, index) => {
|
||||
const minHeight = Math.min(...this.columnHeights)
|
||||
const column = this.columnHeights.indexOf(minHeight)
|
||||
|
||||
// 计算每列的x坐标,考虑padding间距
|
||||
const left = column * this.columnWidth + (column + 1) * 8
|
||||
const top = minHeight
|
||||
|
||||
this.itemPositions[index] = {
|
||||
transform: `translate3d(${left}px, ${top}px, 0)`,
|
||||
width: `${this.columnWidth}px`
|
||||
}
|
||||
|
||||
this.columnHeights[column] = minHeight + item.offsetHeight + 8
|
||||
})
|
||||
|
||||
const containerHeight = Math.max(...this.columnHeights)
|
||||
this.$refs.container.style.height = `${containerHeight}px`
|
||||
},
|
||||
handleResize() {
|
||||
if (this.resizeTimer) {
|
||||
clearTimeout(this.resizeTimer)
|
||||
}
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
this.initWaterfall()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
list: {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.initWaterfall()
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,45 +196,104 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.order-flow {
|
||||
.waterfall-container {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.waterfall-item {
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 0;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.order-main-image {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.order-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
.info-row {
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
.progress-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #606266;
|
||||
width: 70px;
|
||||
}
|
||||
.order-main-image {
|
||||
text-align: center;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
color: #303133;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.order-info {
|
||||
.info-row {
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
|
||||
.label {
|
||||
color: #606266;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
color: #303133;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-products {
|
||||
margin-top: 15px;
|
||||
.sub-products {
|
||||
|
||||
.sub-product {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
.sub-title {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.prod-progress {
|
||||
flex: 1;
|
||||
margin-left: 10px;
|
||||
.sub-product {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
margin-bottom: 4px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s ease;
|
||||
background: #f8f9fb;
|
||||
|
||||
&:hover {
|
||||
background: #f0f2f5;
|
||||
}
|
||||
|
||||
.prod-image {
|
||||
margin-right: 12px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.prod-name {
|
||||
flex: 1;
|
||||
margin-right: 12px;
|
||||
color: #303133;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.prod-type {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.prod-progress {
|
||||
width: 160px;
|
||||
|
||||
:deep(.el-progress-bar__outer) {
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<edit-header :title="title">
|
||||
<el-button plain @click="cancel" icon="el-icon-close" size="small">取消</el-button>
|
||||
<el-button type="primary" plain @click="submitForm(false)" icon="el-icon-check" size="small">保存</el-button>
|
||||
<el-button type="primary" @click="submitForm(true)" icon="el-icon-s-check" size="small" v-if="OrderStatus.canRelease().includes(form.status)">保存并发布</el-button>
|
||||
<el-button type="primary" @click="submitForm(true)" icon="el-icon-s-check" size="small" v-if="form.id == null || OrderStatus.canRelease().includes(form.status)">保存并发布</el-button>
|
||||
</edit-header>
|
||||
|
||||
<div class="app-container">
|
||||
|
@ -10,7 +11,7 @@
|
|||
<div class="edit-title">基础信息</div>
|
||||
<el-row>
|
||||
<form-col :span="span" label="主图" prop="picture">
|
||||
<image-upload v-model="form.picture" :limit="1"/>
|
||||
<image-upload v-model="form.picture" :limit="1" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="订单编号" prop="orderNo">
|
||||
<el-input v-model="form.orderNo" placeholder="请输入订单编号"/>
|
||||
|
@ -160,6 +161,9 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
this.$tab.closeBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -308,11 +308,11 @@ export default {
|
|||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.$router.push("/edit/order");
|
||||
this.$tab.closeOpenPage("/edit/order")
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.$router.push(`/edit/order/${row.id}`)
|
||||
this.$tab.closeOpenPage(`/edit/order/${row.id}`)
|
||||
},
|
||||
// 完工
|
||||
handleFinish(row) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="process-card-list">
|
||||
<div class="process-card-list" v-if="!isEmpty(data)">
|
||||
<el-card
|
||||
v-for="(item, index) in data"
|
||||
:key="index"
|
||||
|
@ -50,10 +50,12 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-empty v-else description="暂无数据"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ProgressColors, ProgressFormat } from '@/utils/constants'
|
||||
import { isEmpty } from '@/utils/index'
|
||||
|
||||
export default {
|
||||
name: 'ProcessCardList',
|
||||
|
@ -70,6 +72,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
ProgressFormat,
|
||||
isEmpty
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
<panel-group />
|
||||
|
||||
<div class="order-flow-title">进行中的订单</div>
|
||||
<div class="group-title">
|
||||
<i class="el-icon-s-order"></i>
|
||||
进行中的订单
|
||||
</div>
|
||||
<order-flow-list />
|
||||
|
||||
</div>
|
||||
|
@ -30,4 +33,11 @@ export default {
|
|||
.dashboard-editor-container {
|
||||
padding: 32px;
|
||||
}
|
||||
.group-title {
|
||||
background: linear-gradient(to right, #409EFF, #ffffff 50% );
|
||||
color: #fff;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue
Block a user