代码提交-对接接口

This commit is contained in:
lixiaobang 2026-01-13 17:58:05 +08:00
parent 6a7d5db119
commit a19f48034d
17 changed files with 13596 additions and 1449 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

12477
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
src/api/base/category.js Normal file
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询商品类别列表
export function listproductCategory(query) {
return request({
url: '/api/v1/product-category',
method: 'get',
params: query
})
}
// 新增商品类别
export function addProductCategory(data) {
return request({
url: '/api/v1/product-category',
method: 'post',
data: data
})
}
// 修改商品类别
export function updateProductCategory(data) {
return request({
url: '/api/v1/product-category/' + data.id,
method: 'put',
data: data
})
}
// 删除商品类别
export function delProductCategory(data) {
return request({
url: '/api/v1/product-category',
method: 'delete',
data: data
})
}

38
src/api/base/customer.js Normal file
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询客户列表
export function listCustomer(query) {
return request({
url: '/api/v1/customer',
method: 'get',
params: query
})
}
// 新增客户
export function addCustomer(data) {
return request({
url: '/api/v1/customer',
method: 'post',
data: data
})
}
// 修改客户
export function updateCustomer(data) {
return request({
url: '/api/v1/customer/' + data.id,
method: 'put',
data: data
})
}
// 删除客户
export function delCustomer(data) {
return request({
url: '/api/v1/customer',
method: 'delete',
data: data
})
}

38
src/api/base/price.js Normal file
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询价格管理列表
export function listPriceIndex(query) {
return request({
url: '/api/v1/price-index',
method: 'get',
params: query
})
}
// 新增价格管理
export function addPriceIndex(data) {
return request({
url: '/api/v1/price-index',
method: 'post',
data: data
})
}
// 修改价格管理
export function updatePriceIndex(data) {
return request({
url: '/api/v1/price-index/' + data.id,
method: 'put',
data: data
})
}
// 删除价格管理
export function delPriceIndex(data) {
return request({
url: '/api/v1/price-index',
method: 'delete',
data: data
})
}

52
src/api/base/product.js Normal file
View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询商品列表
export function listproduct(query) {
return request({
url: '/api/v1/product',
method: 'get',
params: query
})
}
// 新增商品
export function addProduct(data) {
return request({
url: '/api/v1/product',
method: 'post',
data: data
})
}
// 修改商品
export function updateProduct(data) {
return request({
url: '/api/v1/product/' + data.id,
method: 'put',
data: data
})
}
// 删除商品
export function delProduct(data) {
return request({
url: '/api/v1/product',
method: 'delete',
data: data
})
}
//上传文件
export function uploadFile(data) {
return request({
url: '/api/v1/public/uploadFile',
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data',
// 关闭防重复提交,避免 FormData 被序列化
repeatSubmit: false
}
})
}

View File

@ -0,0 +1,74 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询仓库列表
export function listWarehouse(query) {
return request({
url: '/api/v1/warehouse',
method: 'get',
params: query
})
}
// 新增仓库
export function addWarehouse(data) {
return request({
url: '/api/v1/warehouse',
method: 'post',
data: data
})
}
// 修改仓库
export function updateWarehouse(data) {
return request({
url: '/api/v1/warehouse/' + data.id,
method: 'put',
data: data
})
}
// 删除仓库
export function delWarehouse(data) {
return request({
url: '/api/v1/warehouse',
method: 'delete',
data: data
})
}
// 查询仓库垛位列表
export function listWarehouseStock(query) {
return request({
url: '/api/v1/warehouse-stock',
method: 'get',
params: query
})
}
// 新增仓库垛位
export function addWarehouseStock(data) {
return request({
url: '/api/v1/warehouse-stock',
method: 'post',
data: data
})
}
// 修改仓库垛位
export function updateWarehouseStock(data) {
return request({
url: '/api/v1/warehouse-stock/' + data.id,
method: 'put',
data: data
})
}
// 删除仓库垛位
export function delWarehouseStock(data) {
return request({
url: '/api/v1/warehouse-stock',
method: 'delete',
data: data
})
}

38
src/api/base/supplier.js Normal file
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询供应商管理列表
export function listSupplier(query) {
return request({
url: '/api/v1/supplier',
method: 'get',
params: query
})
}
// 新增供应商
export function addSupplier(data) {
return request({
url: '/api/v1/supplier',
method: 'post',
data: data
})
}
// 修改供应商
export function updateSupplier(data) {
return request({
url: '/api/v1/supplier/' + data.id,
method: 'put',
data: data
})
}
// 删除供应商
export function delSupplier(data) {
return request({
url: '/api/v1/supplier',
method: 'delete',
data: data
})
}

View File

@ -0,0 +1,27 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询库存报警配置列表
export function listInventoryAlertConfig(query) {
return request({
url: '/api/v1/inventory-alert-config',
method: 'get',
params: query
})
}
// 修改库存报警配置
export function updateInventoryAlertConfig(data, id) {
return request({
url: '/api/v1/inventory-alert-config/' + id,
method: 'put',
data: data
})
}
// 删除库存报警配置
export function delInventoryAlertConfig(data) {
return request({
url: '/api/v1/inventory-alert-config/' + query.id,
method: 'delete',
data: data
})
}

View File

@ -78,6 +78,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { parseTime } from '@/utils/ruoyi' import { parseTime } from '@/utils/ruoyi'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import { listproductCategory, addProductCategory, updateProductCategory, delProductCategory } from '@/api/base/category'
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
@ -114,41 +115,16 @@ const dialogTitle = computed(() => isEdit.value ? '编辑类别' : '新增类别
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_categories') || '[]') const response = await listproductCategory(queryParams)
const start = (queryParams.pageNum - 1) * queryParams.pageSize categoryList.value = response.data.list || []
const end = start + queryParams.pageSize total.value = response.count || 0
categoryList.value = mockData.slice(start, end)
total.value = mockData.length
if (mockData.length === 0) {
generateMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取类别列表失败:' + error.message) ElMessage.error('获取类别列表失败:' + (error.message || '未知错误'))
} finally { } finally {
loading.value = false loading.value = false
} }
} }
const generateMockData = () => {
setTimeout(() => {
const categoryNames = ['动力煤', '焦煤', '无烟煤', '褐煤', '瘦煤', '肥煤', '气煤', '1/3焦煤', '贫煤', '长焰煤', '不粘煤', '弱粘煤', '1/2中粘煤', '中粘煤', '强粘煤', '特强粘煤', '贫瘦煤', '瘦焦煤', '主焦煤', '其他']
const newCategories = []
const now = Date.now()
for (let i = 1; i <= 20; i++) {
newCategories.push({
id: i,
categoryCode: 'CAT' + String(i).padStart(3, '0'),
categoryName: categoryNames[i - 1],
createTime: new Date(now - i * 30 * 86400000).toISOString(),
updateTime: new Date(now - i * 30 * 86400000).toISOString()
})
}
localStorage.setItem('mock_categories', JSON.stringify(newCategories))
getList()
}, 10)
}
const handleAdd = () => { const handleAdd = () => {
isEdit.value = false isEdit.value = false
resetForm() resetForm()
@ -177,62 +153,24 @@ const resetForm = () => {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!categoryFormRef.value) return if (!categoryFormRef.value) return
await categoryFormRef.value.validate((valid) => { await categoryFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
submitLoading.value = true submitLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_categories') || '[]')
const now = new Date().toISOString()
if (isEdit.value) { if (isEdit.value) {
// //
const index = mockData.findIndex(item => item.id === categoryForm.id) await updateProductCategory(categoryForm)
if (index !== -1) { ElMessage.success('编辑成功')
//
const codeExists = mockData.find(item =>
item.id !== categoryForm.id &&
item.categoryCode === categoryForm.categoryCode
)
if (codeExists) {
ElMessage.warning('类别编码已存在')
submitLoading.value = false
return
}
mockData[index] = {
...mockData[index],
categoryCode: categoryForm.categoryCode,
categoryName: categoryForm.categoryName,
updateTime: now
}
}
} else { } else {
// //
// await addProductCategory(categoryForm)
const codeExists = mockData.find(item => item.categoryCode === categoryForm.categoryCode) ElMessage.success('新增成功')
if (codeExists) {
ElMessage.warning('类别编码已存在')
submitLoading.value = false
return
}
const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1
mockData.push({
id: newId,
categoryCode: categoryForm.categoryCode,
categoryName: categoryForm.categoryName,
createTime: now,
updateTime: now
})
} }
localStorage.setItem('mock_categories', JSON.stringify(mockData))
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
dialogVisible.value = false dialogVisible.value = false
getList() getList()
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + (error.message || '未知错误'))
} finally { } finally {
submitLoading.value = false submitLoading.value = false
} }
@ -240,16 +178,19 @@ const handleSubmit = async () => {
} }
const handleDelete = (row) => { const handleDelete = (row) => {
const Ids = (row.id && [row.id])
ElMessageBox.confirm('确定要删除此类别吗?', '提示', { ElMessageBox.confirm('确定要删除此类别吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const categories = JSON.parse(localStorage.getItem('mock_categories') || '[]') try {
const filtered = categories.filter(c => c.id != row.id) await delProductCategory({ ids: Ids })
localStorage.setItem('mock_categories', JSON.stringify(filtered)) ElMessage.success('删除成功')
ElMessage.success('删除成功') getList()
getList() } catch (error) {
ElMessage.error('删除失败:' + (error.message || '未知错误'))
}
}).catch(() => {}) }).catch(() => {})
} }

View File

@ -14,8 +14,8 @@
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px"> <el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px">
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="正常" value="1" /> <el-option label="正常" value="正常" />
<el-option label="停用" value="0" /> <el-option label="停用" value="停用" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -27,41 +27,36 @@
</div> </div>
<el-table v-loading="loading" :data="customerList" border style="width: 100%; margin-top: 20px;"> <el-table v-loading="loading" :data="customerList" border style="width: 100%; margin-top: 20px;">
<el-table-column prop="customerCode" label="客户ID" width="120" /> <!-- <el-table-column prop="customerCode" label="客户ID" width="120" /> -->
<el-table-column prop="customerName" label="客户名称" width="200" /> <el-table-column prop="customerName" label="客户名称" width="200" />
<el-table-column prop="customerType" label="客户类型" width="120"> <el-table-column prop="customerType" label="客户类型" width="120">
<template #default="scope"> <template #default="scope">
{{ getCustomerTypeName(scope.row.customerType) }} {{ getCustomerTypeName(scope.row.customerType) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="contact" label="联系人" width="120" /> <el-table-column prop="contactPerson" label="联系人" width="120" />
<el-table-column prop="phone" label="手机号" width="130" /> <el-table-column prop="mobilePhone" label="手机号" width="130" />
<el-table-column prop="email" label="邮箱" width="180" /> <el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="address" label="详细地址" min-width="200" /> <el-table-column prop="detailAddress" label="详细地址" min-width="200" />
<el-table-column prop="bankName" label="开户银行" width="150" /> <el-table-column prop="bankName" label="开户银行" width="150" />
<el-table-column prop="bankAccount" label="银行账号" width="180" /> <el-table-column prop="bankAccount" label="银行账号" width="180" />
<el-table-column prop="taxNumber" label="税号" width="180" /> <el-table-column prop="taxNumber" label="税号" width="180" />
<el-table-column prop="status" label="客户状态" width="100" align="center"> <el-table-column prop="status" label="客户状态" width="100" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'"> <el-tag :type="scope.row.status == '正常' ? 'success' : 'danger'">
{{ scope.row.status == 1 ? '正常' : '停用' }} {{ scope.row.status == '正常' ? '正常' : '停用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="qualificationInfo" label="资质信息" width="150"> <!-- <el-table-column prop="qualificationInfo" label="资质信息" width="150">
<template #default="scope"> <template #default="scope">
<el-button <el-button v-if="scope.row.qualificationInfo && scope.row.qualificationInfo.length > 0" link type="primary"
v-if="scope.row.qualificationInfo && scope.row.qualificationInfo.length > 0" size="small" @click="handleViewQualification(scope.row)">
link
type="primary"
size="small"
@click="handleViewQualification(scope.row)"
>
查看资质({{ scope.row.qualificationInfo.length }}) 查看资质({{ scope.row.qualificationInfo.length }})
</el-button> </el-button>
<span v-else style="color: #999;">暂无资质</span> <span v-else style="color: #999;">暂无资质</span>
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column label="操作" width="250" fixed="right" align="center"> <el-table-column label="操作" width="250" fixed="right" align="center">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" size="small" @click="handleView(scope.row)">查看</el-button> <el-button link type="primary" size="small" @click="handleView(scope.row)">查看</el-button>
@ -71,46 +66,23 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageIndex"
v-show="total > 0" v-model:limit="queryParams.pageSize" @pagination="getList" />
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card> </el-card>
<!-- 新增/编辑客户对话框 --> <!-- 新增/编辑客户对话框 -->
<el-dialog <el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :close-on-click-modal="false"
v-model="dialogVisible" @close="resetForm">
:title="dialogTitle" <el-form ref="customerFormRef" :model="customerForm" :rules="customerFormRules" label-width="120px">
width="800px"
:close-on-click-modal="false"
@close="resetForm"
>
<el-form
ref="customerFormRef"
:model="customerForm"
:rules="customerFormRules"
label-width="120px"
>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="客户名称" prop="customerName"> <el-form-item label="客户名称" prop="customerName">
<el-input <el-input v-model="customerForm.customerName" placeholder="请输入客户名称" maxlength="50" />
v-model="customerForm.customerName"
placeholder="请输入客户名称"
maxlength="50"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="客户类型" prop="customerType"> <el-form-item label="客户类型" prop="customerType">
<el-select <el-select v-model="customerForm.customerType" placeholder="请选择客户类型" style="width: 100%">
v-model="customerForm.customerType"
placeholder="请选择客户类型"
style="width: 100%"
>
<el-option label="发电厂" value="power_plant" /> <el-option label="发电厂" value="power_plant" />
<el-option label="炼钢厂" value="steel_plant" /> <el-option label="炼钢厂" value="steel_plant" />
<el-option label="经销商" value="dealer" /> <el-option label="经销商" value="dealer" />
@ -123,93 +95,56 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="联系人" prop="contact"> <el-form-item label="联系人" prop="contactPerson">
<el-input <el-input v-model="customerForm.contactPerson" placeholder="请输入联系人" maxlength="20" />
v-model="customerForm.contact"
placeholder="请输入联系人"
maxlength="20"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="手机号" prop="phone"> <el-form-item label="手机号" prop="mobilePhone">
<el-input <el-input v-model="customerForm.mobilePhone" placeholder="请输入手机号" maxlength="11" />
v-model="customerForm.phone"
placeholder="请输入手机号"
maxlength="11"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="邮箱" prop="email"> <el-form-item label="邮箱" prop="email">
<el-input <el-input v-model="customerForm.email" placeholder="请输入邮箱" maxlength="50" />
v-model="customerForm.email"
placeholder="请输入邮箱"
maxlength="50"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="详细地址" prop="address"> <el-form-item label="详细地址" prop="detailAddress">
<el-input <el-input v-model="customerForm.detailAddress" type="textarea" :rows="2" placeholder="请输入详细地址" maxlength="200" />
v-model="customerForm.address"
type="textarea"
:rows="2"
placeholder="请输入详细地址"
maxlength="200"
/>
</el-form-item> </el-form-item>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="开户银行" prop="bankName"> <el-form-item label="开户银行" prop="bankName">
<el-input <el-input v-model="customerForm.bankName" placeholder="请输入开户银行" maxlength="50" />
v-model="customerForm.bankName"
placeholder="请输入开户银行"
maxlength="50"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="银行账号" prop="bankAccount"> <el-form-item label="银行账号" prop="bankAccount">
<el-input <el-input v-model="customerForm.bankAccount" placeholder="请输入银行账号" maxlength="30" />
v-model="customerForm.bankAccount"
placeholder="请输入银行账号"
maxlength="30"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="税号" prop="taxNumber"> <el-form-item label="税号" prop="taxNumber">
<el-input <el-input v-model="customerForm.taxNumber" placeholder="请输入税号" maxlength="30" />
v-model="customerForm.taxNumber"
placeholder="请输入税号"
maxlength="30"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="客户状态" prop="status"> <el-form-item label="客户状态" prop="status">
<el-radio-group v-model="customerForm.status"> <el-radio-group v-model="customerForm.status">
<el-radio :label="1">正常</el-radio> <el-radio :label="'正常'">正常</el-radio>
<el-radio :label="0">停用</el-radio> <el-radio :label="'停用'">停用</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="资质信息" prop="qualificationInfo"> <!-- <el-form-item label="资质信息" prop="qualificationInfo">
<el-upload <el-upload ref="uploadRef" :file-list="fileList" :auto-upload="false" :on-change="handleFileChange"
ref="uploadRef" :on-remove="handleFileRemove" :multiple="true" accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png">
:file-list="fileList"
:auto-upload="false"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
:multiple="true"
accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png"
>
<el-button type="primary">选择文件</el-button> <el-button type="primary">选择文件</el-button>
<template #tip> <template #tip>
<div class="el-upload__tip"> <div class="el-upload__tip">
@ -217,14 +152,15 @@
</div> </div>
</template> </template>
</el-upload> </el-upload>
<div v-if="customerForm.qualificationInfo && customerForm.qualificationInfo.length > 0" style="margin-top: 10px;"> <div v-if="customerForm.qualificationInfo && customerForm.qualificationInfo.length > 0"
style="margin-top: 10px;">
<div v-for="(file, index) in customerForm.qualificationInfo" :key="index" style="margin-bottom: 5px;"> <div v-for="(file, index) in customerForm.qualificationInfo" :key="index" style="margin-bottom: 5px;">
<el-button link type="primary" size="small" @click="handleViewQualificationFile(file)"> <el-button link type="primary" size="small" @click="handleViewQualificationFile(file)">
{{ file.name }} {{ file.name }}
</el-button> </el-button>
</div> </div>
</div> </div>
</el-form-item> </el-form-item> -->
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -237,28 +173,25 @@
</el-dialog> </el-dialog>
<!-- 查看客户对话框 --> <!-- 查看客户对话框 -->
<el-dialog <el-dialog v-model="viewDialogVisible" title="查看客户" width="800px">
v-model="viewDialogVisible"
title="查看客户"
width="800px"
>
<el-descriptions :column="2" border v-if="currentCustomer"> <el-descriptions :column="2" border v-if="currentCustomer">
<el-descriptions-item label="客户ID">{{ currentCustomer.customerCode }}</el-descriptions-item> <!-- <el-descriptions-item label="客户ID">{{ currentCustomer.customerCode }}</el-descriptions-item> -->
<el-descriptions-item label="客户名称">{{ currentCustomer.customerName }}</el-descriptions-item> <el-descriptions-item label="客户名称">{{ currentCustomer.customerName }}</el-descriptions-item>
<el-descriptions-item label="客户类型">{{ getCustomerTypeName(currentCustomer.customerType) }}</el-descriptions-item> <el-descriptions-item label="客户类型">{{ getCustomerTypeName(currentCustomer.customerType)
}}</el-descriptions-item>
<el-descriptions-item label="客户状态"> <el-descriptions-item label="客户状态">
<el-tag :type="currentCustomer.status == 1 ? 'success' : 'danger'"> <el-tag :type="currentCustomer.status == '正常' ? 'success' : 'danger'">
{{ currentCustomer.status == 1 ? '正常' : '停用' }} {{ currentCustomer.status == '正常' ? '正常' : '停用' }}
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="联系人">{{ currentCustomer.contact }}</el-descriptions-item> <el-descriptions-item label="联系人">{{ currentCustomer.contactPerson }}</el-descriptions-item>
<el-descriptions-item label="手机号">{{ currentCustomer.phone }}</el-descriptions-item> <el-descriptions-item label="手机号">{{ currentCustomer.mobilePhone }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ currentCustomer.email || '-' }}</el-descriptions-item> <el-descriptions-item label="邮箱">{{ currentCustomer.email || '-' }}</el-descriptions-item>
<el-descriptions-item label="详细地址" :span="2">{{ currentCustomer.address }}</el-descriptions-item> <el-descriptions-item label="详细地址" :span="2">{{ currentCustomer.detailAddress }}</el-descriptions-item>
<el-descriptions-item label="开户银行">{{ currentCustomer.bankName || '-' }}</el-descriptions-item> <el-descriptions-item label="开户银行">{{ currentCustomer.bankName || '-' }}</el-descriptions-item>
<el-descriptions-item label="银行账号">{{ currentCustomer.bankAccount || '-' }}</el-descriptions-item> <el-descriptions-item label="银行账号">{{ currentCustomer.bankAccount || '-' }}</el-descriptions-item>
<el-descriptions-item label="税号" :span="2">{{ currentCustomer.taxNumber || '-' }}</el-descriptions-item> <el-descriptions-item label="税号" :span="2">{{ currentCustomer.taxNumber || '-' }}</el-descriptions-item>
<el-descriptions-item label="资质信息" :span="2"> <!-- <el-descriptions-item label="资质信息" :span="2">
<div v-if="currentCustomer.qualificationInfo && currentCustomer.qualificationInfo.length > 0"> <div v-if="currentCustomer.qualificationInfo && currentCustomer.qualificationInfo.length > 0">
<div v-for="(file, index) in currentCustomer.qualificationInfo" :key="index" style="margin-bottom: 5px;"> <div v-for="(file, index) in currentCustomer.qualificationInfo" :key="index" style="margin-bottom: 5px;">
<el-button link type="primary" size="small" @click="handleViewQualificationFile(file)"> <el-button link type="primary" size="small" @click="handleViewQualificationFile(file)">
@ -267,28 +200,17 @@
</div> </div>
</div> </div>
<span v-else style="color: #999;">暂无资质</span> <span v-else style="color: #999;">暂无资质</span>
</el-descriptions-item> </el-descriptions-item> -->
</el-descriptions> </el-descriptions>
</el-dialog> </el-dialog>
<!-- 查看资质文件对话框 --> <!-- 查看资质文件对话框 -->
<el-dialog <el-dialog v-model="qualificationDialogVisible" title="查看资质文件" width="900px">
v-model="qualificationDialogVisible"
title="查看资质文件"
width="900px"
>
<div v-if="currentQualificationFile" style="text-align: center;"> <div v-if="currentQualificationFile" style="text-align: center;">
<iframe <iframe v-if="currentQualificationFile.type === 'pdf'" :src="currentQualificationFile.url"
v-if="currentQualificationFile.type === 'pdf'" style="width: 100%; height: 600px; border: none;"></iframe>
:src="currentQualificationFile.url" <img v-else-if="currentQualificationFile.type === 'image'" :src="currentQualificationFile.url"
style="width: 100%; height: 600px; border: none;" style="max-width: 100%; max-height: 600px;" alt="资质文件" />
></iframe>
<img
v-else-if="currentQualificationFile.type === 'image'"
:src="currentQualificationFile.url"
style="max-width: 100%; max-height: 600px;"
alt="资质文件"
/>
<div v-else> <div v-else>
<el-button type="primary" @click="handleDownloadQualificationFile(currentQualificationFile)"> <el-button type="primary" @click="handleDownloadQualificationFile(currentQualificationFile)">
下载文件 下载文件
@ -304,7 +226,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { formatMoney } from '@/utils/business' import { formatMoney } from '@/utils/business'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import { listCustomer, addCustomer, updateCustomer, delCustomer } from '@/api/base/customer'
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
const customerList = ref([]) const customerList = ref([])
@ -320,7 +242,7 @@ const currentCustomer = ref(null)
const currentQualificationFile = ref(null) const currentQualificationFile = ref(null)
const queryParams = reactive({ const queryParams = reactive({
pageNum: 1, pageIndex: 1,
pageSize: 10, pageSize: 10,
customerType: '', customerType: '',
status: '' status: ''
@ -331,15 +253,15 @@ const customerForm = reactive({
customerCode: '', customerCode: '',
customerName: '', customerName: '',
customerType: '', customerType: '',
contact: '', contactPerson: '',
phone: '', mobilePhone: '',
email: '', email: '',
address: '', detailAddress: '',
bankName: '', bankName: '',
bankAccount: '', bankAccount: '',
taxNumber: '', taxNumber: '',
qualificationInfo: [], qualificationInfo: [],
status: 1 status: '正常'
}) })
const customerFormRules = { const customerFormRules = {
@ -350,17 +272,17 @@ const customerFormRules = {
customerType: [ customerType: [
{ required: true, message: '请选择客户类型', trigger: 'change' } { required: true, message: '请选择客户类型', trigger: 'change' }
], ],
contact: [ contactPerson: [
{ required: true, message: '请输入联系人', trigger: 'blur' } { required: true, message: '请输入联系人', trigger: 'blur' }
], ],
phone: [ mobilePhone: [
{ required: true, message: '请输入手机号', trigger: 'blur' }, { required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' } { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
], ],
email: [ email: [
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' } { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
], ],
address: [ detailAddress: [
{ required: true, message: '请输入详细地址', trigger: 'blur' } { required: true, message: '请输入详细地址', trigger: 'blur' }
], ],
bankName: [ bankName: [
@ -394,20 +316,15 @@ const getCustomerTypeName = (type) => {
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_customers') || '[]') const res = await listCustomer({
let filtered = mockData.filter(item => { pageIndex: queryParams.pageIndex,
if (queryParams.customerType && item.customerType !== queryParams.customerType) return false pageSize: queryParams.pageSize,
if (queryParams.status !== '' && item.status != queryParams.status) return false customerType: queryParams.customerType,
return true status: queryParams.status
}) })
const start = (queryParams.pageNum - 1) * queryParams.pageSize //
const end = start + queryParams.pageSize customerList.value =res.data.list || []
customerList.value = filtered.slice(start, end) total.value = res.count || customerList.value.length
total.value = filtered.length
if (mockData.length === 0) {
generateMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取客户列表失败:' + error.message) ElMessage.error('获取客户列表失败:' + error.message)
} finally { } finally {
@ -446,10 +363,10 @@ const generateMockData = () => {
customerCode: 'C' + String(i).padStart(3, '0'), customerCode: 'C' + String(i).padStart(3, '0'),
customerName: (customerTypeNames[customerType] || '客户') + (i <= 6 ? String.fromCharCode(64 + i) : String(i)), customerName: (customerTypeNames[customerType] || '客户') + (i <= 6 ? String.fromCharCode(64 + i) : String(i)),
customerType: customerType, customerType: customerType,
contact: surnames[Math.floor(Math.random() * surnames.length)] + names[Math.floor(Math.random() * names.length)], contactPerson: surnames[Math.floor(Math.random() * surnames.length)] + names[Math.floor(Math.random() * names.length)],
phone: '139' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0'), mobilePhone: '139' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0'),
email: `customer${i}@example.com`, email: `customer${i}@example.com`,
address: city + district + 'xxx路xxx号', detailAddress: city + district + 'xxx路xxx号',
taxNumber: '91140000' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0') + String.fromCharCode(65 + Math.floor(Math.random() * 26)), taxNumber: '91140000' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0') + String.fromCharCode(65 + Math.floor(Math.random() * 26)),
bankName: banks[Math.floor(Math.random() * banks.length)], bankName: banks[Math.floor(Math.random() * banks.length)],
bankAccount: '622' + String(Math.floor(Math.random() * 10000000000000000)).padStart(16, '0'), bankAccount: '622' + String(Math.floor(Math.random() * 10000000000000000)).padStart(16, '0'),
@ -465,7 +382,7 @@ const generateMockData = () => {
} }
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNum = 1 queryParams.pageIndex = 1
getList() getList()
} }
@ -510,10 +427,10 @@ const handleEdit = (row) => {
customerCode: row.customerCode, customerCode: row.customerCode,
customerName: row.customerName, customerName: row.customerName,
customerType: row.customerType, customerType: row.customerType,
contact: row.contact, contactPerson: row.contactPerson,
phone: row.phone, mobilePhone: row.mobilePhone,
email: row.email || '', email: row.email || '',
address: row.address, detailAddress: row.detailAddress,
taxNumber: row.taxNumber || '', taxNumber: row.taxNumber || '',
bankName: row.bankName || '', bankName: row.bankName || '',
bankAccount: row.bankAccount || '', bankAccount: row.bankAccount || '',
@ -535,16 +452,20 @@ const handleEdit = (row) => {
} }
const handleDelete = (row) => { const handleDelete = (row) => {
const Ids = (row.id && [row.id])
ElMessageBox.confirm('确定要删除此客户吗?', '提示', { ElMessageBox.confirm('确定要删除此客户吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const customers = JSON.parse(localStorage.getItem('mock_customers') || '[]') try {
const filtered = customers.filter(c => c.id != row.id) // id id
localStorage.setItem('mock_customers', JSON.stringify(filtered)) await delCustomer({ ids: Ids })
ElMessage.success('删除成功') ElMessage.success('删除成功')
getList() getList()
} catch (error) {
ElMessage.error('删除失败:' + error.message)
}
}).catch(() => {}) }).catch(() => {})
} }
@ -554,15 +475,15 @@ const resetForm = () => {
customerCode: '', customerCode: '',
customerName: '', customerName: '',
customerType: '', customerType: '',
contact: '', contactPerson: '',
phone: '', mobilePhone: '',
email: '', email: '',
address: '', detailAddress: '',
taxNumber: '', taxNumber: '',
bankName: '', bankName: '',
bankAccount: '', bankAccount: '',
qualificationInfo: [], qualificationInfo: [],
status: 1 status: '正常'
}) })
fileList.value = [] fileList.value = []
customerFormRef.value?.clearValidate() customerFormRef.value?.clearValidate()
@ -635,81 +556,19 @@ const handleDownloadQualificationFile = (file) => {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!customerFormRef.value) return if (!customerFormRef.value) return
await customerFormRef.value.validate((valid) => { await customerFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
submitLoading.value = true submitLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_customers') || '[]') let res
const now = new Date().toISOString()
if (isEdit.value) { if (isEdit.value) {
// //
const index = mockData.findIndex(item => item.id === customerForm.id) res = await updateCustomer(customerForm)
if (index !== -1) {
// ID
const codeExists = mockData.find(item =>
item.id !== customerForm.id &&
item.customerCode === customerForm.customerCode
)
if (codeExists) {
ElMessage.warning('客户ID已存在')
submitLoading.value = false
return
}
mockData[index] = {
...mockData[index],
customerCode: customerForm.customerCode,
customerName: customerForm.customerName,
customerType: customerForm.customerType,
contact: customerForm.contact,
phone: customerForm.phone,
email: customerForm.email,
address: customerForm.address,
taxNumber: customerForm.taxNumber,
bankName: customerForm.bankName,
bankAccount: customerForm.bankAccount,
qualificationInfo: customerForm.qualificationInfo,
status: customerForm.status,
updateTime: now
}
}
} else { } else {
// //
// ID res = await addCustomer(customerForm)
if (!customerForm.customerCode || !customerForm.customerCode.match(/^C\d{3}$/)) {
customerForm.customerCode = generateCustomerCode()
}
// ID
const codeExists = mockData.find(item => item.customerCode === customerForm.customerCode)
if (codeExists) {
//
customerForm.customerCode = generateCustomerCode()
}
const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1
mockData.push({
id: newId,
customerCode: customerForm.customerCode,
customerName: customerForm.customerName,
customerType: customerForm.customerType,
contact: customerForm.contact,
phone: customerForm.phone,
email: customerForm.email,
address: customerForm.address,
creditCode: customerForm.creditCode,
bankName: customerForm.bankName,
bankAccount: customerForm.bankAccount,
qualificationInfo: customerForm.qualificationInfo,
status: customerForm.status,
createTime: now,
updateTime: now
})
} }
localStorage.setItem('mock_customers', JSON.stringify(mockData))
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功') ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
dialogVisible.value = false dialogVisible.value = false
getList() getList()

View File

@ -1,29 +1,59 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<div class="filter-toolbar">
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="价格类型" prop="indexType">
<el-select
v-model="queryParams.indexType"
placeholder="全部"
clearable
style="width: 180px"
>
<el-option label="全部" value="" />
<el-option label="CCI价" value="CCI价" />
<el-option label="神华外购石炭价" value="神华外购石炭价" />
<el-option label="神华外购价" value="神华外购价" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="handleAdd">新增价格配置</el-button>
</div>
<el-table v-loading="loading" :data="priceList" border style="width: 100%; margin-top: 20px;"> <el-table v-loading="loading" :data="priceList" border style="width: 100%; margin-top: 20px;">
<el-table-column prop="name" label="价格类型" /> <!-- <el-table-column prop="name" label="价格类型" /> -->
<el-table-column prop="type" label="类型" width="150"> <el-table-column prop="indexType" label="价格类型" width="150">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.type">{{ scope.row.type }}</span> <span v-if="scope.row.indexType">{{ scope.row.indexType }}</span>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="heatValue" label="热值" />
<el-table-column prop="price" label="价格" align="right"> <el-table-column prop="price" label="价格" align="right">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.price !== null && scope.row.price !== undefined">{{ formatMoney(scope.row.price) }}</span> <span v-if="scope.row.price !== null && scope.row.price !== undefined">{{ formatMoney(scope.row.price)
}}</span>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="berthDayCCI" label="靠泊日CCI" align="right"> <el-table-column prop="publishDate" label="发布日期">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.berthDayCCI !== null && scope.row.berthDayCCI !== undefined">{{ formatMoney(scope.row.berthDayCCI) }}</span> <span>{{ formatDate(scope.row.publishDate) }}</span>
</template>
</el-table-column> <!-- <el-table-column prop="berthDayCCI" label="CCI" align="right">
<template #default="scope">
<span v-if="scope.row.berthDayCCI !== null && scope.row.berthDayCCI !== undefined">{{
formatMoney(scope.row.berthDayCCI) }}</span>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="weeklyCCIAvg" label="靠泊日当周CCI平均价" align="right"> <el-table-column prop="weeklyCCIAvg" label="靠泊日当周CCI平均价" align="right">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.weeklyCCIAvg !== null && scope.row.weeklyCCIAvg !== undefined">{{ formatMoney(scope.row.weeklyCCIAvg) }}</span> <span v-if="scope.row.weeklyCCIAvg !== null && scope.row.weeklyCCIAvg !== undefined">{{
formatMoney(scope.row.weeklyCCIAvg) }}</span>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
</el-table-column> </el-table-column>
@ -35,153 +65,79 @@
</el-table-column> </el-table-column>
<el-table-column prop="downRange" label="下浮范围(%)" width="150" align="right"> <el-table-column prop="downRange" label="下浮范围(%)" width="150" align="right">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.downRange !== null && scope.row.downRange !== undefined">{{ scope.row.downRange }}%</span> <span v-if="scope.row.downRange !== null && scope.row.downRange !== undefined">{{ scope.row.downRange
}}%</span>
<span v-else style="color: #999;">-</span> <span v-else style="color: #999;">-</span>
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column label="操作" width="150" fixed="right" align="center"> <el-table-column label="操作" width="220" fixed="right" align="center">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button> <el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button link type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-card> </el-card>
<!-- 编辑价格对话框 --> <!-- 编辑价格对话框 -->
<el-dialog <el-dialog v-model="dialogVisible" :title="dialogTitle" width="700px" :close-on-click-modal="false"
v-model="dialogVisible" @close="resetForm">
:title="dialogTitle" <el-form ref="priceFormRef" :model="priceForm" :rules="dynamicRules" label-width="160px">
width="700px"
:close-on-click-modal="false"
@close="resetForm"
>
<el-form
ref="priceFormRef"
:model="priceForm"
:rules="dynamicRules"
label-width="160px"
>
<el-form-item label="价格类型"> <el-form-item label="价格类型">
<el-input v-model="priceForm.name" disabled /> <!-- <el-input v-model="priceForm.name" disabled /> -->
<el-select v-model="priceForm.indexType" placeholder="请选择价格类型" style="width: 100%">
<el-option label="CCI价" value="CCI价" />
<el-option label="神华外购石炭价" value="神华外购石炭价" />
<el-option label="神华外购价" value="神华外购价" />
</el-select>
</el-form-item> </el-form-item>
<!-- CCI 类型 --> <!-- CCI 类型 -->
<template v-if="priceForm.priceType === 'cci'"> <el-form-item label="热值" prop="heatValue">
<el-form-item label="靠泊日CCI" prop="berthDayCCI"> <el-input-number v-model="priceForm.heatValue" :min="0" :precision="2" placeholder="请输入热值"
<el-input-number style="width: 100%" />
v-model="priceForm.berthDayCCI" </el-form-item>
:min="0" <el-form-item label="发布日期" prop="publishDate">
:precision="2" <el-date-picker v-model="priceForm.publishDate" type="date" placeholder="请选择发布日期" style="width: 100%" />
placeholder="请输入靠泊日CCI" </el-form-item>
style="width: 100%" <el-form-item label="价格" prop="price">
/> <el-input-number v-model="priceForm.price" :min="0" :precision="2" placeholder="请输入价格" style="width: 100%" />
</el-form-item> </el-form-item>
<el-form-item label="靠泊日当周CCI平均价" prop="weeklyCCIAvg"> <el-form-item label="单位" prop="unit">
<el-input-number <el-input v-model="priceForm.unit" disabled style="width: 100%" />
v-model="priceForm.weeklyCCIAvg" </el-form-item>
:min="0"
:precision="2"
placeholder="请输入靠泊日当周CCI平均价"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="上浮范围(%)" prop="upRange">
<el-input-number
v-model="priceForm.upRange"
:min="0"
:max="100"
:precision="2"
placeholder="请输入上浮范围"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="下浮范围(%)" prop="downRange">
<el-input-number
v-model="priceForm.downRange"
:min="0"
:max="100"
:precision="2"
placeholder="请输入下浮范围"
style="width: 100%"
/>
</el-form-item>
</template>
<!-- 神华外购石炭价 --> <!-- 神华外购石炭价价 -->
<template v-else-if="priceForm.priceType === 'shenhua_stone'"> <!-- <template v-else-if="priceForm.indexType === '神华外购石炭价'">
<el-form-item label="类型">
<el-input v-model="priceForm.type" disabled />
</el-form-item>
<el-form-item label="价格" prop="price"> <el-form-item label="价格" prop="price">
<el-input-number <el-input-number v-model="priceForm.price" :min="0" :precision="2" placeholder="请输入价格"
v-model="priceForm.price" style="width: 100%" />
:min="0"
:precision="2"
placeholder="请输入价格"
style="width: 100%"
/>
</el-form-item> </el-form-item>
<el-form-item label="上浮范围(%)" prop="upRange"> <el-form-item label="上浮范围(%)" prop="upRange">
<el-input-number <el-input-number v-model="priceForm.upRange" :min="0" :max="100" :precision="2" placeholder="请输入上浮范围"
v-model="priceForm.upRange" style="width: 100%" />
:min="0"
:max="100"
:precision="2"
placeholder="请输入上浮范围"
style="width: 100%"
/>
</el-form-item> </el-form-item>
<el-form-item label="下浮范围(%)" prop="downRange"> <el-form-item label="下浮范围(%)" prop="downRange">
<el-input-number <el-input-number v-model="priceForm.downRange" :min="0" :max="100" :precision="2" placeholder="请输入下浮范围"
v-model="priceForm.downRange" style="width: 100%" />
:min="0"
:max="100"
:precision="2"
placeholder="请输入下浮范围"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</template> </template> -->
<!-- 神华外购价 --> <!-- 神华外购价价 -->
<template v-else-if="priceForm.priceType === 'shenhua_purchase'"> <!-- <template v-else-if="priceForm.indexType === '神华外购价'">
<el-form-item label="类型" prop="type">
<el-input
v-model="priceForm.type"
placeholder="请输入类型"
maxlength="50"
/>
</el-form-item>
<el-form-item label="价格" prop="price"> <el-form-item label="价格" prop="price">
<el-input-number <el-input-number v-model="priceForm.price" :min="0" :precision="2" placeholder="请输入价格"
v-model="priceForm.price" style="width: 100%" />
:min="0"
:precision="2"
placeholder="请输入价格"
style="width: 100%"
/>
</el-form-item> </el-form-item>
<el-form-item label="上浮范围(%)" prop="upRange"> <el-form-item label="上浮范围(%)" prop="upRange">
<el-input-number <el-input-number v-model="priceForm.upRange" :min="0" :max="100" :precision="2" placeholder="请输入上浮范围"
v-model="priceForm.upRange" style="width: 100%" />
:min="0"
:max="100"
:precision="2"
placeholder="请输入上浮范围"
style="width: 100%"
/>
</el-form-item> </el-form-item>
<el-form-item label="下浮范围(%)" prop="downRange"> <el-form-item label="下浮范围(%)" prop="downRange">
<el-input-number <el-input-number v-model="priceForm.downRange" :min="0" :max="100" :precision="2" placeholder="请输入下浮范围"
v-model="priceForm.downRange" style="width: 100%" />
:min="0"
:max="100"
:precision="2"
placeholder="请输入下浮范围"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</template> </template> -->
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -197,28 +153,45 @@
<script setup name="Price"> <script setup name="Price">
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { formatMoney } from '@/utils/business' import { formatMoney } from '@/utils/business'
import { listPriceIndex, addPriceIndex, updatePriceIndex, delPriceIndex } from '@/api/base/price'
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
const priceList = ref([]) const priceList = ref([])
const dialogVisible = ref(false) const dialogVisible = ref(false)
const priceFormRef = ref(null) const priceFormRef = ref(null)
const isEdit = ref(false)
//
const queryParams = reactive({
indexType: ''
})
const priceForm = reactive({ const priceForm = reactive({
id: null, id: null,
priceType: '', indexType: '',
name: '', name: '',
type: '', type: '',
heatValue: null,
publishDate: null,
price: null, price: null,
berthDayCCI: null, berthDayCCI: null,
weeklyCCIAvg: null, weeklyCCIAvg: null,
upRange: null, upRange: null,
downRange: null downRange: null,
unit: '吨'
}) })
const baseRules = { const baseRules = {
heatValue: [
{ required: true, message: '请输入热值', trigger: 'blur' },
{ type: 'number', min: 0, message: '热值必须大于等于0', trigger: 'blur' }
],
publishDate: [
{ required: true, message: '请选择发布日期', trigger: 'change' }
],
berthDayCCI: [ berthDayCCI: [
{ required: true, message: '请输入靠泊日CCI', trigger: 'blur' }, { required: true, message: '请输入靠泊日CCI', trigger: 'blur' },
{ type: 'number', min: 0, message: 'CCI必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: 'CCI必须大于等于0', trigger: 'blur' }
@ -247,19 +220,19 @@ const baseRules = {
const dynamicRules = computed(() => { const dynamicRules = computed(() => {
const rules = {} const rules = {}
if (priceForm.priceType === 'cci') { if (priceForm.indexType === 'CCI价') {
// CCICCICCI // CCI
rules.berthDayCCI = baseRules.berthDayCCI rules.type = baseRules.type
rules.weeklyCCIAvg = baseRules.weeklyCCIAvg rules.heatValue = baseRules.heatValue
rules.upRange = baseRules.upRange rules.publishDate = baseRules.publishDate
rules.downRange = baseRules.downRange rules.price = baseRules.price
} else if (priceForm.priceType === 'shenhua_stone') { } else if (priceForm.indexType === 'shenhua_stone') {
// //
rules.price = baseRules.price rules.price = baseRules.price
rules.upRange = baseRules.upRange rules.upRange = baseRules.upRange
rules.downRange = baseRules.downRange rules.downRange = baseRules.downRange
} else if (priceForm.priceType === 'shenhua_purchase') { } else if (priceForm.indexType === 'shenhua_purchase') {
// //
rules.type = baseRules.type rules.type = baseRules.type
rules.price = baseRules.price rules.price = baseRules.price
rules.upRange = baseRules.upRange rules.upRange = baseRules.upRange
@ -269,19 +242,16 @@ const dynamicRules = computed(() => {
return rules return rules
}) })
const dialogTitle = computed(() => '编辑价格配置') const dialogTitle = computed(() => (isEdit.value ? '编辑价格配置' : '新增价格配置'))
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_price_configs') || '[]') const res = await listPriceIndex({
indexType: queryParams.indexType || undefined
if (mockData.length === 0) { })
generateMockData() //
return priceList.value = (res && (res.data?.list || res.data || res.list)) || []
}
priceList.value = mockData
} catch (error) { } catch (error) {
ElMessage.error('获取价格配置失败:' + error.message) ElMessage.error('获取价格配置失败:' + error.message)
} finally { } finally {
@ -289,56 +259,35 @@ const getList = async () => {
} }
} }
const generateMockData = () => { //
setTimeout(() => { const handleQuery = () => {
const defaultConfigs = [ getList()
{ }
id: 1,
priceType: 'cci',
name: 'CCI煤炭价格指数网',
type: null,
price: null,
berthDayCCI: 550.00,
weeklyCCIAvg: 545.50,
upRange: 5.00,
downRange: 3.00
},
{
id: 2,
priceType: 'shenhua_stone',
name: '神华外购石炭价',
type: '石炭',
price: 570.00,
berthDayCCI: null,
weeklyCCIAvg: null,
upRange: 8.00,
downRange: 5.00
},
{
id: 3,
priceType: 'shenhua_purchase',
name: '神华外购价',
type: '标准煤',
price: 580.00,
berthDayCCI: null,
weeklyCCIAvg: null,
upRange: 10.00,
downRange: 6.00
}
]
localStorage.setItem('mock_price_configs', JSON.stringify(defaultConfigs)) //
priceList.value = defaultConfigs const resetQuery = () => {
loading.value = false queryParams.indexType = ''
}, 10) getList()
}
const handleAdd = () => {
isEdit.value = false
resetForm()
// CCI
priceForm.indexType = 'CCI价'
priceForm.name = 'CCI煤炭价格指数网'
dialogVisible.value = true
} }
const handleEdit = (row) => { const handleEdit = (row) => {
isEdit.value = true
Object.assign(priceForm, { Object.assign(priceForm, {
id: row.id, id: row.id,
priceType: row.priceType, indexType: row.indexType,
name: row.name, name: row.name,
type: row.priceType === 'shenhua_stone' ? '石炭' : (row.type || ''), type: row.indexType === 'shenhua_stone' ? '石炭' : (row.type || ''),
heatValue: row.heatValue,
publishDate: row.publishDate,
price: row.price, price: row.price,
berthDayCCI: row.berthDayCCI, berthDayCCI: row.berthDayCCI,
weeklyCCIAvg: row.weeklyCCIAvg, weeklyCCIAvg: row.weeklyCCIAvg,
@ -348,12 +297,33 @@ const handleEdit = (row) => {
dialogVisible.value = true dialogVisible.value = true
} }
const handleDelete = (row) => {
const ids = row.id ? [row.id] : []
if (!ids.length) return
ElMessageBox.confirm('确定要删除该价格配置吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
await delPriceIndex({ ids })
ElMessage.success('删除成功')
getList()
} catch (error) {
ElMessage.error('删除失败:' + error.message)
}
}).catch(() => { })
}
const resetForm = () => { const resetForm = () => {
Object.assign(priceForm, { Object.assign(priceForm, {
id: null, id: null,
priceType: '', indexType: '',
name: '', name: '',
type: '', type: '',
heatValue: null,
publishDate: null,
price: null, price: null,
berthDayCCI: null, berthDayCCI: null,
weeklyCCIAvg: null, weeklyCCIAvg: null,
@ -366,29 +336,17 @@ const resetForm = () => {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!priceFormRef.value) return if (!priceFormRef.value) return
await priceFormRef.value.validate((valid) => { await priceFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
submitLoading.value = true submitLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_price_configs') || '[]') if (isEdit.value) {
const index = mockData.findIndex(item => item.id === priceForm.id) await updatePriceIndex(priceForm)
} else {
if (index !== -1) { await addPriceIndex(priceForm)
mockData[index] = {
...mockData[index],
type: priceForm.priceType === 'shenhua_stone' ? '石炭' : (priceForm.type || null),
price: priceForm.price,
berthDayCCI: priceForm.berthDayCCI,
weeklyCCIAvg: priceForm.weeklyCCIAvg,
upRange: priceForm.upRange,
downRange: priceForm.downRange,
updateTime: new Date().toISOString()
}
} }
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
localStorage.setItem('mock_price_configs', JSON.stringify(mockData))
ElMessage.success('编辑成功')
dialogVisible.value = false dialogVisible.value = false
getList() getList()
} catch (error) { } catch (error) {
@ -398,6 +356,15 @@ const handleSubmit = async () => {
} }
}) })
} }
const formatDate = (value) => {
if (!value) return '-'
const d = new Date(value)
if (Number.isNaN(d.getTime())) return value
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
onMounted(() => getList()) onMounted(() => getList())
</script> </script>
@ -419,4 +386,3 @@ onMounted(() => getList())
padding-top: 20px; padding-top: 20px;
} }
</style> </style>

View File

@ -3,19 +3,18 @@
<el-card> <el-card>
<div class="filter-toolbar"> <div class="filter-toolbar">
<el-form :model="queryParams" ref="queryForm" :inline="true"> <el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="商品类别" prop="category"> <el-form-item label="商品类别" prop="categoryId">
<el-select v-model="queryParams.category" placeholder="全部" clearable style="width: 150px"> <el-select v-model="queryParams.categoryId" placeholder="全部" clearable style="width: 150px">
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="动力煤" value="动力煤" /> <el-option v-for="category in categoryOptions" :key="category.id" :label="category.categoryName"
<el-option label="焦煤" value="焦煤" /> :value="category.id" />
<el-option label="无烟煤" value="无烟煤" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px"> <el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px">
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="启用" value="1" /> <el-option label="启用" value="启用" />
<el-option label="禁用" value="0" /> <el-option label="禁用" value="禁用" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -27,46 +26,45 @@
</div> </div>
<el-table v-loading="loading" :data="productList" border style="width: 100%; margin-top: 20px;"> <el-table v-loading="loading" :data="productList" border style="width: 100%; margin-top: 20px;">
<el-table-column prop="productCode" label="商品编码" width="120" /> <el-table-column prop="productCode" label="商品编码" width="200" />
<el-table-column prop="productName" label="商品名称" width="200" /> <el-table-column prop="productName" label="商品名称" width="200" />
<el-table-column prop="specification" label="规格型号" width="150" /> <el-table-column prop="specification" label="规格型号" width="200" />
<el-table-column prop="categoryName" label="商品类别" width="120" /> <el-table-column prop="categoryName" label="商品类别" width="200">
<el-table-column prop="purchaseUnit" label="采购单位" width="120" /> <template #default="scope">
<el-table-column prop="salesUnit" label="销售单位" width="120" /> {{ scope.row.categoryName || scope.row.categoryId || scope.row.categoryId || '-' }}
<el-table-column prop="stockUnit" label="库存单位" width="120" /> </template>
<el-table-column prop="defaultCostPrice" label="默认成本价(元/吨)" width="160" align="right"> </el-table-column>
<el-table-column prop="unit" label="计量单位" width="200" />
<!-- <el-table-column prop="salesUnit" label="销售单位" width="120" />
<el-table-column prop="stockUnit" label="库存单位" width="120" /> -->
<!-- <el-table-column prop="defaultCostPrice" label="默认成本价(元/吨)" width="160" align="right">
<template #default="scope"> <template #default="scope">
{{ formatMoney(scope.row.defaultCostPrice) }} {{ formatMoney(scope.row.defaultCostPrice) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="defaultSalesPrice" label="默认销售价(元/吨)" width="160" align="right"> <el-table-column prop="defaultSalesPrice" label="默认销售价(元/吨)" width="160" align="right">
<template #default="scope"> <template #default="scope">
{{ formatMoney(scope.row.defaultSalesPrice) }} {{ formatMoney(scope.row.defaultSalesPrice) }}
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column prop="calorificValue" label="热值(kcal/kg)" width="150" align="right" /> <el-table-column prop="standardHeatValue" label="热值(kcal/kg)" width="200" />
<el-table-column prop="qualityReport" label="质检报告" width="150"> <!-- <el-table-column prop="qualityReport" label="质检报告" width="">
<template #default="scope"> <template #default="scope">
<el-button <el-button v-if="scope.row.qualityReport" link type="primary" size="small"
v-if="scope.row.qualityReport" @click="handleViewReport(scope.row)">
link
type="primary"
size="small"
@click="handleViewReport(scope.row)"
>
查看报告 查看报告
</el-button> </el-button>
<span v-else style="color: #999;">暂无报告</span> <span v-else style="color: #999;">暂无报告</span>
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column prop="status" label="状态" width="100"> <el-table-column prop="status" label="状态" width="200">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'"> <el-tag :type="scope.row.status == '启用' ? 'success' : 'danger'">
{{ scope.row.status == 1 ? '启用' : '禁用' }} {{ scope.row.status == '启用' ? '启用' : '禁用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="200" fixed="right" align="center"> <el-table-column label="操作" width="" fixed="right" align="center">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button> <el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button link type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button> <el-button link type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
@ -74,162 +72,91 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageIndex"
v-show="total > 0" v-model:limit="queryParams.pageSize" @pagination="getList" />
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card> </el-card>
<!-- 新增/编辑商品对话框 --> <!-- 新增/编辑商品对话框 -->
<el-dialog <el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :close-on-click-modal="false"
v-model="dialogVisible" @close="resetForm">
:title="dialogTitle" <el-form ref="productFormRef" :model="productForm" :rules="productFormRules" label-width="140px">
width="800px"
:close-on-click-modal="false"
@close="resetForm"
>
<el-form
ref="productFormRef"
:model="productForm"
:rules="productFormRules"
label-width="140px"
>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="商品编码" prop="productCode"> <el-form-item label="商品编码" prop="productCode">
<el-input <el-input v-model="productForm.productCode" placeholder="请输入商品编码" :disabled="isEdit" maxlength="30" />
v-model="productForm.productCode"
placeholder="请输入商品编码"
:disabled="isEdit"
maxlength="30"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="商品名称" prop="productName"> <el-form-item label="商品名称" prop="productName">
<el-input <el-input v-model="productForm.productName" placeholder="请输入商品名称" maxlength="50" />
v-model="productForm.productName"
placeholder="请输入商品名称"
maxlength="50"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="规格型号" prop="specification"> <el-form-item label="规格型号" prop="specification">
<el-input <el-input v-model="productForm.specification" placeholder="请输入规格型号" maxlength="50" />
v-model="productForm.specification"
placeholder="请输入规格型号"
maxlength="50"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="商品类别" prop="categoryName"> <el-form-item label="商品类别" prop="categoryId">
<el-select <el-select v-model="productForm.categoryId" placeholder="请选择商品类别" filterable style="width: 100%">
v-model="productForm.categoryName" <el-option v-for="category in categoryOptions" :key="category.id" :label="category.categoryName"
placeholder="请选择商品类别" :value="category.id" />
filterable
style="width: 100%"
>
<el-option
v-for="category in categoryOptions"
:key="category"
:label="category"
:value="category"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="采购单位" prop="purchaseUnit"> <el-form-item label="计量单位" prop="unit">
<el-input <el-input v-model="productForm.purchaseUnit" disabled placeholder="请输入计量单位" maxlength="10" />
v-model="productForm.purchaseUnit"
placeholder="请输入采购单位"
maxlength="10"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <!-- <el-col :span="12">
<el-form-item label="销售单位" prop="salesUnit"> <el-form-item label="销售单位" prop="salesUnit">
<el-input <el-input v-model="productForm.salesUnit" placeholder="请输入销售单位" maxlength="10" />
v-model="productForm.salesUnit"
placeholder="请输入销售单位"
maxlength="10"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="库存单位" prop="stockUnit"> <el-form-item label="库存单位" prop="stockUnit">
<el-input <el-input v-model="productForm.stockUnit" placeholder="请输入库存单位" maxlength="10" />
v-model="productForm.stockUnit"
placeholder="请输入库存单位"
maxlength="10"
/>
</el-form-item> </el-form-item>
</el-col> </el-col> -->
</el-row> </el-row>
<el-row :gutter="20"> <!-- <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="默认成本价(元/吨)" prop="defaultCostPrice"> <el-form-item label="默认成本价(元/吨)" prop="defaultCostPrice">
<el-input-number <el-input-number v-model="productForm.defaultCostPrice" :min="0" :precision="2" placeholder="请输入默认成本价"
v-model="productForm.defaultCostPrice" style="width: 100%" />
:min="0"
:precision="2"
placeholder="请输入默认成本价"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="默认销售价(元/吨)" prop="defaultSalesPrice"> <el-form-item label="默认销售价(元/吨)" prop="defaultSalesPrice">
<el-input-number <el-input-number v-model="productForm.defaultSalesPrice" :min="0" :precision="2" placeholder="请输入默认销售价"
v-model="productForm.defaultSalesPrice" style="width: 100%" />
:min="0"
:precision="2"
placeholder="请输入默认销售价"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row> -->
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="热值(kcal/kg)" prop="calorificValue"> <el-form-item label="热值(kcal/kg)" prop="standardHeatValue">
<el-input-number <el-input-number v-model="productForm.standardHeatValue" :min="0" :precision="0" placeholder="请输入热值"
v-model="productForm.calorificValue" style="width: 100%" />
:min="0"
:precision="0"
placeholder="请输入热值"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="productForm.status"> <el-radio-group v-model="productForm.status">
<el-radio :label="1">启用</el-radio> <el-radio :label="'启用'">启用</el-radio>
<el-radio :label="0">禁用</el-radio> <el-radio :label="'禁用'">禁用</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="质检报告" prop="qualityReport"> <!-- <el-form-item label="质检报告" prop="qualityReport">
<el-upload <el-upload ref="uploadRef" :file-list="fileList" :auto-upload="false" :on-change="handleFileChange"
ref="uploadRef" :on-remove="handleFileRemove" :limit="1" accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png">
:file-list="fileList"
:auto-upload="false"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
:limit="1"
accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png"
>
<el-button type="primary">选择文件</el-button> <el-button type="primary">选择文件</el-button>
<template #tip> <template #tip>
<div class="el-upload__tip"> <div class="el-upload__tip">
@ -242,7 +169,7 @@
查看当前报告 查看当前报告
</el-button> </el-button>
</div> </div>
</el-form-item> </el-form-item> -->
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -255,23 +182,12 @@
</el-dialog> </el-dialog>
<!-- 查看质检报告对话框 --> <!-- 查看质检报告对话框 -->
<el-dialog <el-dialog v-model="reportDialogVisible" title="质检报告" width="900px">
v-model="reportDialogVisible"
title="质检报告"
width="900px"
>
<div v-if="currentReport" style="text-align: center;"> <div v-if="currentReport" style="text-align: center;">
<iframe <iframe v-if="currentReport.type === 'pdf'" :src="currentReport.url"
v-if="currentReport.type === 'pdf'" style="width: 100%; height: 600px; border: none;"></iframe>
:src="currentReport.url" <img v-else-if="currentReport.type === 'image'" :src="currentReport.url"
style="width: 100%; height: 600px; border: none;" style="max-width: 100%; max-height: 600px;" alt="质检报告" />
></iframe>
<img
v-else-if="currentReport.type === 'image'"
:src="currentReport.url"
style="max-width: 100%; max-height: 600px;"
alt="质检报告"
/>
<div v-else> <div v-else>
<el-button type="primary" @click="handleDownloadReport(currentReport)"> <el-button type="primary" @click="handleDownloadReport(currentReport)">
下载报告 下载报告
@ -287,6 +203,8 @@ import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { formatMoney } from '@/utils/business' import { formatMoney } from '@/utils/business'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import { listproductCategory } from '@/api/base/category'
import { listproduct, addProduct, updateProduct, delProduct } from '@/api/base/product'
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
@ -301,28 +219,33 @@ const fileList = ref([])
const currentReport = ref(null) const currentReport = ref(null)
const queryParams = reactive({ const queryParams = reactive({
pageNum: 1, pageIndex: 1,
pageSize: 10, pageSize: 10,
category: '', category: '',
status: '' status: ''
}) })
const categoryOptions = ref(['动力煤', '焦煤', '无烟煤', '褐煤', '瘦煤', '肥煤', '气煤', '1/3焦煤', '贫煤', '长焰煤', '不粘煤', '弱粘煤', '1/2中粘煤', '中粘煤', '强粘煤', '特强粘煤', '贫瘦煤', '瘦焦煤', '主焦煤', '其他']) const categoryOptions = ref([])
const categoryMap = computed(() => {
const map = {}
categoryOptions.value.forEach((item) => {
map[item.id] = item.categoryName
})
return map
})
const productForm = reactive({ const productForm = reactive({
id: null, id: null,
productCode: '', productCode: '',
productName: '', productName: '',
specification: '', specification: '',
categoryName: '', categoryId: '',
purchaseUnit: '吨', unit: '吨',
salesUnit: '吨',
stockUnit: '吨',
defaultCostPrice: 0, defaultCostPrice: 0,
defaultSalesPrice: 0, defaultSalesPrice: 0,
calorificValue: 0, standardHeatValue: 0,
qualityReport: null, qualityReport: null,
status: 1 status: '启用'
}) })
const productFormRules = { const productFormRules = {
@ -334,13 +257,13 @@ const productFormRules = {
{ required: true, message: '请输入商品名称', trigger: 'blur' }, { required: true, message: '请输入商品名称', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' } { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
], ],
categoryName: [ categoryId: [
{ required: true, message: '请选择商品类别', trigger: 'change' } { required: true, message: '请选择商品类别', trigger: 'change' }
], ],
purchaseUnit: [ purchaseUnit: [
{ required: true, message: '请输入采购单位', trigger: 'blur' } { required: true, message: '请输入采购单位', trigger: 'blur' }
], ],
salesUnit: [ unit: [
{ required: true, message: '请输入销售单位', trigger: 'blur' } { required: true, message: '请输入销售单位', trigger: 'blur' }
], ],
stockUnit: [ stockUnit: [
@ -354,7 +277,7 @@ const productFormRules = {
{ required: true, message: '请输入默认销售价', trigger: 'blur' }, { required: true, message: '请输入默认销售价', trigger: 'blur' },
{ type: 'number', min: 0, message: '销售价必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '销售价必须大于等于0', trigger: 'blur' }
], ],
calorificValue: [ standardHeatValue: [
{ required: true, message: '请输入热值', trigger: 'blur' }, { required: true, message: '请输入热值', trigger: 'blur' },
{ type: 'number', min: 0, message: '热值必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '热值必须大于等于0', trigger: 'blur' }
], ],
@ -365,25 +288,37 @@ const productFormRules = {
const dialogTitle = computed(() => isEdit.value ? '编辑商品' : '新增商品') const dialogTitle = computed(() => isEdit.value ? '编辑商品' : '新增商品')
//
const appendCategoryName = (list = []) => {
return list.map((item) => ({
...item,
categoryName: categoryMap.value[item.categoryId] || categoryMap.value[item.categoryId] || item.categoryName || ''
}))
}
const getCategoryList = async () => {
try {
const response = await listproductCategory({ pageIndex: 1, pageSize: 1000 })
categoryOptions.value = response.data?.list || []
//
productList.value = appendCategoryName(productList.value)
// categoryOptions.value = categories.map(item => item.categoryName).filter(Boolean)
console.log(categoryOptions.value, ' categoryOptions.value ');
} catch (error) {
ElMessage.error('获取商品类别列表失败:' + (error.message || '未知错误'))
}
}
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_products') || '[]') const response = await listproduct(queryParams)
let filtered = mockData.filter(item => { const list = response.data?.list || response.rows || []
if (queryParams.category && item.categoryName !== queryParams.category) return false productList.value = appendCategoryName(list)
if (queryParams.status !== '' && item.status != queryParams.status) return false total.value = response.data?.count || response.total || 0
return true
})
const start = (queryParams.pageNum - 1) * queryParams.pageSize
const end = start + queryParams.pageSize
productList.value = filtered.slice(start, end)
total.value = filtered.length
if (mockData.length === 0) {
generateMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取商品列表失败:' + error.message) ElMessage.error('获取商品列表失败:' + (error.message || '未知错误'))
} finally { } finally {
loading.value = false loading.value = false
} }
@ -399,7 +334,7 @@ const generateMockData = () => {
for (let i = 1; i <= 20; i++) { for (let i = 1; i <= 20; i++) {
const costPrice = Math.floor(Math.random() * 300) + 400 const costPrice = Math.floor(Math.random() * 300) + 400
const salesPrice = costPrice + Math.floor(Math.random() * 100) + 50 const salesPrice = costPrice + Math.floor(Math.random() * 100) + 50
const calorificValue = Math.floor(Math.random() * 2000) + 4000 const standardHeatValue = Math.floor(Math.random() * 2000) + 4000
newProducts.push({ newProducts.push({
id: i, id: i,
productCode: 'PM' + String(i).padStart(3, '0'), productCode: 'PM' + String(i).padStart(3, '0'),
@ -411,7 +346,7 @@ const generateMockData = () => {
stockUnit: '吨', stockUnit: '吨',
defaultCostPrice: costPrice, defaultCostPrice: costPrice,
defaultSalesPrice: salesPrice, defaultSalesPrice: salesPrice,
calorificValue: calorificValue, standardHeatValue: standardHeatValue,
qualityReport: i <= 5 ? { name: `质检报告_${productNames[i - 1]}.pdf`, url: '#', type: 'pdf' } : null, qualityReport: i <= 5 ? { name: `质检报告_${productNames[i - 1]}.pdf`, url: '#', type: 'pdf' } : null,
status: Math.random() > 0.1 ? 1 : 0, status: Math.random() > 0.1 ? 1 : 0,
createTime: new Date(now - i * 30 * 86400000).toISOString(), createTime: new Date(now - i * 30 * 86400000).toISOString(),
@ -424,12 +359,12 @@ const generateMockData = () => {
} }
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNum = 1 queryParams.pageIndex = 1
getList() getList()
} }
const resetQuery = () => { const resetQuery = () => {
queryParams.category = '' queryParams.categoryId = ''
queryParams.status = '' queryParams.status = ''
handleQuery() handleQuery()
} }
@ -447,13 +382,13 @@ const handleEdit = (row) => {
productCode: row.productCode, productCode: row.productCode,
productName: row.productName, productName: row.productName,
specification: row.specification || '', specification: row.specification || '',
categoryName: row.categoryName, categoryId: row.categoryId,
purchaseUnit: row.purchaseUnit, purchaseUnit: row.purchaseUnit,
salesUnit: row.salesUnit, salesUnit: row.salesUnit,
stockUnit: row.stockUnit, stockUnit: row.stockUnit,
defaultCostPrice: row.defaultCostPrice, defaultCostPrice: row.defaultCostPrice,
defaultSalesPrice: row.defaultSalesPrice, defaultSalesPrice: row.defaultSalesPrice,
calorificValue: row.calorificValue || 0, standardHeatValue: row.standardHeatValue || 0,
qualityReport: row.qualityReport, qualityReport: row.qualityReport,
status: row.status status: row.status
}) })
@ -472,17 +407,20 @@ const handleEdit = (row) => {
} }
const handleDelete = (row) => { const handleDelete = (row) => {
const Ids = (row.id && [row.id])
ElMessageBox.confirm('确定要删除此商品吗?', '提示', { ElMessageBox.confirm('确定要删除此商品吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const products = JSON.parse(localStorage.getItem('mock_products') || '[]') try {
const filtered = products.filter(p => p.id != row.id) await delProduct({ ids: Ids })
localStorage.setItem('mock_products', JSON.stringify(filtered)) ElMessage.success('删除成功')
ElMessage.success('删除成功') getList()
getList() } catch (error) {
}).catch(() => {}) ElMessage.error('删除失败:' + (error.message || '未知错误'))
}
}).catch(() => { })
} }
const resetForm = () => { const resetForm = () => {
@ -497,9 +435,9 @@ const resetForm = () => {
stockUnit: '吨', stockUnit: '吨',
defaultCostPrice: 0, defaultCostPrice: 0,
defaultSalesPrice: 0, defaultSalesPrice: 0,
calorificValue: 0, standardHeatValue: 0,
qualityReport: null, qualityReport: null,
status: 1 status: '启用'
}) })
fileList.value = [] fileList.value = []
productFormRef.value?.clearValidate() productFormRef.value?.clearValidate()
@ -566,89 +504,34 @@ const handleDownloadReport = (report) => {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!productFormRef.value) return if (!productFormRef.value) return
await productFormRef.value.validate((valid) => { await productFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
submitLoading.value = true submitLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_products') || '[]')
const now = new Date().toISOString()
if (isEdit.value) { if (isEdit.value) {
// //
const index = mockData.findIndex(item => item.id === productForm.id) await updateProduct(productForm)
if (index !== -1) { ElMessage.success('编辑成功')
//
const codeExists = mockData.find(item =>
item.id !== productForm.id &&
item.productCode === productForm.productCode
)
if (codeExists) {
ElMessage.warning('商品编码已存在')
submitLoading.value = false
return
}
mockData[index] = {
...mockData[index],
productCode: productForm.productCode,
productName: productForm.productName,
specification: productForm.specification,
categoryName: productForm.categoryName,
purchaseUnit: productForm.purchaseUnit,
salesUnit: productForm.salesUnit,
stockUnit: productForm.stockUnit,
defaultCostPrice: productForm.defaultCostPrice,
defaultSalesPrice: productForm.defaultSalesPrice,
calorificValue: productForm.calorificValue,
qualityReport: productForm.qualityReport,
status: productForm.status,
updateTime: now
}
}
} else { } else {
// //
// await addProduct(productForm)
const codeExists = mockData.find(item => item.productCode === productForm.productCode) ElMessage.success('新增成功')
if (codeExists) {
ElMessage.warning('商品编码已存在')
submitLoading.value = false
return
}
const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1
mockData.push({
id: newId,
productCode: productForm.productCode,
productName: productForm.productName,
specification: productForm.specification,
categoryName: productForm.categoryName,
purchaseUnit: productForm.purchaseUnit,
salesUnit: productForm.salesUnit,
stockUnit: productForm.stockUnit,
defaultCostPrice: productForm.defaultCostPrice,
defaultSalesPrice: productForm.defaultSalesPrice,
calorificValue: productForm.calorificValue,
qualityReport: productForm.qualityReport,
status: productForm.status,
createTime: now,
updateTime: now
})
} }
localStorage.setItem('mock_products', JSON.stringify(mockData))
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
dialogVisible.value = false dialogVisible.value = false
getList() getList()
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + (error.message || '未知错误'))
} finally { } finally {
submitLoading.value = false submitLoading.value = false
} }
}) })
} }
onMounted(() => getList()) onMounted(() => {
getCategoryList()
getList()
})
</script> </script>
<style scoped> <style scoped>

View File

@ -7,13 +7,14 @@
<div class="filter-toolbar"> <div class="filter-toolbar">
<el-form :model="warehouseQueryParams" ref="warehouseQueryForm" :inline="true"> <el-form :model="warehouseQueryParams" ref="warehouseQueryForm" :inline="true">
<el-form-item label="仓库名称" prop="warehouseName"> <el-form-item label="仓库名称" prop="warehouseName">
<el-input v-model="warehouseQueryParams.warehouseName" placeholder="请输入仓库名称" clearable style="width: 200px" /> <el-input v-model="warehouseQueryParams.warehouseName" placeholder="请输入仓库名称" clearable
style="width: 200px" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="warehouseQueryParams.status" placeholder="全部" clearable style="width: 150px"> <el-select v-model="warehouseQueryParams.status" placeholder="全部" clearable style="width: 150px">
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="启用" value="1" /> <el-option label="启用" value="启用" />
<el-option label="禁用" value="0" /> <el-option label="禁用" value="禁用" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -27,19 +28,19 @@
<el-table v-loading="warehouseLoading" :data="warehouseList" border style="width: 100%"> <el-table v-loading="warehouseLoading" :data="warehouseList" border style="width: 100%">
<el-table-column prop="warehouseCode" label="仓库编码" width="150" /> <el-table-column prop="warehouseCode" label="仓库编码" width="150" />
<el-table-column prop="warehouseName" label="仓库名称" /> <el-table-column prop="warehouseName" label="仓库名称" />
<el-table-column prop="address" label="地址" /> <el-table-column prop="detailAddress" label="地址" />
<el-table-column prop="manager" label="负责人" width="160" /> <el-table-column prop="contactPerson" label="联系人" width="160" />
<el-table-column prop="phone" label="联系电话" width="180"> <el-table-column prop="contactPhone" label="联系电话" width="180">
<template #default="scope"> <template #default="scope">
{{ scope.row.phone || '-' }} {{ scope.row.contactPhone || '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="capacity" label="容量(吨)" width="120" align="right" /> <!-- <el-table-column prop="stockCapacity" label="容量(吨)" width="120" align="right" />
<el-table-column prop="currentStock" label="当前库存(吨)" width="150" align="right" /> <el-table-column prop="stockInventory" label="当前库存(吨)" width="150" align="right" /> -->
<el-table-column prop="status" label="状态" width="100"> <el-table-column prop="status" label="状态" width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'"> <el-tag :type="scope.row.status == '启用' ? 'success' : 'danger'">
{{ scope.row.status == 1 ? '启用' : '禁用' }} {{ scope.row.status == '启用' ? '启用' : '禁用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
@ -51,21 +52,16 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="warehouseTotal > 0" :total="warehouseTotal" v-model:page="warehouseQueryParams.pageIndex"
v-show="warehouseTotal > 0" v-model:limit="warehouseQueryParams.pageSize" @pagination="getWarehouseList" />
:total="warehouseTotal"
v-model:page="warehouseQueryParams.pageNum"
v-model:limit="warehouseQueryParams.pageSize"
@pagination="getWarehouseList"
/>
</el-tab-pane> </el-tab-pane>
<!-- 垛位管理 --> <!-- 垛位管理 -->
<el-tab-pane label="垛位管理" name="stack"> <el-tab-pane label="垛位管理" name="stack">
<div class="filter-toolbar"> <div class="filter-toolbar">
<el-form :model="stackQueryParams" ref="stackQueryForm" :inline="true"> <el-form :model="stackQueryParams" ref="stackQueryForm" :inline="true">
<el-form-item label="垛位名称" prop="stackName"> <el-form-item label="垛位名称" prop="stockName">
<el-input v-model="stackQueryParams.stackName" placeholder="请输入垛位名称" clearable style="width: 200px" /> <el-input v-model="stackQueryParams.stockName" placeholder="请输入垛位名称" clearable style="width: 200px" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleStackQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleStackQuery">搜索</el-button>
@ -76,17 +72,21 @@
</div> </div>
<el-table v-loading="stackLoading" :data="stackList" border style="width: 100%"> <el-table v-loading="stackLoading" :data="stackList" border style="width: 100%">
<el-table-column prop="stackCode" label="垛位编码" width="150" /> <el-table-column prop="stockCode" label="垛位编码" width="200" />
<el-table-column prop="stackName" label="垛位名称" width="150" /> <el-table-column prop="stockName" label="垛位名称"/>
<el-table-column prop="warehouseName" label="所属仓库" width="150" /> <el-table-column prop="warehouseId" label="所属仓库" width="200">
<el-table-column prop="capacity" label="容量(吨)" width="120" align="right" />
<el-table-column prop="currentStock" label="当前库存(吨)" width="150" align="right" />
<el-table-column prop="createTime" label="创建时间" width="180">
<template #default="scope"> <template #default="scope">
{{ parseTime(scope.row.createTime) }} {{ scope.row.warehouse.warehouseName }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="200" fixed="right"> <el-table-column prop="stockCapacity" label="容量(吨)" width="150" align="right" />
<el-table-column prop="stockInventory" label="当前库存(吨)" width="200" align="right" />
<el-table-column prop="createdAt" label="创建时间" >
<template #default="scope">
{{ parseTime(scope.row.createdAt) }}
</template>
</el-table-column>
<el-table-column label="操作" width="" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" size="small" @click="handleStackEdit(scope.row)">编辑</el-button> <el-button link type="primary" size="small" @click="handleStackEdit(scope.row)">编辑</el-button>
<el-button link type="danger" size="small" @click="handleStackDelete(scope.row)">删除</el-button> <el-button link type="danger" size="small" @click="handleStackDelete(scope.row)">删除</el-button>
@ -94,87 +94,53 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="stackTotal > 0" :total="stackTotal" v-model:page="stackQueryParams.pageIndex"
v-show="stackTotal > 0" v-model:limit="stackQueryParams.pageSize" @pagination="getStackList" />
:total="stackTotal"
v-model:page="stackQueryParams.pageNum"
v-model:limit="stackQueryParams.pageSize"
@pagination="getStackList"
/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-card> </el-card>
<!-- 新增/编辑仓库对话框 --> <!-- 新增/编辑仓库对话框 -->
<el-dialog <el-dialog v-model="warehouseDialogVisible" :title="warehouseDialogTitle" width="600px"
v-model="warehouseDialogVisible" :close-on-click-modal="false">
:title="warehouseDialogTitle" <el-form ref="warehouseFormRef" :model="warehouseForm" :rules="warehouseFormRules" label-width="100px">
width="600px"
:close-on-click-modal="false"
>
<el-form
ref="warehouseFormRef"
:model="warehouseForm"
:rules="warehouseFormRules"
label-width="100px"
>
<el-form-item label="仓库编码" prop="warehouseCode"> <el-form-item label="仓库编码" prop="warehouseCode">
<el-input <el-input v-model="warehouseForm.warehouseCode" placeholder="系统自动生成" disabled />
v-model="warehouseForm.warehouseCode"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
<el-form-item label="仓库名称" prop="warehouseName"> <el-form-item label="仓库名称" prop="warehouseName">
<el-input <el-input v-model="warehouseForm.warehouseName" placeholder="请输入仓库名称" maxlength="50" />
v-model="warehouseForm.warehouseName"
placeholder="请输入仓库名称"
maxlength="50"
/>
</el-form-item> </el-form-item>
<el-form-item label="地址" prop="address"> <el-form-item label="地址" prop="detailAddress">
<el-input <el-input v-model="warehouseForm.detailAddress" placeholder="请输入地址" maxlength="200" />
v-model="warehouseForm.address"
placeholder="请输入地址"
maxlength="200"
/>
</el-form-item> </el-form-item>
<el-form-item label="负责人" prop="manager"> <el-form-item label="联系人" prop="contactPerson">
<el-input <el-input v-model="warehouseForm.contactPerson" placeholder="请输入联系人" maxlength="20" />
v-model="warehouseForm.manager"
placeholder="请输入负责人"
maxlength="20"
/>
</el-form-item> </el-form-item>
<el-form-item label="联系电话" prop="phone"> <el-form-item label="联系电话" prop="contactPhone">
<el-input <el-input v-model="warehouseForm.contactPhone" placeholder="请输入联系电话" maxlength="20" />
v-model="warehouseForm.phone"
placeholder="请输入联系电话"
maxlength="20"
/>
</el-form-item> </el-form-item>
<el-form-item label="容量(吨)" prop="capacity"> <!-- <el-form-item label="容量(吨)" prop="stockCapacity">
<el-input-number <el-input-number
v-model="warehouseForm.capacity" v-model="warehouseForm.stockCapacity"
:min="0" :min="0"
:precision="0" :precision="0"
placeholder="请输入容量" placeholder="请输入容量"
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item> -->
<el-form-item label="当前库存(吨)" prop="currentStock"> <!-- <el-form-item label="当前库存(吨)" prop="stockInventory">
<el-input-number <el-input-number
v-model="warehouseForm.currentStock" v-model="warehouseForm.stockInventory"
:min="0" :min="0"
:precision="0" :precision="0"
placeholder="请输入当前库存" placeholder="请输入当前库存"
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item> -->
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="warehouseForm.status"> <el-radio-group v-model="warehouseForm.status">
<el-radio :label="1">启用</el-radio> <el-radio :label="'启用'">启用</el-radio>
<el-radio :label="0">禁用</el-radio> <el-radio :label="'禁用'">禁用</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -189,64 +155,27 @@
</el-dialog> </el-dialog>
<!-- 新增/编辑垛位对话框 --> <!-- 新增/编辑垛位对话框 -->
<el-dialog <el-dialog v-model="stackDialogVisible" :title="stackDialogTitle" width="600px" :close-on-click-modal="false">
v-model="stackDialogVisible" <el-form ref="stackFormRef" :model="stackForm" :rules="stackFormRules" label-width="100px">
:title="stackDialogTitle" <el-form-item label="垛位编码" prop="stockCode">
width="600px" <el-input v-model="stackForm.stockCode" placeholder="系统自动生成" disabled />
:close-on-click-modal="false"
>
<el-form
ref="stackFormRef"
:model="stackForm"
:rules="stackFormRules"
label-width="100px"
>
<el-form-item label="垛位编码" prop="stackCode">
<el-input
v-model="stackForm.stackCode"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
<el-form-item label="垛位名称" prop="stackName"> <el-form-item label="垛位名称" prop="stockName">
<el-input <el-input v-model="stackForm.stockName" placeholder="请输入垛位名称" maxlength="50" />
v-model="stackForm.stackName"
placeholder="请输入垛位名称"
maxlength="50"
/>
</el-form-item> </el-form-item>
<el-form-item label="所属仓库" prop="warehouseName"> <el-form-item label="所属仓库" prop="warehouseId">
<el-select <el-select v-model="stackForm.warehouseId" placeholder="请选择所属仓库" style="width: 100%" filterable>
v-model="stackForm.warehouseName" <el-option v-for="warehouse in warehouseOptions" :key="warehouse.id" :label="warehouse.warehouseName"
placeholder="请选择所属仓库" :value="warehouse.id" />
style="width: 100%"
filterable
>
<el-option
v-for="warehouse in warehouseOptions"
:key="warehouse.warehouseName"
:label="warehouse.warehouseName"
:value="warehouse.warehouseName"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="容量(吨)" prop="capacity"> <el-form-item label="容量(吨)" prop="stockCapacity">
<el-input-number <el-input-number v-model="stackForm.stockCapacity" :min="0" :precision="0" placeholder="请输入容量"
v-model="stackForm.capacity" style="width: 100%" />
:min="0"
:precision="0"
placeholder="请输入容量"
style="width: 100%"
/>
</el-form-item> </el-form-item>
<el-form-item label="当前库存(吨)" prop="currentStock"> <el-form-item label="当前库存(吨)" prop="stockInventory">
<el-input-number <el-input-number v-model="stackForm.stockInventory" :min="0" :precision="0" placeholder="请输入当前库存"
v-model="stackForm.currentStock" style="width: 100%" />
:min="0"
:precision="0"
placeholder="请输入当前库存"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@ -266,6 +195,16 @@ import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { parseTime } from '@/utils/ruoyi' import { parseTime } from '@/utils/ruoyi'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import {
listWarehouse,
addWarehouse,
updateWarehouse,
delWarehouse,
listWarehouseStock,
addWarehouseStock,
updateWarehouseStock,
delWarehouseStock
} from '@/api/base/serviceProvider'
// Tab // Tab
const activeTab = ref('warehouse') const activeTab = ref('warehouse')
@ -279,46 +218,55 @@ const warehouseSubmitLoading = ref(false)
const warehouseIsEdit = ref(false) const warehouseIsEdit = ref(false)
const warehouseFormRef = ref(null) const warehouseFormRef = ref(null)
// 使 pageIndex
const warehouseQueryParams = reactive({ const warehouseQueryParams = reactive({
pageNum: 1, pageIndex: 1,
pageSize: 10, pageSize: 10,
warehouseName: '', warehouseName: '',
status: '' status: ''
}) })
const warehouseForm = reactive({ const warehouseForm = reactive({
id: null,
warehouseCode: '', warehouseCode: '',
warehouseName: '', warehouseName: '',
address: '', detailAddress: '',
manager: '', contactPerson: '',
phone: '', contactPhone: '',
capacity: null, stockCapacity: null,
currentStock: null, stockInventory: null,
status: 1 status: '启用'
}) })
// CK + 6 + 3
const generateWarehouseCode = () => {
const prefix = 'CK'
const timePart = Date.now().toString().slice(-6)
const randomPart = Math.floor(Math.random() * 900 + 100) // 100-999
return `${prefix}${timePart}${randomPart}`
}
const warehouseFormRules = { const warehouseFormRules = {
warehouseName: [ warehouseName: [
{ required: true, message: '请输入仓库名称', trigger: 'blur' }, { required: true, message: '请输入仓库名称', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' } { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
], ],
address: [ detailAddress: [
{ required: true, message: '请输入地址', trigger: 'blur' }, { required: true, message: '请输入地址', trigger: 'blur' },
{ max: 200, message: '地址不能超过 200 个字符', trigger: 'blur' } { max: 200, message: '地址不能超过 200 个字符', trigger: 'blur' }
], ],
manager: [ contactPerson: [
{ required: true, message: '请输入负责人', trigger: 'blur' }, { required: true, message: '请输入联系人', trigger: 'blur' },
{ max: 20, message: '负责人姓名不能超过 20 个字符', trigger: 'blur' } { max: 20, message: '联系人姓名不能超过 20 个字符', trigger: 'blur' }
], ],
phone: [ contactPhone: [
{ pattern: /^1[3-9]\d{9}$|^$/, message: '请输入正确的手机号码', trigger: 'blur' } { required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
], ],
capacity: [ stockCapacity: [
{ required: true, message: '请输入容量', trigger: 'blur' }, { required: true, message: '请输入容量', trigger: 'blur' },
{ type: 'number', min: 0, message: '容量必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '容量必须大于等于0', trigger: 'blur' }
], ],
currentStock: [ stockInventory: [
{ required: true, message: '请输入当前库存', trigger: 'blur' }, { required: true, message: '请输入当前库存', trigger: 'blur' },
{ type: 'number', min: 0, message: '当前库存必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '当前库存必须大于等于0', trigger: 'blur' }
], ],
@ -332,57 +280,19 @@ const warehouseDialogTitle = computed(() => warehouseIsEdit.value ? '编辑仓
const getWarehouseList = async () => { const getWarehouseList = async () => {
warehouseLoading.value = true warehouseLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_warehouses') || '[]') const response = await listWarehouse(warehouseQueryParams)
let filtered = mockData.filter(item => { const list = response.data?.list || response.rows || []
if (warehouseQueryParams.warehouseName && !item.warehouseName.includes(warehouseQueryParams.warehouseName)) return false warehouseList.value = list
if (warehouseQueryParams.status !== '' && item.status != warehouseQueryParams.status) return false warehouseTotal.value = response.data?.count || response.total || 0
return true
})
const start = (warehouseQueryParams.pageNum - 1) * warehouseQueryParams.pageSize
const end = start + warehouseQueryParams.pageSize
warehouseList.value = filtered.slice(start, end)
warehouseTotal.value = filtered.length
if (mockData.length === 0) {
generateWarehouseMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取仓库列表失败:' + error.message) ElMessage.error('获取仓库列表失败:' + (error.message || '未知错误'))
} finally { } finally {
warehouseLoading.value = false warehouseLoading.value = false
} }
} }
const generateWarehouseMockData = () => {
setTimeout(() => {
const cities = ['太原市', '大同市', '阳泉市', '长治市', '晋城市', '朔州市', '晋中市', '运城市', '忻州市', '临汾市']
const districts = ['xxx区', 'xxx县', 'xxx市']
const surnames = ['张', '李', '王', '赵', '刘', '陈', '杨', '黄', '周', '吴']
const names = ['三', '四', '五', '六', '七', '明', '强', '伟', '芳', '娜']
const newWarehouses = []
const now = Date.now()
for (let i = 1; i <= 20; i++) {
const capacity = Math.floor(Math.random() * 200000) + 50000
newWarehouses.push({
id: i,
warehouseCode: 'WH' + String(i).padStart(3, '0'),
warehouseName: '仓库' + i,
address: cities[Math.floor(Math.random() * cities.length)] + districts[Math.floor(Math.random() * districts.length)] + 'xxx路xxx号',
manager: surnames[Math.floor(Math.random() * surnames.length)] + names[Math.floor(Math.random() * names.length)],
phone: '138' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0'),
capacity: capacity,
currentStock: Math.floor(capacity * (0.3 + Math.random() * 0.4)),
status: Math.random() > 0.1 ? 1 : 0,
createTime: new Date(now - i * 30 * 86400000).toISOString()
})
}
localStorage.setItem('mock_warehouses', JSON.stringify(newWarehouses))
getWarehouseList()
}, 10)
}
const handleWarehouseQuery = () => { const handleWarehouseQuery = () => {
warehouseQueryParams.pageNum = 1 warehouseQueryParams.pageIndex = 1
getWarehouseList() getWarehouseList()
} }
@ -392,19 +302,10 @@ const resetWarehouseQuery = () => {
handleWarehouseQuery() handleWarehouseQuery()
} }
const generateWarehouseCode = () => {
const warehouses = JSON.parse(localStorage.getItem('mock_warehouses') || '[]')
if (warehouses.length === 0) return 'WH001'
const codes = warehouses.map(w => w.warehouseCode).filter(code => code.startsWith('WH'))
if (codes.length === 0) return 'WH001'
const numbers = codes.map(code => parseInt(code.replace('WH', '')) || 0)
const maxNum = Math.max(...numbers)
return 'WH' + String(maxNum + 1).padStart(3, '0')
}
const handleWarehouseAdd = () => { const handleWarehouseAdd = () => {
warehouseIsEdit.value = false warehouseIsEdit.value = false
resetWarehouseForm() resetWarehouseForm()
//
warehouseForm.warehouseCode = generateWarehouseCode() warehouseForm.warehouseCode = generateWarehouseCode()
warehouseDialogVisible.value = true warehouseDialogVisible.value = true
} }
@ -415,11 +316,11 @@ const handleWarehouseEdit = (row) => {
id: row.id, id: row.id,
warehouseCode: row.warehouseCode, warehouseCode: row.warehouseCode,
warehouseName: row.warehouseName, warehouseName: row.warehouseName,
address: row.address, detailAddress: row.detailAddress,
manager: row.manager, contactPerson: row.contactPerson,
phone: row.phone || '', contactPhone: row.contactPhone || '',
capacity: row.capacity, stockCapacity: row.stockCapacity,
currentStock: row.currentStock || 0, stockInventory: row.stockInventory || 0,
status: row.status status: row.status
}) })
warehouseDialogVisible.value = true warehouseDialogVisible.value = true
@ -430,12 +331,12 @@ const resetWarehouseForm = () => {
id: null, id: null,
warehouseCode: '', warehouseCode: '',
warehouseName: '', warehouseName: '',
address: '', detailAddress: '',
manager: '', contactPerson: '',
phone: '', contactPhone: '',
capacity: null, stockCapacity: null,
currentStock: 0, stockInventory: 0,
status: 1 status: '启用'
}) })
warehouseFormRef.value?.clearValidate() warehouseFormRef.value?.clearValidate()
} }
@ -443,52 +344,22 @@ const resetWarehouseForm = () => {
const handleWarehouseSubmit = async () => { const handleWarehouseSubmit = async () => {
if (!warehouseFormRef.value) return if (!warehouseFormRef.value) return
await warehouseFormRef.value.validate((valid) => { await warehouseFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
warehouseSubmitLoading.value = true warehouseSubmitLoading.value = true
try { try {
const warehouses = JSON.parse(localStorage.getItem('mock_warehouses') || '[]')
if (warehouseIsEdit.value) { if (warehouseIsEdit.value) {
// await updateWarehouse(warehouseForm)
const index = warehouses.findIndex(w => w.id === warehouseForm.id) ElMessage.success('编辑成功')
if (index !== -1) {
warehouses[index] = {
...warehouses[index],
warehouseName: warehouseForm.warehouseName,
address: warehouseForm.address,
manager: warehouseForm.manager,
phone: warehouseForm.phone,
capacity: warehouseForm.capacity,
currentStock: warehouseForm.currentStock,
status: warehouseForm.status,
updateTime: new Date().toISOString()
}
}
} else { } else {
// await addWarehouse(warehouseForm)
const newWarehouse = { ElMessage.success('新增成功')
id: Date.now(),
warehouseCode: warehouseForm.warehouseCode,
warehouseName: warehouseForm.warehouseName,
address: warehouseForm.address,
manager: warehouseForm.manager,
phone: warehouseForm.phone,
capacity: warehouseForm.capacity,
currentStock: warehouseForm.currentStock || 0,
status: warehouseForm.status,
createTime: new Date().toISOString()
}
warehouses.push(newWarehouse)
} }
localStorage.setItem('mock_warehouses', JSON.stringify(warehouses))
ElMessage.success(warehouseIsEdit.value ? '编辑成功' : '新增成功')
warehouseDialogVisible.value = false warehouseDialogVisible.value = false
getWarehouseList() getWarehouseList()
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + (error.message || '未知错误'))
} finally { } finally {
warehouseSubmitLoading.value = false warehouseSubmitLoading.value = false
} }
@ -496,17 +367,20 @@ const handleWarehouseSubmit = async () => {
} }
const handleWarehouseDelete = (row) => { const handleWarehouseDelete = (row) => {
const ids = row.id ? [row.id] : []
ElMessageBox.confirm('确定要删除此仓库吗?', '提示', { ElMessageBox.confirm('确定要删除此仓库吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const warehouses = JSON.parse(localStorage.getItem('mock_warehouses') || '[]') try {
const filtered = warehouses.filter(w => w.id != row.id) await delWarehouse({ ids })
localStorage.setItem('mock_warehouses', JSON.stringify(filtered)) ElMessage.success('删除成功')
ElMessage.success('删除成功') getWarehouseList()
getWarehouseList() } catch (error) {
}).catch(() => {}) ElMessage.error('删除失败:' + (error.message || '未知错误'))
}
}).catch(() => { })
} }
// ==================== ==================== // ==================== ====================
@ -520,33 +394,33 @@ const stackFormRef = ref(null)
const warehouseOptions = ref([]) const warehouseOptions = ref([])
const stackQueryParams = reactive({ const stackQueryParams = reactive({
pageNum: 1, pageIndex: 1,
pageSize: 10, pageSize: 10,
stackName: '' stockName: ''
}) })
const stackForm = reactive({ const stackForm = reactive({
id: null, warehouseId: null,
stackCode: '', stockCode: '',
stackName: '', stockName: '',
warehouseName: '', warehouseName: '',
capacity: null, stockCapacity: null,
currentStock: null stockInventory: null
}) })
const stackFormRules = { const stackFormRules = {
stackName: [ stockName: [
{ required: true, message: '请输入垛位名称', trigger: 'blur' }, { required: true, message: '请输入垛位名称', trigger: 'blur' },
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' } { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
], ],
warehouseName: [ warehouseName: [
{ required: true, message: '请选择所属仓库', trigger: 'change' } { required: true, message: '请选择所属仓库', trigger: 'change' }
], ],
capacity: [ stockCapacity: [
{ required: true, message: '请输入容量', trigger: 'blur' }, { required: true, message: '请输入容量', trigger: 'blur' },
{ type: 'number', min: 0, message: '容量必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '容量必须大于等于0', trigger: 'blur' }
], ],
currentStock: [ stockInventory: [
{ required: true, message: '请输入当前库存', trigger: 'blur' }, { required: true, message: '请输入当前库存', trigger: 'blur' },
{ type: 'number', min: 0, message: '当前库存必须大于等于0', trigger: 'blur' } { type: 'number', min: 0, message: '当前库存必须大于等于0', trigger: 'blur' }
] ]
@ -557,82 +431,42 @@ const stackDialogTitle = computed(() => stackIsEdit.value ? '编辑垛位' : '
const getStackList = async () => { const getStackList = async () => {
stackLoading.value = true stackLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_stacks') || '[]') const response = await listWarehouseStock(stackQueryParams)
let filtered = mockData.filter(item => { const list = response.data?.list || response.rows || []
if (stackQueryParams.stackName && !item.stackName.includes(stackQueryParams.stackName)) return false stackList.value = list
return true stackTotal.value = response.data?.count || response.total || 0
})
const start = (stackQueryParams.pageNum - 1) * stackQueryParams.pageSize
const end = start + stackQueryParams.pageSize
stackList.value = filtered.slice(start, end)
stackTotal.value = filtered.length
if (mockData.length === 0) {
generateStackMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取垛位列表失败:' + error.message) ElMessage.error('获取垛位列表失败:' + (error.message || '未知错误'))
} finally { } finally {
stackLoading.value = false stackLoading.value = false
} }
} }
const generateStackMockData = () => { const loadWarehouseOptions = async () => {
setTimeout(() => { try {
const warehouses = ['仓库1', '仓库2', '仓库3'] const response = await listWarehouse({ pageIndex: 1, pageSize: 1000, status: '启用' })
const newStacks = [] warehouseOptions.value = response.data?.list || response.rows || []
const now = Date.now() } catch (error) {
for (let i = 1; i <= 20; i++) { ElMessage.error('加载仓库选项失败:' + (error.message || '未知错误'))
const capacity = Math.floor(Math.random() * 20000) + 5000 }
newStacks.push({
id: i,
stackCode: 'ST' + String(i).padStart(3, '0'),
stackName: i + '号垛位',
warehouseName: warehouses[Math.floor(Math.random() * warehouses.length)],
capacity: capacity,
currentStock: Math.floor(capacity * (0.2 + Math.random() * 0.6)),
createTime: new Date(now - i * 30 * 86400000).toISOString()
})
}
localStorage.setItem('mock_stacks', JSON.stringify(newStacks))
getStackList()
}, 10)
}
const loadWarehouseOptions = () => {
const warehouses = JSON.parse(localStorage.getItem('mock_warehouses') || '[]')
warehouseOptions.value = warehouses
.filter(w => w.status == 1)
.map(w => ({
warehouseName: w.warehouseName
}))
}
const generateStackCode = () => {
const stacks = JSON.parse(localStorage.getItem('mock_stacks') || '[]')
if (stacks.length === 0) return 'ST001'
const codes = stacks.map(s => s.stackCode).filter(code => code.startsWith('ST'))
if (codes.length === 0) return 'ST001'
const numbers = codes.map(code => parseInt(code.replace('ST', '')) || 0)
const maxNum = Math.max(...numbers)
return 'ST' + String(maxNum + 1).padStart(3, '0')
} }
//
const handleStackQuery = () => { const handleStackQuery = () => {
stackQueryParams.pageNum = 1 stackQueryParams.pageIndex = 1
getStackList() getStackList()
} }
const resetStackQuery = () => { const resetStackQuery = () => {
stackQueryParams.stackName = '' stackQueryParams.stockName = ''
handleStackQuery() handleStackQuery()
} }
const handleStackAdd = () => { const handleStackAdd = () => {
stackIsEdit.value = false stackIsEdit.value = false
resetStackForm() resetStackForm()
stackForm.stackCode = generateStackCode()
loadWarehouseOptions() loadWarehouseOptions()
stackForm.stockCode = generateWarehouseCode()
stackDialogVisible.value = true stackDialogVisible.value = true
} }
@ -640,11 +474,12 @@ const handleStackEdit = (row) => {
stackIsEdit.value = true stackIsEdit.value = true
Object.assign(stackForm, { Object.assign(stackForm, {
id: row.id, id: row.id,
stackCode: row.stackCode, stockCode: row.stockCode,
stackName: row.stackName, stockName: row.stockName,
warehouseName: row.warehouseName, warehouseName: row.warehouseName,
capacity: row.capacity, stockCapacity: row.stockCapacity,
currentStock: row.currentStock || 0 stockInventory: row.stockInventory || 0,
warehouseId: row.warehouseId
}) })
loadWarehouseOptions() loadWarehouseOptions()
stackDialogVisible.value = true stackDialogVisible.value = true
@ -653,11 +488,11 @@ const handleStackEdit = (row) => {
const resetStackForm = () => { const resetStackForm = () => {
Object.assign(stackForm, { Object.assign(stackForm, {
id: null, id: null,
stackCode: '', stockCode: '',
stackName: '', stockName: '',
warehouseName: '', warehouseName: '',
capacity: null, stockCapacity: null,
currentStock: 0 stockInventory: 0
}) })
stackFormRef.value?.clearValidate() stackFormRef.value?.clearValidate()
} }
@ -665,46 +500,22 @@ const resetStackForm = () => {
const handleStackSubmit = async () => { const handleStackSubmit = async () => {
if (!stackFormRef.value) return if (!stackFormRef.value) return
await stackFormRef.value.validate((valid) => { await stackFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
stackSubmitLoading.value = true stackSubmitLoading.value = true
try { try {
const stacks = JSON.parse(localStorage.getItem('mock_stacks') || '[]')
if (stackIsEdit.value) { if (stackIsEdit.value) {
// await updateWarehouseStock(stackForm)
const index = stacks.findIndex(s => s.id === stackForm.id) ElMessage.success('编辑成功')
if (index !== -1) {
stacks[index] = {
...stacks[index],
stackName: stackForm.stackName,
warehouseName: stackForm.warehouseName,
capacity: stackForm.capacity,
currentStock: stackForm.currentStock,
updateTime: new Date().toISOString()
}
}
} else { } else {
// await addWarehouseStock(stackForm)
const newStack = { ElMessage.success('新增成功')
id: Date.now(),
stackCode: stackForm.stackCode,
stackName: stackForm.stackName,
warehouseName: stackForm.warehouseName,
capacity: stackForm.capacity,
currentStock: stackForm.currentStock || 0,
createTime: new Date().toISOString()
}
stacks.push(newStack)
} }
localStorage.setItem('mock_stacks', JSON.stringify(stacks))
ElMessage.success(stackIsEdit.value ? '编辑成功' : '新增成功')
stackDialogVisible.value = false stackDialogVisible.value = false
getStackList() getStackList()
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + (error.message || '未知错误'))
} finally { } finally {
stackSubmitLoading.value = false stackSubmitLoading.value = false
} }
@ -712,31 +523,38 @@ const handleStackSubmit = async () => {
} }
const handleStackDelete = (row) => { const handleStackDelete = (row) => {
const ids = row.id ? [row.id] : []
ElMessageBox.confirm('确定要删除此垛位吗?', '提示', { ElMessageBox.confirm('确定要删除此垛位吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const stacks = JSON.parse(localStorage.getItem('mock_stacks') || '[]') try {
const filtered = stacks.filter(s => s.id != row.id) await delWarehouseStock({ ids })
localStorage.setItem('mock_stacks', JSON.stringify(filtered)) ElMessage.success('删除成功')
ElMessage.success('删除成功') getStackList()
getStackList() } catch (error) {
}).catch(() => {}) ElMessage.error('删除失败:' + (error.message || '未知错误'))
}
}).catch(() => { })
} }
// tab // tab
watch(activeTab, (newTab) => { watch(activeTab, (newTab) => {
// tab warehouseOptions
loadWarehouseOptions()
if (newTab === 'warehouse') { if (newTab === 'warehouse') {
getWarehouseList() getWarehouseList()
} else if (newTab === 'stack') { } else if (newTab === 'stack') {
getStackList() getStackList()
loadWarehouseOptions()
} }
}) })
onMounted(() => { onMounted(() => {
// tab
getWarehouseList() getWarehouseList()
//
loadWarehouseOptions() loadWarehouseOptions()
}) })
</script> </script>
@ -763,4 +581,3 @@ onMounted(() => {
padding: 20px; padding: 20px;
} }
</style> </style>

View File

@ -6,8 +6,8 @@
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px"> <el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 150px">
<el-option label="全部" value="" /> <el-option label="全部" value="" />
<el-option label="正常" value="1" /> <el-option label="正常" value="正常" />
<el-option label="停用" value="0" /> <el-option label="停用" value="停用" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -19,19 +19,19 @@
</div> </div>
<el-table v-loading="loading" :data="supplierList" border style="width: 100%; margin-top: 20px;"> <el-table v-loading="loading" :data="supplierList" border style="width: 100%; margin-top: 20px;">
<el-table-column prop="supplierCode" label="供应商ID" width="120" /> <!-- <el-table-column prop="supplierCode" label="供应商ID" width="120" /> -->
<el-table-column prop="supplierName" label="供应商名称" width="200" /> <el-table-column prop="supplierName" label="供应商名称" width="200" />
<el-table-column prop="supplierType" label="供应商类别" width="150" /> <el-table-column prop="supplierType" label="供应商类别" width="150" />
<el-table-column prop="contact" label="联系人" width="120" /> <el-table-column prop="contactPerson" label="联系人" width="120" />
<el-table-column prop="phone" label="手机号" width="130" /> <el-table-column prop="mobilePhone" label="手机号" width="130" />
<el-table-column prop="address" label="详细地址" min-width="200" /> <el-table-column prop="detailAddress" label="详细地址" min-width="200" />
<el-table-column prop="bankName" label="开户银行" width="150" /> <el-table-column prop="bankName" label="开户银行" width="150" />
<el-table-column prop="bankAccount" label="银行账号" width="180" /> <el-table-column prop="bankAccount" label="银行账号" width="180" />
<el-table-column prop="taxNumber" label="税号" width="180" /> <el-table-column prop="taxNumber" label="税号" width="180" />
<el-table-column prop="status" label="状态" width="100" align="center"> <el-table-column prop="status" label="状态" width="100" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'"> <el-tag :type="scope.row.status == '正常' ? 'success' : 'danger'">
{{ scope.row.status == 1 ? '正常' : '停用' }} {{ scope.row.status == '正常' ? '正常' : '停用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
@ -47,7 +47,7 @@
<pagination <pagination
v-show="total > 0" v-show="total > 0"
:total="total" :total="total"
v-model:page="queryParams.pageNum" v-model:page="queryParams.pageIndex"
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
@ -94,27 +94,27 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="联系人" prop="contact"> <el-form-item label="联系人" prop="contactPerson">
<el-input <el-input
v-model="supplierForm.contact" v-model="supplierForm.contactPerson"
placeholder="请输入联系人" placeholder="请输入联系人"
maxlength="20" maxlength="20"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="手机号" prop="phone"> <el-form-item label="手机号" prop="mobilePhone">
<el-input <el-input
v-model="supplierForm.phone" v-model="supplierForm.mobilePhone"
placeholder="请输入手机号" placeholder="请输入手机号"
maxlength="11" maxlength="11"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="详细地址" prop="address"> <el-form-item label="详细地址" prop="detailAddress">
<el-input <el-input
v-model="supplierForm.address" v-model="supplierForm.detailAddress"
type="textarea" type="textarea"
:rows="2" :rows="2"
placeholder="请输入详细地址" placeholder="请输入详细地址"
@ -154,8 +154,8 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="supplierForm.status"> <el-radio-group v-model="supplierForm.status">
<el-radio :label="1">正常</el-radio> <el-radio :label="'正常'">正常</el-radio>
<el-radio :label="0">停用</el-radio> <el-radio :label="'停用'">停用</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -182,13 +182,13 @@
<el-descriptions-item label="供应商名称">{{ currentSupplier.supplierName }}</el-descriptions-item> <el-descriptions-item label="供应商名称">{{ currentSupplier.supplierName }}</el-descriptions-item>
<el-descriptions-item label="供应商类别">{{ currentSupplier.supplierType }}</el-descriptions-item> <el-descriptions-item label="供应商类别">{{ currentSupplier.supplierType }}</el-descriptions-item>
<el-descriptions-item label="状态"> <el-descriptions-item label="状态">
<el-tag :type="currentSupplier.status == 1 ? 'success' : 'danger'"> <el-tag :type="currentSupplier.status == '正常' ? 'success' : 'danger'">
{{ currentSupplier.status == 1 ? '正常' : '停用' }} {{ currentSupplier.status == '正常' ? '正常' : '停用' }}
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="联系人">{{ currentSupplier.contact }}</el-descriptions-item> <el-descriptions-item label="联系人">{{ currentSupplier.contactPerson }}</el-descriptions-item>
<el-descriptions-item label="手机号">{{ currentSupplier.phone }}</el-descriptions-item> <el-descriptions-item label="手机号">{{ currentSupplier.mobilePhone }}</el-descriptions-item>
<el-descriptions-item label="详细地址" :span="2">{{ currentSupplier.address }}</el-descriptions-item> <el-descriptions-item label="详细地址" :span="2">{{ currentSupplier.detailAddress }}</el-descriptions-item>
<el-descriptions-item label="开户银行">{{ currentSupplier.bankName }}</el-descriptions-item> <el-descriptions-item label="开户银行">{{ currentSupplier.bankName }}</el-descriptions-item>
<el-descriptions-item label="银行账号">{{ currentSupplier.bankAccount }}</el-descriptions-item> <el-descriptions-item label="银行账号">{{ currentSupplier.bankAccount }}</el-descriptions-item>
<el-descriptions-item label="税号" :span="2">{{ currentSupplier.taxNumber }}</el-descriptions-item> <el-descriptions-item label="税号" :span="2">{{ currentSupplier.taxNumber }}</el-descriptions-item>
@ -201,6 +201,7 @@
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import { listSupplier, addSupplier, updateSupplier, delSupplier } from '@/api/base/supplier'
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
@ -213,7 +214,7 @@ const supplierFormRef = ref(null)
const currentSupplier = ref(null) const currentSupplier = ref(null)
const queryParams = reactive({ const queryParams = reactive({
pageNum: 1, pageIndex: 1,
pageSize: 10, pageSize: 10,
status: '' status: ''
}) })
@ -223,13 +224,13 @@ const supplierForm = reactive({
supplierCode: '', supplierCode: '',
supplierName: '', supplierName: '',
supplierType: '', supplierType: '',
contact: '', contactPerson: '',
phone: '', mobilePhone: '',
address: '', detailAddress: '',
bankName: '', bankName: '',
bankAccount: '', bankAccount: '',
taxNumber: '', taxNumber: '',
status: 1 status: '正常'
}) })
const supplierFormRules = { const supplierFormRules = {
@ -240,14 +241,14 @@ const supplierFormRules = {
supplierType: [ supplierType: [
{ required: true, message: '请选择供应商类别', trigger: 'change' } { required: true, message: '请选择供应商类别', trigger: 'change' }
], ],
contact: [ contactPerson: [
{ required: true, message: '请输入联系人', trigger: 'blur' } { required: true, message: '请输入联系人', trigger: 'blur' }
], ],
phone: [ mobilePhone: [
{ required: true, message: '请输入手机号', trigger: 'blur' }, { required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' } { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
], ],
address: [ detailAddress: [
{ required: true, message: '请输入详细地址', trigger: 'blur' } { required: true, message: '请输入详细地址', trigger: 'blur' }
], ],
bankName: [ bankName: [
@ -269,74 +270,18 @@ const dialogTitle = computed(() => isEdit.value ? '编辑供应商' : '新增供
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_suppliers') || '[]') const res = await listSupplier(queryParams)
let filtered = mockData.filter(item => { supplierList.value = res.data?.list || res.rows || []
if (queryParams.status !== '' && item.status != queryParams.status) return false total.value = res.data?.count || res.total || supplierList.value.length
return true
})
const start = (queryParams.pageNum - 1) * queryParams.pageSize
const end = start + queryParams.pageSize
supplierList.value = filtered.slice(start, end)
total.value = filtered.length
if (mockData.length === 0) {
generateMockData()
}
} catch (error) { } catch (error) {
ElMessage.error('获取供应商列表失败:' + error.message) ElMessage.error('获取供应商列表失败:' + (error.message || '未知错误'))
} finally { } finally {
loading.value = false loading.value = false
} }
} }
const generateMockData = () => {
setTimeout(() => {
const supplierTypes = ['煤炭供应商', '物流供应商', '设备供应商', '服务供应商']
const cities = ['太原市', '大同市', '阳泉市', '长治市', '晋城市', '朔州市', '晋中市', '运城市', '忻州市', '临汾市']
const banks = ['中国工商银行', '中国建设银行', '中国农业银行', '中国银行', '交通银行', '招商银行', '浦发银行']
const surnames = ['张', '李', '王', '赵', '刘', '陈', '杨', '黄', '周', '吴']
const names = ['三', '四', '五', '六', '七', '明', '强', '伟', '芳', '娜']
const newSuppliers = []
const now = Date.now()
for (let i = 1; i <= 20; i++) {
newSuppliers.push({
id: i,
supplierCode: 'S' + String(i).padStart(3, '0'),
supplierName: '煤贸商' + String.fromCharCode(64 + i),
supplierType: supplierTypes[Math.floor(Math.random() * supplierTypes.length)],
contact: surnames[Math.floor(Math.random() * surnames.length)] + names[Math.floor(Math.random() * names.length)],
phone: '138' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0'),
address: cities[Math.floor(Math.random() * cities.length)] + 'xxx区xxx路xxx号',
bankName: banks[Math.floor(Math.random() * banks.length)],
bankAccount: '622' + String(Math.floor(Math.random() * 10000000000000000)).padStart(16, '0'),
taxNumber: '91140000' + String(Math.floor(Math.random() * 100000000)).padStart(8, '0') + String.fromCharCode(65 + Math.floor(Math.random() * 26)),
status: Math.random() > 0.2 ? 1 : 0,
createTime: new Date(now - i * 30 * 86400000).toISOString(),
updateTime: new Date(now - i * 30 * 86400000).toISOString()
})
}
localStorage.setItem('mock_suppliers', JSON.stringify(newSuppliers))
getList()
}, 10)
}
const generateSupplierCode = () => {
const mockData = JSON.parse(localStorage.getItem('mock_suppliers') || '[]')
let maxCode = 0
mockData.forEach(item => {
const match = item.supplierCode.match(/^S(\d+)$/)
if (match) {
const num = parseInt(match[1])
if (num > maxCode) {
maxCode = num
}
}
})
return 'S' + String(maxCode + 1).padStart(3, '0')
}
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNum = 1 queryParams.pageIndex = 1
getList() getList()
} }
@ -348,8 +293,6 @@ const resetQuery = () => {
const handleAdd = () => { const handleAdd = () => {
isEdit.value = false isEdit.value = false
resetForm() resetForm()
// ID
supplierForm.supplierCode = generateSupplierCode()
dialogVisible.value = true dialogVisible.value = true
} }
@ -365,9 +308,9 @@ const handleEdit = (row) => {
supplierCode: row.supplierCode, supplierCode: row.supplierCode,
supplierName: row.supplierName, supplierName: row.supplierName,
supplierType: row.supplierType, supplierType: row.supplierType,
contact: row.contact, contactPerson: row.contactPerson,
phone: row.phone, mobilePhone: row.mobilePhone,
address: row.address, detailAddress: row.detailAddress,
bankName: row.bankName, bankName: row.bankName,
bankAccount: row.bankAccount, bankAccount: row.bankAccount,
taxNumber: row.taxNumber, taxNumber: row.taxNumber,
@ -377,16 +320,19 @@ const handleEdit = (row) => {
} }
const handleDelete = (row) => { const handleDelete = (row) => {
const Ids = row.id ? [row.id] : []
ElMessageBox.confirm('确定要删除此供应商吗?', '提示', { ElMessageBox.confirm('确定要删除此供应商吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(async () => {
const suppliers = JSON.parse(localStorage.getItem('mock_suppliers') || '[]') try {
const filtered = suppliers.filter(s => s.id != row.id) await delSupplier({ ids: Ids })
localStorage.setItem('mock_suppliers', JSON.stringify(filtered)) ElMessage.success('删除成功')
ElMessage.success('删除成功') getList()
getList() } catch (error) {
ElMessage.error('删除失败:' + (error.message || '未知错误'))
}
}).catch(() => {}) }).catch(() => {})
} }
@ -396,13 +342,13 @@ const resetForm = () => {
supplierCode: '', supplierCode: '',
supplierName: '', supplierName: '',
supplierType: '', supplierType: '',
contact: '', contactPerson: '',
phone: '', mobilePhone: '',
address: '', detailAddress: '',
bankName: '', bankName: '',
bankAccount: '', bankAccount: '',
taxNumber: '', taxNumber: '',
status: 1 status: '正常'
}) })
supplierFormRef.value?.clearValidate() supplierFormRef.value?.clearValidate()
} }
@ -410,70 +356,22 @@ const resetForm = () => {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!supplierFormRef.value) return if (!supplierFormRef.value) return
await supplierFormRef.value.validate((valid) => { await supplierFormRef.value.validate(async (valid) => {
if (!valid) return if (!valid) return
submitLoading.value = true submitLoading.value = true
try { try {
const mockData = JSON.parse(localStorage.getItem('mock_suppliers') || '[]')
const now = new Date().toISOString()
if (isEdit.value) { if (isEdit.value) {
// await updateSupplier(supplierForm)
const index = mockData.findIndex(item => item.id === supplierForm.id) ElMessage.success('编辑成功')
if (index !== -1) {
mockData[index] = {
...mockData[index],
supplierName: supplierForm.supplierName,
supplierType: supplierForm.supplierType,
contact: supplierForm.contact,
phone: supplierForm.phone,
address: supplierForm.address,
bankName: supplierForm.bankName,
bankAccount: supplierForm.bankAccount,
taxNumber: supplierForm.taxNumber,
status: supplierForm.status,
updateTime: now
}
}
} else { } else {
// await addSupplier(supplierForm)
// ID ElMessage.success('新增成功')
if (!supplierForm.supplierCode || !supplierForm.supplierCode.match(/^S\d{3}$/)) {
supplierForm.supplierCode = generateSupplierCode()
}
// ID
const codeExists = mockData.find(item => item.supplierCode === supplierForm.supplierCode)
if (codeExists) {
//
supplierForm.supplierCode = generateSupplierCode()
}
const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1
mockData.push({
id: newId,
supplierCode: supplierForm.supplierCode,
supplierName: supplierForm.supplierName,
supplierType: supplierForm.supplierType,
contact: supplierForm.contact,
phone: supplierForm.phone,
address: supplierForm.address,
bankName: supplierForm.bankName,
bankAccount: supplierForm.bankAccount,
taxNumber: supplierForm.taxNumber,
status: supplierForm.status,
createTime: now,
updateTime: now
})
} }
localStorage.setItem('mock_suppliers', JSON.stringify(mockData))
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
dialogVisible.value = false dialogVisible.value = false
getList() getList()
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + (error.message || '未知错误'))
} finally { } finally {
submitLoading.value = false submitLoading.value = false
} }

View File

@ -2,46 +2,34 @@
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<el-table v-loading="loading" :data="alertConfigList" border style="width: 100%"> <el-table v-loading="loading" :data="alertConfigList" border style="width: 100%">
<el-table-column prop="category" label="报警类别" width="150" align="center"> <el-table-column prop="alertType" label="报警类别" width="150" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.category === 'insufficient' ? 'danger' : 'warning'"> <el-tag :type="scope.row.alertType === '库存不足' ? 'danger' : 'warning'">
{{ scope.row.category === 'insufficient' ? '库存不足' : '库存积压' }} <!-- {{ scope.row.alertType === 'insufficient' ? '库存不足' : '库存积压' }} -->
{{ scope.row.alertType }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="level" label="报警级别" width="120" align="center"> <el-table-column prop="alertLevel" label="报警级别" width="120" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="getLevelType(scope.row.level)"> <el-tag :type="getLevelType(scope.row.alertLevel)">
{{ getLevelName(scope.row.level) }} {{ getLevelName(scope.row.alertLevel) }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="threshold" label="阈值" width="200" align="center"> <el-table-column prop="threshold" label="阈值" width="200" align="center">
<template #default="scope"> <template #default="scope">
<span v-if="!scope.row.editing">{{ scope.row.threshold }} {{ scope.row.unit }}</span> <span v-if="!scope.row.editing">{{ scope.row.threshold }} {{ scope.row.unit }}</span>
<el-input-number <el-input-number v-else v-model="scope.row.threshold" :min="0" :precision="2" :controls="false"
v-else style="width: 120px" />
v-model="scope.row.threshold"
:min="0"
:precision="2"
:controls="false"
style="width: 120px"
/>
<span style="margin-left: 8px">{{ scope.row.unit }}</span> <span style="margin-left: 8px">{{ scope.row.unit }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="description" label="说明" min-width="200"> <el-table-column prop="description" label="说明" min-width="200">
<template #default="scope"> <template #default="scope">
<span v-if="!scope.row.editing">{{ scope.row.description || '-' }}</span> <span v-if="!scope.row.editing">{{ scope.row.description || '-' }}</span>
<el-input <el-input v-else v-model="scope.row.description" type="textarea" :rows="2" placeholder="请输入说明"
v-else maxlength="200" style="width: 100%" />
v-model="scope.row.description"
type="textarea"
:rows="2"
placeholder="请输入说明"
maxlength="200"
style="width: 100%"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center"> <el-table-column prop="status" label="状态" width="100" align="center">
@ -55,12 +43,8 @@
<template #default="scope"> <template #default="scope">
<template v-if="!scope.row.editing"> <template v-if="!scope.row.editing">
<el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button> <el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button <el-button link :type="scope.row.status === 1 ? 'warning' : 'success'" size="small"
link @click="handleToggleStatus(scope.row)">
:type="scope.row.status === 1 ? 'warning' : 'success'"
size="small"
@click="handleToggleStatus(scope.row)"
>
{{ scope.row.status === 1 ? '禁用' : '启用' }} {{ scope.row.status === 1 ? '禁用' : '启用' }}
</el-button> </el-button>
</template> </template>
@ -78,7 +62,7 @@
<script setup name="InventoryAlertConfig"> <script setup name="InventoryAlertConfig">
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { listInventoryAlertConfig, addInventoryAlertConfig, delInventoryAlertConfig } from "@/api/system/inventory-alert"
const loading = ref(false) const loading = ref(false)
const alertConfigList = ref([]) const alertConfigList = ref([])
@ -90,8 +74,15 @@ const getLevelName = (level) => {
} }
return levelMap[level] || level return levelMap[level] || level
} }
const queryParams = reactive({
pageIndex: 1,
pageSize: 10,
alertType: null,
alertLevel: null,
status: null
})
const getLevelType = (level) => { const getLevelType = (level) => {
const typeMap = { const typeMap = {
'low': 'info', 'low': 'info',
'medium': 'warning', 'medium': 'warning',
@ -132,71 +123,75 @@ const getList = async () => {
} }
const generateDefaultConfigs = () => { const generateDefaultConfigs = () => {
const defaultConfigs = [ listInventoryAlertConfig(queryParams).then(response => {
// - alertConfigList.value = response.data.list
{
id: 1,
category: 'insufficient',
level: 'low',
threshold: 100,
unit: '吨',
description: '库存低于100吨时触发低级别报警',
status: 1
},
{
id: 2,
category: 'insufficient',
level: 'medium',
threshold: 50,
unit: '吨',
description: '库存低于50吨时触发中级别报警',
status: 1
},
{
id: 3,
category: 'insufficient',
level: 'high',
threshold: 20,
unit: '吨',
description: '库存低于20吨时触发高级别报警',
status: 1
},
// -
{
id: 4,
category: 'overstock',
level: 'low',
threshold: 5000,
unit: '吨',
description: '库存超过5000吨时触发低级别报警',
status: 1
},
{
id: 5,
category: 'overstock',
level: 'medium',
threshold: 8000,
unit: '吨',
description: '库存超过8000吨时触发中级别报警',
status: 1
},
{
id: 6,
category: 'overstock',
level: 'high',
threshold: 10000,
unit: '吨',
description: '库存超过10000吨时触发高级别报警',
status: 1
}
]
localStorage.setItem('mock_inventory_alert_configs', JSON.stringify(defaultConfigs)) // const defaultConfigs = [
alertConfigList.value = defaultConfigs.map(item => ({ // // -
...item, // {
editing: false, // id: 1,
originalData: null // category: 'insufficient',
})) // level: 'low',
// threshold: 100,
// unit: '',
// description: '100',
// status: 1
// },
// {
// id: 2,
// category: 'insufficient',
// level: 'medium',
// threshold: 50,
// unit: '',
// description: '50',
// status: 1
// },
// {
// id: 3,
// category: 'insufficient',
// level: 'high',
// threshold: 20,
// unit: '',
// description: '20',
// status: 1
// },
// // -
// {
// id: 4,
// category: 'overstock',
// level: 'low',
// threshold: 5000,
// unit: '',
// description: '5000',
// status: 1
// },
// {
// id: 5,
// category: 'overstock',
// level: 'medium',
// threshold: 8000,
// unit: '',
// description: '8000',
// status: 1
// },
// {
// id: 6,
// category: 'overstock',
// level: 'high',
// threshold: 10000,
// unit: '',
// description: '10000',
// status: 1
// }
// ]
// localStorage.setItem('mock_inventory_alert_configs', JSON.stringify(defaultConfigs))
// alertConfigList.value = defaultConfigs.map(item => ({
// ...item,
// editing: false,
// originalData: null
// }))
})
} }
const handleEdit = (row) => { const handleEdit = (row) => {
@ -275,10 +270,15 @@ const handleToggleStatus = (row) => {
} catch (error) { } catch (error) {
ElMessage.error('操作失败:' + error.message) ElMessage.error('操作失败:' + error.message)
} }
}).catch(() => {}) }).catch(() => { })
} }
onMounted(() => getList())
onMounted(() => {
getList()
generateDefaultConfigs()
})
</script> </script>
<style scoped> <style scoped>
@ -294,4 +294,3 @@ onMounted(() => getList())
text-align: left; text-align: left;
} }
</style> </style>

View File

@ -7,7 +7,8 @@ import { defineConfig, loadEnv } from 'vite'
import path from 'path' import path from 'path'
import createVitePlugins from './vite/plugins' import createVitePlugins from './vite/plugins'
const baseUrl = 'http://172.16.1.116:8000/' // 后端接口 // const baseUrl = 'http://172.16.1.116:8000/' // 后端接口
const baseUrl = 'http://172.16.1.162:40980/' // 后端接口
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => { export default defineConfig(({ mode, command }) => {