增加前端增删改查

This commit is contained in:
cjw
2026-03-15 13:50:23 +08:00
parent 191ac77d15
commit e13104e792
4 changed files with 777 additions and 101 deletions
+452 -90
View File
@@ -448,7 +448,7 @@ const HomeView = {
</div>
<div class="stat-card" @click="$router.push('/moldinsight')">
<div class="stat-icon">◈</div>
<div class="stat-icon">⚙️</div>
<div class="stat-content">
<div class="stat-value">{{ state.stats?.health?.total_tasks || 0 }}</div>
<div class="stat-label">分析任务</div>
@@ -500,7 +500,7 @@ const HomeView = {
<h2 class="section-title">快速操作</h2>
<div class="action-grid">
<button class="action-card" @click="$router.push('/moldinsight')">
<span class="action-icon">◈</span>
<span class="action-icon">⚙️</span>
<span class="action-label">模具分析</span>
</button>
<button class="action-card" @click="$router.push('/inventory')">
@@ -1479,7 +1479,11 @@ const InventoryView = {
warehouses: [],
inventory: [],
movements: [],
loading: false
loading: false,
showModal: false,
modalType: '',
editingItem: null,
form: {}
});
const loadDashboard = async () => {
@@ -1560,6 +1564,153 @@ const InventoryView = {
}
};
const openModal = (type, item = null) => {
state.modalType = type;
state.editingItem = item;
if (item) {
state.form = { ...item };
} else {
state.form = {};
}
state.showModal = true;
};
const closeModal = () => {
state.showModal = false;
state.modalType = '';
state.editingItem = null;
state.form = {};
};
const saveProduct = async () => {
try {
if (state.editingItem) {
await apiRequest(`/api/products/${state.editingItem.id}`, {
method: 'PUT',
body: JSON.stringify(state.form)
});
showNotification('产品更新成功', 'success');
} else {
await apiRequest('/api/products', {
method: 'POST',
body: JSON.stringify(state.form)
});
showNotification('产品创建成功', 'success');
}
closeModal();
loadProducts();
} catch (e) {
handleApiError(e, '保存产品');
}
};
const deleteProduct = async (id) => {
if (!confirm('确定要删除这个产品吗?')) return;
try {
await apiRequest(`/api/products/${id}`, { method: 'DELETE' });
showNotification('产品已删除', 'success');
loadProducts();
} catch (e) {
handleApiError(e, '删除产品');
}
};
const saveSupplier = async () => {
try {
if (state.editingItem) {
await apiRequest(`/api/suppliers/${state.editingItem.id}`, {
method: 'PUT',
body: JSON.stringify(state.form)
});
showNotification('供应商更新成功', 'success');
} else {
await apiRequest('/api/suppliers', {
method: 'POST',
body: JSON.stringify(state.form)
});
showNotification('供应商创建成功', 'success');
}
closeModal();
loadSuppliers();
} catch (e) {
handleApiError(e, '保存供应商');
}
};
const deleteSupplier = async (id) => {
if (!confirm('确定要删除这个供应商吗?')) return;
try {
await apiRequest(`/api/suppliers/${id}`, { method: 'DELETE' });
showNotification('供应商已删除', 'success');
loadSuppliers();
} catch (e) {
handleApiError(e, '删除供应商');
}
};
const saveCustomer = async () => {
try {
if (state.editingItem) {
await apiRequest(`/api/customers/${state.editingItem.id}`, {
method: 'PUT',
body: JSON.stringify(state.form)
});
showNotification('客户更新成功', 'success');
} else {
await apiRequest('/api/customers', {
method: 'POST',
body: JSON.stringify(state.form)
});
showNotification('客户创建成功', 'success');
}
closeModal();
loadCustomers();
} catch (e) {
handleApiError(e, '保存客户');
}
};
const deleteCustomer = async (id) => {
if (!confirm('确定要删除这个客户吗?')) return;
try {
await apiRequest(`/api/customers/${id}`, { method: 'DELETE' });
showNotification('客户已删除', 'success');
loadCustomers();
} catch (e) {
handleApiError(e, '删除客户');
}
};
const stockIn = async () => {
try {
await apiRequest('/api/stock-movements', {
method: 'POST',
body: JSON.stringify({ ...state.form, movement_type: 'in' })
});
showNotification('入库成功', 'success');
closeModal();
loadInventory();
loadMovements();
} catch (e) {
handleApiError(e, '入库操作');
}
};
const stockOut = async () => {
try {
await apiRequest('/api/stock-movements', {
method: 'POST',
body: JSON.stringify({ ...state.form, movement_type: 'out' })
});
showNotification('出库成功', 'success');
closeModal();
loadInventory();
loadMovements();
} catch (e) {
handleApiError(e, '出库操作');
}
};
onMounted(() => {
if (!appState.user) {
router.push('/login');
@@ -1573,7 +1724,17 @@ const InventoryView = {
switchTab,
formatNumber,
formatCurrency,
formatDateTime
formatDateTime,
openModal,
closeModal,
saveProduct,
deleteProduct,
saveSupplier,
deleteSupplier,
saveCustomer,
deleteCustomer,
stockIn,
stockOut
};
},
template: `
@@ -1643,98 +1804,140 @@ const InventoryView = {
</div>
</div>
<div v-else-if="state.activeTab === 'products'" class="table-container">
<table class="data-table">
<thead>
<tr>
<th>SKU</th>
<th>名称</th>
<th>分类</th>
<th>单位</th>
<th>成本价</th>
<th>销售价</th>
</tr>
</thead>
<tbody>
<tr v-for="product in state.products" :key="product.id">
<td>{{ product.sku }}</td>
<td>{{ product.name }}</td>
<td>{{ product.category || '-' }}</td>
<td>{{ product.unit }}</td>
<td>{{ formatCurrency(product.cost_price) }}</td>
<td>{{ formatCurrency(product.sale_price) }}</td>
</tr>
</tbody>
</table>
<div v-else-if="state.activeTab === 'products'">
<div class="table-header">
<button class="btn btn-primary" @click="openModal('product')">+ 新增产品</button>
</div>
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>SKU</th>
<th>名称</th>
<th>分类</th>
<th>单位</th>
<th>成本价</th>
<th>销售价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="product in state.products" :key="product.id">
<td>{{ product.sku }}</td>
<td>{{ product.name }}</td>
<td>{{ product.category || '-' }}</td>
<td>{{ product.unit }}</td>
<td>{{ formatCurrency(product.cost_price) }}</td>
<td>{{ formatCurrency(product.sale_price) }}</td>
<td>
<div class="action-btns">
<button class="btn btn-sm btn-secondary" @click="openModal('product', product)">编辑</button>
<button class="btn btn-sm btn-danger" @click="deleteProduct(product.id)">删除</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-else-if="state.activeTab === 'inventory'" class="table-container">
<table class="data-table">
<thead>
<tr>
<th>SKU</th>
<th>产品</th>
<th>仓库</th>
<th>数量</th>
<th>可用</th>
</tr>
</thead>
<tbody>
<tr v-for="item in state.inventory" :key="item.id">
<td>{{ item.product_sku }}</td>
<td>{{ item.product_name }}</td>
<td>{{ item.warehouse_name }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.available_quantity }}</td>
</tr>
</tbody>
</table>
<div v-else-if="state.activeTab === 'inventory'">
<div class="table-header">
<button class="btn btn-primary" @click="openModal('stockIn')">📥 入库</button>
<button class="btn btn-secondary" @click="openModal('stockOut')" style="margin-left: 8px;">📤 出库</button>
</div>
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>SKU</th>
<th>产品</th>
<th>仓库</th>
<th>数量</th>
<th>可用</th>
</tr>
</thead>
<tbody>
<tr v-for="item in state.inventory" :key="item.id">
<td>{{ item.product_sku }}</td>
<td>{{ item.product_name }}</td>
<td>{{ item.warehouse_name }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.available_quantity }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-else-if="state.activeTab === 'suppliers'" class="table-container">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>名称</th>
<th>联系人</th>
<th>电话</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr v-for="supplier in state.suppliers" :key="supplier.id">
<td>{{ supplier.code }}</td>
<td>{{ supplier.name }}</td>
<td>{{ supplier.contact_person || '-' }}</td>
<td>{{ supplier.phone || '-' }}</td>
<td>{{ supplier.email || '-' }}</td>
</tr>
</tbody>
</table>
<div v-else-if="state.activeTab === 'suppliers'">
<div class="table-header">
<button class="btn btn-primary" @click="openModal('supplier')">+ 新增供应商</button>
</div>
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>名称</th>
<th>联系人</th>
<th>电话</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="supplier in state.suppliers" :key="supplier.id">
<td>{{ supplier.code }}</td>
<td>{{ supplier.name }}</td>
<td>{{ supplier.contact_person || '-' }}</td>
<td>{{ supplier.phone || '-' }}</td>
<td>{{ supplier.email || '-' }}</td>
<td>
<div class="action-btns">
<button class="btn btn-sm btn-secondary" @click="openModal('supplier', supplier)">编辑</button>
<button class="btn btn-sm btn-danger" @click="deleteSupplier(supplier.id)">删除</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-else-if="state.activeTab === 'customers'" class="table-container">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>名称</th>
<th>联系人</th>
<th>电话</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr v-for="customer in state.customers" :key="customer.id">
<td>{{ customer.code }}</td>
<td>{{ customer.name }}</td>
<td>{{ customer.contact_person || '-' }}</td>
<td>{{ customer.phone || '-' }}</td>
<td>{{ customer.email || '-' }}</td>
</tr>
</tbody>
</table>
<div v-else-if="state.activeTab === 'customers'">
<div class="table-header">
<button class="btn btn-primary" @click="openModal('customer')">+ 新增客户</button>
</div>
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>名称</th>
<th>联系人</th>
<th>电话</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="customer in state.customers" :key="customer.id">
<td>{{ customer.code }}</td>
<td>{{ customer.name }}</td>
<td>{{ customer.contact_person || '-' }}</td>
<td>{{ customer.phone || '-' }}</td>
<td>{{ customer.email || '-' }}</td>
<td>
<div class="action-btns">
<button class="btn btn-sm btn-secondary" @click="openModal('customer', customer)">编辑</button>
<button class="btn btn-sm btn-danger" @click="deleteCustomer(customer.id)">删除</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-else-if="state.activeTab === 'movements'" class="table-container">
@@ -1766,6 +1969,165 @@ const InventoryView = {
</table>
</div>
</div>
<!-- 模态框 -->
<div v-if="state.showModal" class="modal-overlay" @click.self="closeModal">
<div class="modal-content">
<div class="modal-header">
<h3>{{ state.editingItem ? '编辑' : '新增' }}{{ state.modalType === 'product' ? '产品' : state.modalType === 'supplier' ? '供应商' : state.modalType === 'customer' ? '客户' : state.modalType === 'stockIn' ? '入库' : '出库' }}</h3>
<button class="modal-close" @click="closeModal">&times;</button>
</div>
<div class="modal-body">
<!-- 产品表单 -->
<form v-if="state.modalType === 'product'" @submit.prevent="saveProduct">
<div class="form-group">
<label class="form-label">SKU *</label>
<input v-model="state.form.sku" class="form-input" required placeholder="产品编码" />
</div>
<div class="form-group">
<label class="form-label">名称 *</label>
<input v-model="state.form.name" class="form-input" required placeholder="产品名称" />
</div>
<div class="form-group">
<label class="form-label">分类</label>
<input v-model="state.form.category" class="form-input" placeholder="产品分类" />
</div>
<div class="form-group">
<label class="form-label">单位</label>
<input v-model="state.form.unit" class="form-input" placeholder="件/个/箱" />
</div>
<div class="form-group">
<label class="form-label">成本价</label>
<input v-model.number="state.form.cost_price" type="number" step="0.01" class="form-input" placeholder="0.00" />
</div>
<div class="form-group">
<label class="form-label">销售价</label>
<input v-model.number="state.form.sale_price" type="number" step="0.01" class="form-input" placeholder="0.00" />
</div>
<div class="form-group">
<label class="form-label">最低库存</label>
<input v-model.number="state.form.min_stock" type="number" class="form-input" placeholder="0" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="closeModal">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
<!-- 供应商表单 -->
<form v-else-if="state.modalType === 'supplier'" @submit.prevent="saveSupplier">
<div class="form-group">
<label class="form-label">名称 *</label>
<input v-model="state.form.name" class="form-input" required placeholder="供应商名称" />
</div>
<div class="form-group">
<label class="form-label">联系人</label>
<input v-model="state.form.contact_person" class="form-input" placeholder="联系人姓名" />
</div>
<div class="form-group">
<label class="form-label">电话</label>
<input v-model="state.form.phone" class="form-input" placeholder="联系电话" />
</div>
<div class="form-group">
<label class="form-label">邮箱</label>
<input v-model="state.form.email" type="email" class="form-input" placeholder="email@example.com" />
</div>
<div class="form-group">
<label class="form-label">地址</label>
<input v-model="state.form.address" class="form-input" placeholder="详细地址" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="closeModal">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
<!-- 客户表单 -->
<form v-else-if="state.modalType === 'customer'" @submit.prevent="saveCustomer">
<div class="form-group">
<label class="form-label">名称 *</label>
<input v-model="state.form.name" class="form-input" required placeholder="客户名称" />
</div>
<div class="form-group">
<label class="form-label">联系人</label>
<input v-model="state.form.contact_person" class="form-input" placeholder="联系人姓名" />
</div>
<div class="form-group">
<label class="form-label">电话</label>
<input v-model="state.form.phone" class="form-input" placeholder="联系电话" />
</div>
<div class="form-group">
<label class="form-label">邮箱</label>
<input v-model="state.form.email" type="email" class="form-input" placeholder="email@example.com" />
</div>
<div class="form-group">
<label class="form-label">地址</label>
<input v-model="state.form.address" class="form-input" placeholder="详细地址" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="closeModal">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
<!-- 入库表单 -->
<form v-else-if="state.modalType === 'stockIn'" @submit.prevent="stockIn">
<div class="form-group">
<label class="form-label">产品ID *</label>
<input v-model.number="state.form.product_id" type="number" class="form-input" required placeholder="产品ID" />
</div>
<div class="form-group">
<label class="form-label">仓库ID *</label>
<input v-model.number="state.form.warehouse_id" type="number" class="form-input" required placeholder="仓库ID (默认1)" />
</div>
<div class="form-group">
<label class="form-label">数量 *</label>
<input v-model.number="state.form.quantity" type="number" class="form-input" required placeholder="入库数量" />
</div>
<div class="form-group">
<label class="form-label">单价</label>
<input v-model.number="state.form.unit_price" type="number" step="0.01" class="form-input" placeholder="采购单价" />
</div>
<div class="form-group">
<label class="form-label">备注</label>
<input v-model="state.form.remark" class="form-input" placeholder="备注信息" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="closeModal">取消</button>
<button type="submit" class="btn btn-primary">确认入库</button>
</div>
</form>
<!-- 出库表单 -->
<form v-else-if="state.modalType === 'stockOut'" @submit.prevent="stockOut">
<div class="form-group">
<label class="form-label">产品ID *</label>
<input v-model.number="state.form.product_id" type="number" class="form-input" required placeholder="产品ID" />
</div>
<div class="form-group">
<label class="form-label">仓库ID *</label>
<input v-model.number="state.form.warehouse_id" type="number" class="form-input" required placeholder="仓库ID (默认1)" />
</div>
<div class="form-group">
<label class="form-label">数量 *</label>
<input v-model.number="state.form.quantity" type="number" class="form-input" required placeholder="出库数量" />
</div>
<div class="form-group">
<label class="form-label">单价</label>
<input v-model.number="state.form.unit_price" type="number" step="0.01" class="form-input" placeholder="销售单价" />
</div>
<div class="form-group">
<label class="form-label">备注</label>
<input v-model="state.form.remark" class="form-input" placeholder="备注信息" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="closeModal">取消</button>
<button type="submit" class="btn btn-primary">确认出库</button>
</div>
</form>
</div>
</div>
</div>
</div>
`
};