后端: - 产品价格本模块(型材/玻璃/五金/配件, 供报价取价) - 报价单模块(BJ单号, 手动报价/样板算料/转订单) - 售后单(问题描述必填, 对齐原站校验)与状态流转 - 量尺单(洞口尺寸清单)与阳光房订单(order_type=1) - 个人中心: 资料/密码修改/邀请返利(HMC邀请码) 前端: - 新增8页面: 产品/报价单/售后/量尺/阳光房/商城/使用指南/个人中心 - 登录页注册双Tab, 响应式侧边栏(<900px自动折叠) - Element Plus 图标全局注册修复 - 共15个页面覆盖原站核心业务路由
108 lines
4.7 KiB
Vue
108 lines
4.7 KiB
Vue
<template>
|
|
<el-card>
|
|
<div class="toolbar">
|
|
<el-input v-model="keyword" placeholder="名称/规格" clearable style="width:200px" @keyup.enter="load" />
|
|
<el-select v-model="material" placeholder="全部类型" clearable style="width:130px" @change="load">
|
|
<el-option value="profile" label="型材" /><el-option value="glass" label="玻璃" />
|
|
<el-option value="hardware" label="五金" /><el-option value="addon" label="配件" />
|
|
</el-select>
|
|
<el-button type="primary" @click="load">查询</el-button>
|
|
<div style="flex:1" />
|
|
<el-button type="primary" plain @click="openEdit()">新增产品</el-button>
|
|
</div>
|
|
<el-table :data="rows" v-loading="loading" stripe>
|
|
<el-table-column prop="name" label="名称" min-width="140" />
|
|
<el-table-column label="类型" width="80">
|
|
<template #default="{ row }">{{ label(row.material) }}</template>
|
|
</el-table-column>
|
|
<el-table-column prop="spec" label="规格" width="120" />
|
|
<el-table-column prop="unit" label="单位" width="70" />
|
|
<el-table-column prop="price" label="售价" width="90" />
|
|
<el-table-column prop="cost" label="成本" width="90" />
|
|
<el-table-column label="操作" width="140" fixed="right">
|
|
<template #default="{ row }">
|
|
<el-button size="small" @click="openEdit(row)">编辑</el-button>
|
|
<el-button size="small" type="danger" plain @click="remove(row)">删</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<el-pagination style="margin-top:12px; justify-content:flex-end" background layout="total, prev, pager, next"
|
|
:total="total" :page-size="page_size" v-model:current-page="page" @current-change="load" />
|
|
|
|
<el-dialog v-model="editVisible" :title="form.id ? '编辑产品' : '新增产品'" width="480px">
|
|
<el-form :model="form" label-width="70px">
|
|
<el-form-item label="名称"><el-input v-model="form.name" /></el-form-item>
|
|
<el-form-item label="类型">
|
|
<el-select v-model="form.material" style="width:100%">
|
|
<el-option value="profile" label="型材" /><el-option value="glass" label="玻璃" />
|
|
<el-option value="hardware" label="五金" /><el-option value="addon" label="配件" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="规格"><el-input v-model="form.spec" /></el-form-item>
|
|
<el-form-item label="单位"><el-input v-model="form.unit" style="width:100px" /></el-form-item>
|
|
<el-form-item label="售价"><el-input-number v-model="form.price" :min="0" :precision="2" /></el-form-item>
|
|
<el-form-item label="成本"><el-input-number v-model="form.cost" :min="0" :precision="2" /></el-form-item>
|
|
<el-form-item label="备注"><el-input v-model="form.note" type="textarea" /></el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="editVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="save">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</el-card>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, reactive, ref } from 'vue'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { api } from '../api'
|
|
|
|
const rows = ref<any[]>([])
|
|
const total = ref(0)
|
|
const page = ref(1)
|
|
const page_size = 15
|
|
const keyword = ref('')
|
|
const material = ref<string | undefined>()
|
|
const loading = ref(false)
|
|
const editVisible = ref(false)
|
|
const form = reactive<any>({ id: 0, name: '', material: 'profile', spec: '', unit: '米', price: 0, cost: 0, note: '' })
|
|
|
|
const label = (m: string) => ({ profile: '型材', glass: '玻璃', hardware: '五金', addon: '配件' } as Record<string, string>)[m] ?? m
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const qs = `page=${page.value}&page_size=${page_size}&keyword=${keyword.value}${material.value ? `&material=${material.value}` : ''}`
|
|
const d = await api<any>('get', `/api/products?${qs}`)
|
|
rows.value = d.data
|
|
total.value = d.total
|
|
} finally { loading.value = false }
|
|
}
|
|
|
|
function openEdit(row?: any) {
|
|
Object.assign(form, row ?? { id: 0, name: '', material: 'profile', spec: '', unit: '米', price: 0, cost: 0, note: '' })
|
|
editVisible.value = true
|
|
}
|
|
|
|
async function save() {
|
|
if (form.id) await api('put', `/api/products/${form.id}`, form)
|
|
else await api('post', '/api/products', form)
|
|
ElMessage.success('已保存')
|
|
editVisible.value = false
|
|
load()
|
|
}
|
|
|
|
async function remove(row: any) {
|
|
await ElMessageBox.confirm(`确定删除「${row.name}」?`, '提示', { type: 'warning' })
|
|
await api('delete', `/api/products/${row.id}`)
|
|
ElMessage.success('已删除')
|
|
load()
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<style scoped>
|
|
.toolbar { display: flex; gap: 10px; margin-bottom: 12px; }
|
|
</style>
|