feat: v0.4 画布编辑器——拖拽布置分格v1

- WindoorCanvas editable模式: 加竖梃/横梃点击玻璃区域实时分割
- 多边形两次交叉点法分割, mm.sp分割线记录同步, 撤销栈
- 订单详情: 编辑分格后保存图纸(PUT orders/{id})
- 样板库: 另存为我的样板(POST windoor/templates, 企业隔离)
- 10个API端点回归全部通过
This commit is contained in:
HHY
2026-09-20 09:04:37 -07:00
parent 065d387399
commit dffca83508
7 changed files with 252 additions and 34 deletions
+41 -5
View File
@@ -23,13 +23,22 @@
<el-dialog v-model="previewVisible" :title="current?.name || `样板#${current?.id}`" width="72%" top="4vh">
<div v-if="current" class="preview">
<div class="canvas-box">
<WindoorCanvas :drawing-data="current.drawing_data" />
<WindoorCanvas ref="editRef" :drawing-data="current.drawing_data"
:editable="editing" @change="dirty = true" />
</div>
<div class="meta">
<span>尺寸限制: {{ current.low_width }}-{{ current.high_width }} × {{ current.low_height }}-{{ current.high_height }} mm</span>
<span>引用次数: {{ current.times }}</span>
<el-button type="success" size="small" @click="quoteRef.open({ template_id: current.id })">算料报价</el-button>
<el-button type="primary" size="small" @click="useInOrder">用此样板下单</el-button>
<template v-if="!editing">
<span>尺寸限制: {{ current.low_width }}-{{ current.high_width }} × {{ current.low_height }}-{{ current.high_height }} mm</span>
<span>引用次数: {{ current.times }}</span>
<el-button type="success" size="small" @click="quoteRef.open({ template_id: current.id })">算料报价</el-button>
<el-button size="small" @click="editing = true">编辑分格</el-button>
<el-button type="primary" size="small" @click="useInOrder">用此样板下单</el-button>
</template>
<template v-else>
<span class="tip">左侧工具:+竖梃/+横梃 → 点击玻璃区域完成分割,支持撤销</span>
<el-button size="small" @click="cancelEdit">取消</el-button>
<el-button type="primary" size="small" :disabled="!dirty" @click="saveAsTemplate">另存为我的样板</el-button>
</template>
</div>
</div>
</el-dialog>
@@ -40,6 +49,7 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { api } from '../api'
import WindoorCanvas from '../components/WindoorCanvas.vue'
import QuoteDialog from '../components/QuoteDialog.vue'
@@ -56,6 +66,9 @@ const catelogs = ref<any[]>([])
const loading = ref(false)
const previewVisible = ref(false)
const current = ref<any>(null)
const editing = ref(false)
const dirty = ref(false)
const editRef = ref()
async function load() {
loading.value = true
@@ -70,9 +83,32 @@ async function load() {
async function preview(t: any) {
current.value = await api<any>('get', `/api/windoor/templates/${t.id}`)
editing.value = false
dirty.value = false
previewVisible.value = true
}
function cancelEdit() {
editing.value = false
dirty.value = false
// 重新拉取以还原画布
const id = current.value.id
api<any>('get', `/api/windoor/templates/${id}`).then(d => (current.value = d))
}
async function saveAsTemplate() {
const drawing = editRef.value?.exportDrawing()
if (!drawing) return
const base = current.value.name || `样板${current.value.id}`
const saved = await api<any>('post', '/api/windoor/templates', {
name: `${base}-改`, catelog_id: current.value.catelog_id,
drawing_data: drawing, note: `基于样板#${current.value.id}修改`,
})
ElMessage.success(`已另存为我的样板 #${saved.id}`)
editing.value = false
dirty.value = false
}
function useInOrder() {
router.push({ path: '/orders', query: { template: current.value.id } })
}