暂存更改
This commit is contained in:
41
src/api/contract.js
Normal file
41
src/api/contract.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import axios from 'axios'
|
||||
import { mockContractAPI } from './mock/contract'
|
||||
|
||||
// 开关:true 用 mock,false 用真实接口
|
||||
const USE_MOCK = true
|
||||
|
||||
// axios 实例
|
||||
const request = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 5000
|
||||
})
|
||||
|
||||
// 获取合同列表
|
||||
export const getContractList = (params) => {
|
||||
if (USE_MOCK) return mockContractAPI.getList(params)
|
||||
return request.get('/contracts', { params }).then(r => r.data)
|
||||
}
|
||||
|
||||
// 获取合同详情
|
||||
export const getContractDetail = (id) => {
|
||||
if (USE_MOCK) return mockContractAPI.getDetail(id)
|
||||
return request.get(`/contracts/${id}`).then(r => r.data)
|
||||
}
|
||||
|
||||
// 新增合同
|
||||
export const createContract = (data) => {
|
||||
if (USE_MOCK) return mockContractAPI.create(data)
|
||||
return request.post('/contracts', data).then(r => r.data)
|
||||
}
|
||||
|
||||
// 更新合同
|
||||
export const updateContract = (id, data) => {
|
||||
if (USE_MOCK) return mockContractAPI.update(id, data)
|
||||
return request.put(`/contracts/${id}`, data).then(r => r.data)
|
||||
}
|
||||
|
||||
// 删除合同
|
||||
export const deleteContractAPI = (id) => {
|
||||
if (USE_MOCK) return mockContractAPI.delete(id)
|
||||
return request.delete(`/contracts/${id}`).then(r => r.data)
|
||||
}
|
||||
41
src/api/customer.js
Normal file
41
src/api/customer.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import axios from 'axios'
|
||||
import { mockCustomerAPI } from './mock/customer'
|
||||
|
||||
// 开关:true 用 mock,false 用真实接口
|
||||
const USE_MOCK = true
|
||||
|
||||
// axios 实例
|
||||
const request = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 5000
|
||||
})
|
||||
|
||||
// 获取客户列表
|
||||
export const getCustomerList = (params) => {
|
||||
if (USE_MOCK) return mockCustomerAPI.getList(params)
|
||||
return request.get('/customers', { params }).then(r => r.data)
|
||||
}
|
||||
|
||||
// 获取客户详情
|
||||
export const getCustomerDetail = (id) => {
|
||||
if (USE_MOCK) return mockCustomerAPI.getDetail(id)
|
||||
return request.get(`/customers/${id}`).then(r => r.data)
|
||||
}
|
||||
|
||||
// 新增客户
|
||||
export const createCustomer = (data) => {
|
||||
if (USE_MOCK) return mockCustomerAPI.create(data)
|
||||
return request.post('/customers', data).then(r => r.data)
|
||||
}
|
||||
|
||||
// 更新客户
|
||||
export const updateCustomer = (id, data) => {
|
||||
if (USE_MOCK) return mockCustomerAPI.update(id, data)
|
||||
return request.put(`/customers/${id}`, data).then(r => r.data)
|
||||
}
|
||||
|
||||
// 删除客户
|
||||
export const deleteCustomerAPI = (id) => {
|
||||
if (USE_MOCK) return mockCustomerAPI.delete(id)
|
||||
return request.delete(`/customers/${id}`).then(r => r.data)
|
||||
}
|
||||
151
src/api/mock/contract.js
Normal file
151
src/api/mock/contract.js
Normal file
@@ -0,0 +1,151 @@
|
||||
// 模拟合同数据
|
||||
const mockContracts = [
|
||||
{
|
||||
id: 1,
|
||||
contract_no: 'HT-2025-001',
|
||||
contract_name: '蜜雪冰城加盟合同',
|
||||
type: '加盟合同',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '张三',
|
||||
sign_date: '2025-01-15',
|
||||
start_date: '2025-02-01',
|
||||
end_date: '2028-01-31',
|
||||
amount: 300000,
|
||||
status: '生效中',
|
||||
remark: '三年期加盟合同',
|
||||
create_time: '2025-01-15 10:30:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
contract_no: 'HT-2025-002',
|
||||
contract_name: '原材料供货合同',
|
||||
type: '供货合同',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '李四',
|
||||
sign_date: '2025-03-10',
|
||||
start_date: '2025-04-01',
|
||||
end_date: '2026-03-31',
|
||||
amount: 50000,
|
||||
status: '生效中',
|
||||
remark: '年度供货协议',
|
||||
create_time: '2025-03-10 09:15:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
contract_no: 'HT-2024-010',
|
||||
contract_name: '门店租赁合同',
|
||||
type: '租赁合同',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '王五',
|
||||
sign_date: '2024-06-20',
|
||||
start_date: '2024-07-01',
|
||||
end_date: '2025-06-30',
|
||||
amount: 120000,
|
||||
status: '已到期',
|
||||
remark: '已续签',
|
||||
create_time: '2024-06-20 14:20:00'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
contract_no: 'HT-2025-003',
|
||||
contract_name: '设备维护服务合同',
|
||||
type: '服务合同',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '赵六',
|
||||
sign_date: '2025-05-01',
|
||||
start_date: '2025-05-15',
|
||||
end_date: '2026-05-14',
|
||||
amount: 15000,
|
||||
status: '待审批',
|
||||
remark: '',
|
||||
create_time: '2025-05-01 11:00:00'
|
||||
}
|
||||
]
|
||||
|
||||
// 模拟网络延迟
|
||||
const delay = (ms = 300) => new Promise(r => setTimeout(r, ms))
|
||||
|
||||
// Mock API
|
||||
export const mockContractAPI = {
|
||||
// 获取列表
|
||||
async getList(params = {}) {
|
||||
await delay()
|
||||
let result = [...mockContracts]
|
||||
|
||||
// 关键词搜索
|
||||
if (params.keyword) {
|
||||
const keyword = params.keyword.toLowerCase()
|
||||
result = result.filter(item =>
|
||||
item.contract_no.toLowerCase().includes(keyword) ||
|
||||
item.contract_name.toLowerCase().includes(keyword) ||
|
||||
item.party_b.toLowerCase().includes(keyword)
|
||||
)
|
||||
}
|
||||
|
||||
// 合同类型筛选
|
||||
if (params.type) {
|
||||
result = result.filter(item => item.type === params.type)
|
||||
}
|
||||
|
||||
// 日期范围筛选(按签订日期)
|
||||
if (params.startDate && params.endDate) {
|
||||
const start = new Date(params.startDate)
|
||||
const end = new Date(params.endDate)
|
||||
result = result.filter(item => {
|
||||
const signDate = new Date(item.sign_date)
|
||||
return signDate >= start && signDate <= end
|
||||
})
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (params.status) {
|
||||
result = result.filter(item => item.status === params.status)
|
||||
}
|
||||
|
||||
return { code: 200, data: result, total: result.length }
|
||||
},
|
||||
|
||||
// 获取详情
|
||||
async getDetail(id) {
|
||||
await delay()
|
||||
const contract = mockContracts.find(item => item.id === id)
|
||||
if (contract) {
|
||||
return { code: 200, data: contract }
|
||||
}
|
||||
return { code: 404, message: '合同不存在' }
|
||||
},
|
||||
|
||||
// 新增
|
||||
async create(data) {
|
||||
await delay()
|
||||
const newContract = {
|
||||
id: Date.now(),
|
||||
...data,
|
||||
create_time: new Date().toISOString().replace('T', ' ').slice(0, 19)
|
||||
}
|
||||
mockContracts.push(newContract)
|
||||
return { code: 200, data: newContract, message: '新增成功' }
|
||||
},
|
||||
|
||||
// 更新
|
||||
async update(id, data) {
|
||||
await delay()
|
||||
const index = mockContracts.findIndex(item => item.id === id)
|
||||
if (index !== -1) {
|
||||
mockContracts[index] = { ...mockContracts[index], ...data }
|
||||
return { code: 200, data: mockContracts[index], message: '更新成功' }
|
||||
}
|
||||
return { code: 404, message: '合同不存在' }
|
||||
},
|
||||
|
||||
// 删除
|
||||
async delete(id) {
|
||||
await delay()
|
||||
const index = mockContracts.findIndex(item => item.id === id)
|
||||
if (index !== -1) {
|
||||
mockContracts.splice(index, 1)
|
||||
return { code: 200, message: '删除成功' }
|
||||
}
|
||||
return { code: 404, message: '合同不存在' }
|
||||
}
|
||||
}
|
||||
144
src/api/mock/customer.js
Normal file
144
src/api/mock/customer.js
Normal file
@@ -0,0 +1,144 @@
|
||||
// 模拟客户数据
|
||||
const mockCustomers = [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
phone: '13800138001',
|
||||
province: '广东省',
|
||||
city: '深圳市',
|
||||
district: '南山区',
|
||||
address: '科技园路1号',
|
||||
email: 'zhangsan@example.com',
|
||||
customer_type: 'VIP',
|
||||
create_time: '2025-01-15 10:30:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
phone: '13800138002',
|
||||
province: '浙江省',
|
||||
city: '杭州市',
|
||||
district: '西湖区',
|
||||
address: '文三路100号',
|
||||
email: 'lisi@example.com',
|
||||
customer_type: 'Normal',
|
||||
create_time: '2025-02-20 14:20:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
phone: '13800138003',
|
||||
province: '四川省',
|
||||
city: '成都市',
|
||||
district: '武侯区',
|
||||
address: '天府大道200号',
|
||||
email: 'wangwu@example.com',
|
||||
customer_type: 'VIP',
|
||||
create_time: '2025-03-10 09:15:00'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '赵六',
|
||||
phone: '13800138004',
|
||||
province: '湖南省',
|
||||
city: '长沙市',
|
||||
district: '岳麓区',
|
||||
address: '麓山南路100号',
|
||||
email: 'zhaoliu@example.com',
|
||||
customer_type: 'Normal',
|
||||
create_time: '2025-04-05 16:45:00'
|
||||
}
|
||||
]
|
||||
|
||||
// 模拟网络延迟
|
||||
const delay = (ms = 300) => new Promise(r => setTimeout(r, ms))
|
||||
|
||||
// Mock API
|
||||
export const mockCustomerAPI = {
|
||||
// 获取列表
|
||||
async getList(params = {}) {
|
||||
await delay()
|
||||
let result = [...mockCustomers]
|
||||
|
||||
// 关键词搜索
|
||||
if (params.keyword) {
|
||||
const keyword = params.keyword.toLowerCase()
|
||||
const searchField = params.searchField || '1'
|
||||
|
||||
if (searchField === '2') {
|
||||
// 编号:精确匹配
|
||||
result = result.filter(item => String(item.id) === keyword)
|
||||
} else if (searchField === '1') {
|
||||
// 姓名:模糊匹配
|
||||
result = result.filter(item => item.name.includes(keyword))
|
||||
} else if (searchField === '3') {
|
||||
// 电话:模糊匹配
|
||||
result = result.filter(item => item.phone.includes(keyword))
|
||||
} else if (searchField === '4') {
|
||||
// 邮箱:模糊匹配
|
||||
result = result.filter(item => item.email.includes(keyword))
|
||||
} else {
|
||||
// 默认:模糊匹配所有字段
|
||||
result = result.filter(item =>
|
||||
String(item.id).includes(keyword) ||
|
||||
item.name.includes(keyword) ||
|
||||
item.phone.includes(keyword) ||
|
||||
item.email.includes(keyword)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 客户类型筛选
|
||||
if (params.customer_type) {
|
||||
result = result.filter(item => item.customer_type === params.customer_type)
|
||||
}
|
||||
|
||||
return { code: 200, data: result, total: result.length }
|
||||
},
|
||||
|
||||
// 获取详情
|
||||
async getDetail(id) {
|
||||
await delay()
|
||||
const customer = mockCustomers.find(item => item.id === id)
|
||||
if (customer) {
|
||||
return { code: 200, data: customer }
|
||||
}
|
||||
return { code: 404, message: '客户不存在' }
|
||||
},
|
||||
|
||||
// 新增
|
||||
async create(data) {
|
||||
await delay()
|
||||
// 生成自增 ID
|
||||
const maxId = mockCustomers.length > 0 ? Math.max(...mockCustomers.map(item => item.id)) : 0
|
||||
const newCustomer = {
|
||||
id: maxId + 1,
|
||||
...data,
|
||||
create_time: new Date().toISOString().replace('T', ' ').slice(0, 19)
|
||||
}
|
||||
mockCustomers.push(newCustomer)
|
||||
return { code: 200, data: newCustomer, message: '新增成功' }
|
||||
},
|
||||
|
||||
// 更新
|
||||
async update(id, data) {
|
||||
await delay()
|
||||
const index = mockCustomers.findIndex(item => item.id === id)
|
||||
if (index !== -1) {
|
||||
mockCustomers[index] = { ...mockCustomers[index], ...data }
|
||||
return { code: 200, data: mockCustomers[index], message: '更新成功' }
|
||||
}
|
||||
return { code: 404, message: '客户不存在' }
|
||||
},
|
||||
|
||||
// 删除
|
||||
async delete(id) {
|
||||
await delay()
|
||||
const index = mockCustomers.findIndex(item => item.id === id)
|
||||
if (index !== -1) {
|
||||
mockCustomers.splice(index, 1)
|
||||
return { code: 200, message: '删除成功' }
|
||||
}
|
||||
return { code: 404, message: '客户不存在' }
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,176 @@
|
||||
<script setup>
|
||||
import { ref,computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getContractList,
|
||||
createContract,
|
||||
updateContract,
|
||||
deleteContractAPI
|
||||
} from '../api/contract'
|
||||
|
||||
const searchKeyword = ref('')
|
||||
const selectField = ref('1')
|
||||
const search = ref('')
|
||||
const select = ref('1')
|
||||
const dateRange = ref([])
|
||||
const loading=ref(false)
|
||||
|
||||
//过滤搜索结果
|
||||
const filteredContracts=computed(()=>{
|
||||
const filterType = ref('')
|
||||
const loading = ref(false)
|
||||
const searchResults = ref([])
|
||||
const showSearchResults = ref(false)
|
||||
const showAddForm = ref(false)
|
||||
const isEditMode = ref(false)
|
||||
const currentContractId = ref(null)
|
||||
|
||||
const form = reactive({
|
||||
contract_no: '',
|
||||
contract_name: '',
|
||||
type: '',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '',
|
||||
sign_date: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
amount: 0,
|
||||
status: '待审批',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
//处理搜索
|
||||
const handleSearch=()=>{
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// 获取合同列表
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
const res = await getContractList()
|
||||
searchResults.value = res.data
|
||||
showSearchResults.value = true
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
//日期变更处理
|
||||
const handleDateChange=()=>{
|
||||
handleSearch();
|
||||
// 处理搜索
|
||||
const handleSearch = async () => {
|
||||
loading.value = true
|
||||
|
||||
let keyword = search.value
|
||||
if (select.value === '1' && keyword && !keyword.startsWith('HT')) {
|
||||
keyword = 'HT' + keyword
|
||||
}
|
||||
|
||||
const params = {
|
||||
keyword,
|
||||
searchField: select.value,
|
||||
type: filterType.value,
|
||||
startDate: dateRange.value?.[0],
|
||||
endDate: dateRange.value?.[1]
|
||||
}
|
||||
|
||||
const res = await getContractList(params)
|
||||
searchResults.value = res.data
|
||||
showSearchResults.value = true
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 日期变更处理
|
||||
const handleDateChange = () => {
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const resetSearch = () => {
|
||||
searchKeyword.value = ''
|
||||
searchField.value = '1'
|
||||
search.value = ''
|
||||
select.value = '1'
|
||||
filterType.value = ''
|
||||
dateRange.value = []
|
||||
handleSearch()
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 新增合同
|
||||
const addContract = () => {
|
||||
resetForm()
|
||||
showAddForm.value = true
|
||||
showSearchResults.value = false
|
||||
}
|
||||
|
||||
// 编辑合同
|
||||
const editContract = (row) => {
|
||||
isEditMode.value = true
|
||||
currentContractId.value = row.id
|
||||
Object.assign(form, {
|
||||
contract_no: row.contract_no,
|
||||
contract_name: row.contract_name,
|
||||
type: row.type,
|
||||
party_a: row.party_a,
|
||||
party_b: row.party_b,
|
||||
sign_date: row.sign_date,
|
||||
start_date: row.start_date,
|
||||
end_date: row.end_date,
|
||||
amount: row.amount,
|
||||
status: row.status,
|
||||
remark: row.remark
|
||||
})
|
||||
showAddForm.value = true
|
||||
showSearchResults.value = false
|
||||
}
|
||||
|
||||
// 保存合同
|
||||
const saveContract = async () => {
|
||||
if (isEditMode.value) {
|
||||
await updateContract(currentContractId.value, { ...form })
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createContract({ ...form })
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
cancelAdd()
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 删除合同
|
||||
const deleteContract = (id) => {
|
||||
ElMessageBox.confirm('确定删除该合同吗?', '提示', {
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
await deleteContractAPI(id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchData()
|
||||
})
|
||||
}
|
||||
|
||||
// 取消
|
||||
const cancelAdd = () => {
|
||||
resetForm()
|
||||
showAddForm.value = false
|
||||
showSearchResults.value = true
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, {
|
||||
contract_no: '',
|
||||
contract_name: '',
|
||||
type: '',
|
||||
party_a: '蜜雪冰城股份有限公司',
|
||||
party_b: '',
|
||||
sign_date: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
amount: 0,
|
||||
status: '待审批',
|
||||
remark: ''
|
||||
})
|
||||
isEditMode.value = false
|
||||
currentContractId.value = null
|
||||
}
|
||||
|
||||
// 状态样式
|
||||
const getStatusType = (status) => {
|
||||
const map = {
|
||||
'生效中': 'success',
|
||||
'已到期': 'danger',
|
||||
'待审批': 'warning',
|
||||
'已终止': 'info'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
}
|
||||
|
||||
// 日期快捷选项
|
||||
@@ -69,128 +212,233 @@ const formatDate = (date) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="contract-container">
|
||||
<!-- 搜索栏区域 -->
|
||||
<div class="contract-search">
|
||||
<div class="search-row">
|
||||
<el-input v-model="searchKeyword" style="max-width: 600px" placeholder="Please input"
|
||||
class="contract-search-with-select">
|
||||
<template #prepend>
|
||||
<el-select v-model="searchField" placeholder="Select" style="width: 115px">
|
||||
<el-option label="编号" value="1" />
|
||||
<el-option label="名称" value="2" />
|
||||
<el-option label="类型" value="3" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button :icon="Search" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="search-row date-range">
|
||||
<span class="date-label">日期范围</span>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:shortcuts="dateShortcuts"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="contract-container">
|
||||
<!-- 搜索栏区域 -->
|
||||
<div class="contract-search">
|
||||
<!-- 第一行:搜索框 + 按钮 -->
|
||||
<div class="search-row">
|
||||
<el-input v-model="search" style="max-width: 500px" placeholder="请输入搜索关键词"
|
||||
class="contract-search-with-select" @keyup.enter="handleSearch">
|
||||
<template #prepend>
|
||||
<el-select v-model="select" placeholder="请选择" style="width: 115px">
|
||||
<el-option label="编号" value="1" />
|
||||
<el-option label="名称" value="2" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button :icon="Search" @click="handleSearch" />
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-button type="primary" @click="addCustomer" style="margin-left: 20px">
|
||||
新增合同
|
||||
</el-button>
|
||||
<el-button type="default" @click="resetSearch" style="margin-left:20px">
|
||||
重置
|
||||
</el-button>
|
||||
<div class="search-buttons">
|
||||
<el-button type="success" @click="addContract">新增合同</el-button>
|
||||
<el-button type="default" @click="resetSearch">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 合同列表 -->
|
||||
<div class="contract-list">
|
||||
<div v-if="loading" class="loading-container">
|
||||
<el-skeleton :rows="5" animated />
|
||||
</div>
|
||||
<!-- 第二行:筛选条件 -->
|
||||
<div class="filter-row">
|
||||
<span class="filter-label">筛选条件:</span>
|
||||
<el-select v-model="filterType" placeholder="合同类型" clearable style="width: 150px;" @change="handleSearch">
|
||||
<el-option label="全部类型" value="" />
|
||||
<el-option label="加盟合同" value="加盟合同" />
|
||||
<el-option label="供货合同" value="供货合同" />
|
||||
<el-option label="租赁合同" value="租赁合同" />
|
||||
<el-option label="服务合同" value="服务合同" />
|
||||
</el-select>
|
||||
|
||||
<div v-else-if="filteredContracts.length===0" class="empty-container">
|
||||
<el-empty description="暂无合同数据" />
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="list-header">
|
||||
<span class="total-count">共找到{{ filteredContracts.length }}条合同</span>
|
||||
</div>
|
||||
|
||||
<div class="contract-cards">
|
||||
<el-card
|
||||
v-for="contract in filteredContracts"
|
||||
:key="contract.id"
|
||||
class="contract-card"
|
||||
shadow="hover"
|
||||
@click="viewDetail"
|
||||
>
|
||||
<div class="contract-info">
|
||||
<div class="contract-no">
|
||||
<el-tag size="small" type="primary">编号</el-tag>
|
||||
<span class="no-value">{{ contract.contractNo }}</span>
|
||||
</div>
|
||||
<div class="contract-name">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span class="name-value">{{ contract.contractName }}</span>
|
||||
</div>
|
||||
<div class="contract-date">
|
||||
<el-icon><Calendar /></el-icon>
|
||||
<span class="date-value">{{ formatDate(contract.signDate) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增客户表单 -->
|
||||
<div v-if="showAddForm" class="customer-info-label">
|
||||
<el-form :model="form" label-width="auto" style="max-width: 600px" label-position="top">
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="form.phone" :controls="false" :min="0" :max="99999999999" :precision="0"
|
||||
placeholder="请输入11位手机号" style="width: 100%" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="地区">
|
||||
<el-cascader v-model="form.region" :options="regionData" :props="{ expandTrigger: 'hover' }"
|
||||
placeholder="请选择省/市/区" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="详细地址">
|
||||
<el-input v-model="form.address" placeholder=" 请输入详细地址" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="电子邮箱">
|
||||
<el-input v-model="form.email" placeholder=" 请输入邮箱地址" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="代理商类型">
|
||||
<el-radio-group v-model="form.customer_type">
|
||||
<el-radio value="VIP">地区总代理</el-radio>
|
||||
<el-radio value="Normal">普通代理</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="saveCustomer">保存</el-button>
|
||||
<el-button type="danger" @click="cancelAdd">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
style="margin-left: 10px;"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 合同列表 -->
|
||||
<div v-if="showSearchResults" class="contract-list">
|
||||
<div v-if="loading" class="loading-container">
|
||||
<el-skeleton :rows="5" animated />
|
||||
</div>
|
||||
|
||||
<div v-else-if="searchResults.length === 0" class="empty-container">
|
||||
<el-empty description="暂无合同数据" />
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="list-header">
|
||||
<span class="total-count">共找到 {{ searchResults.length }} 条合同</span>
|
||||
</div>
|
||||
|
||||
<el-table :data="searchResults" border style="width: 100%">
|
||||
<el-table-column prop="id" label="ID" width="60" />
|
||||
<el-table-column prop="contract_no" label="合同编号" width="130" />
|
||||
<el-table-column prop="contract_name" label="合同名称" min-width="180" />
|
||||
<el-table-column prop="type" label="合同类型" width="110" />
|
||||
<el-table-column prop="party_b" label="乙方" width="100" />
|
||||
<el-table-column prop="amount" label="金额" width="110">
|
||||
<template #default="{ row }">
|
||||
¥{{ row.amount?.toLocaleString() }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status)">{{ row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sign_date" label="签订日期" width="110" />
|
||||
<el-table-column label="操作" width="140" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="editContract(row)">编辑</el-button>
|
||||
<el-button link type="danger" @click="deleteContract(row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑表单 -->
|
||||
<div v-if="showAddForm" class="contract-form" style="margin-top: 20px;">
|
||||
<el-divider content-position="left">{{ isEditMode ? '编辑合同' : '新增合同' }}</el-divider>
|
||||
<el-form :model="form" label-width="auto" style="max-width: 700px;" label-position="top">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合同编号">
|
||||
<el-input v-model="form.contract_no" placeholder="如: HT-001" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合同类型">
|
||||
<el-select v-model="form.type" placeholder="请选择" style="width: 100%;">
|
||||
<el-option label="加盟合同" value="加盟合同" />
|
||||
<el-option label="供货合同" value="供货合同" />
|
||||
<el-option label="租赁合同" value="租赁合同" />
|
||||
<el-option label="服务合同" value="服务合同" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="合同名称">
|
||||
<el-input v-model="form.contract_name" placeholder="请输入合同名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="甲方">
|
||||
<el-input v-model="form.party_a" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="乙方">
|
||||
<el-input v-model="form.party_b" placeholder="请输入乙方名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="签订日期">
|
||||
<el-date-picker v-model="form.sign_date" type="date" style="width: 100%;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="生效日期">
|
||||
<el-date-picker v-model="form.start_date" type="date" style="width: 100%;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="到期日期">
|
||||
<el-date-picker v-model="form.end_date" type="date" style="width: 100%;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合同金额">
|
||||
<el-input-number v-model="form.amount" :min="0" :step="1000" style="width: 100%;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="form.status" style="width: 100%;">
|
||||
<el-option label="待审批" value="待审批" />
|
||||
<el-option label="生效中" value="生效中" />
|
||||
<el-option label="已到期" value="已到期" />
|
||||
<el-option label="已终止" value="已终止" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="saveContract">保存</el-button>
|
||||
<el-button @click="cancelAdd">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contract-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.contract-search {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.search-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.list-header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.total-count {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.loading-container, .empty-container {
|
||||
padding: 40px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,63 +1,153 @@
|
||||
<script setup>
|
||||
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ref,reactive } from 'vue'
|
||||
import { regionData } from 'element-china-area-data'
|
||||
import { ref, onMounted, reactive } from 'vue'
|
||||
import { regionData, CodeToText, TextToCode } from 'element-china-area-data'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
getCustomerList,
|
||||
createCustomer,
|
||||
updateCustomer,
|
||||
deleteCustomerAPI
|
||||
} from '../api/customer'
|
||||
|
||||
const form = reactive({
|
||||
name: '', // 姓名,默认为空字符串
|
||||
phone: '', // 电话,默认为空字符串
|
||||
region: [], // 地区,默认为空数组(省市区三级代码)
|
||||
address: '', // 详细地址,默认为空字符串
|
||||
email: '', // 电子邮箱,默认为空字符串
|
||||
customer_type: 'Normal' // 客户类型,默认选中"普通客户"
|
||||
id: '',
|
||||
name: '', // 姓名,默认为空字符串
|
||||
phone: '', // 电话,默认为空字符串
|
||||
region: [], // 地区,默认为空数组(省市区三级代码)
|
||||
address: '', // 详细地址,默认为空字符串
|
||||
email: '', // 电子邮箱,默认为空字符串
|
||||
customer_type: 'Normal' // 客户类型,默认选中"普通客户"
|
||||
})
|
||||
|
||||
const search = ref('')
|
||||
const select = ref('1')
|
||||
|
||||
const searchResults=ref([])
|
||||
|
||||
const showSearchResults=ref(false) //是否显示搜索结果
|
||||
const showAddForm=ref(false) //是否显示新增表单
|
||||
const searchResults = ref([])
|
||||
const showSearchResults = ref(false) //是否显示搜索结果
|
||||
const showAddForm = ref(false) //是否显示新增表单
|
||||
const isEditMode = ref(false) //是否为编辑模式
|
||||
const currentCustomerId = ref(null) //当前编辑的客户的ID
|
||||
const loading = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
|
||||
//获取用户列表
|
||||
const fetchData = async () => {
|
||||
loading.value = true;
|
||||
const res = await getCustomerList()
|
||||
searchResults.value = res.data
|
||||
showSearchResults.value = true
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
//搜索
|
||||
const handleSearch = async () => {
|
||||
loading.value = true
|
||||
const res = await getCustomerList({ keyword: search.value, searchField: select.value })
|
||||
searchResults.value = res.data
|
||||
showSearchResults.value = true
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 清空表单
|
||||
const resetForm = () => {
|
||||
form.name = ''
|
||||
form.phone = ''
|
||||
form.region = []
|
||||
form.address = ''
|
||||
form.email = ''
|
||||
form.customer_type = 'Normal'
|
||||
isEditMode.value = false
|
||||
currentCustomerId.value = null
|
||||
form.id = ''
|
||||
form.name = ''
|
||||
form.phone = ''
|
||||
form.region = []
|
||||
form.address = ''
|
||||
form.email = ''
|
||||
form.customer_type = 'Normal'
|
||||
isEditMode.value = false
|
||||
currentCustomerId.value = null
|
||||
}
|
||||
|
||||
// 显示新增表单
|
||||
const addCustomer = () => {
|
||||
resetForm()
|
||||
showAddForm.value = true
|
||||
showSearchResults.value = false
|
||||
resetForm()
|
||||
showAddForm.value = true
|
||||
showSearchResults.value = false
|
||||
}
|
||||
|
||||
//编辑
|
||||
const editCustomer = (row) => {
|
||||
isEditMode.value = true
|
||||
currentCustomerId.value = row.id
|
||||
form.name = row.name
|
||||
form.phone = row.phone
|
||||
// 名称转回代码,让级联选择器显示
|
||||
form.region = [
|
||||
TextToCode[row.province]?.code || '',
|
||||
TextToCode[row.province]?.[row.city]?.code || '',
|
||||
TextToCode[row.province]?.[row.city]?.[row.district]?.code || ''
|
||||
]
|
||||
form.address = row.address
|
||||
form.email = row.email
|
||||
form.customer_type = row.customer_type
|
||||
showAddForm.value = true
|
||||
showSearchResults.value = false
|
||||
}
|
||||
|
||||
const saveCustomer = async () => {
|
||||
const formData = {
|
||||
name: form.name,
|
||||
phone: form.phone,
|
||||
province: CodeToText[form.region[0]] || '',
|
||||
city: CodeToText[form.region[1]] || '',
|
||||
district: CodeToText[form.region[2]] || '',
|
||||
address: form.address,
|
||||
email: form.email,
|
||||
customer_type: form.customer_type
|
||||
}
|
||||
if (isEditMode.value) {
|
||||
await updateCustomer(currentCustomerId.value, formData)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createCustomer(formData)
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
|
||||
cancelAdd()
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const deleteCustomer = async (id) => {
|
||||
ElMessageBox.confirm('确定删除该客户吗?', '提示', {
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
await deleteCustomerAPI(id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchData()
|
||||
})
|
||||
}
|
||||
|
||||
// 取消
|
||||
const cancelAdd = () => {
|
||||
resetForm()
|
||||
showAddForm.value = false
|
||||
showSearchResults.value = true
|
||||
}
|
||||
|
||||
// 清空搜索
|
||||
const clearSearch = () => {
|
||||
search.value = ''
|
||||
showSearchResults.value = false
|
||||
showAddForm.value = false
|
||||
search.value = ''
|
||||
showSearchResults.value = false
|
||||
showAddForm.value = false
|
||||
fetchData()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="customer-container">
|
||||
<div class="customer-container">
|
||||
<!-- 搜索栏区域 -->
|
||||
<div class="customer-search">
|
||||
<el-input v-model="search" style="max-width: 600px" placeholder="Please input"
|
||||
class="customer-search-with-select">
|
||||
class="customer-search-with-select" @keyup.enter="handleSearch">
|
||||
<template #prepend>
|
||||
<el-select v-model="select" placeholder="Select" style="width: 115px">
|
||||
<el-option label="姓名" value="1" />
|
||||
@@ -67,44 +157,67 @@ const clearSearch = () => {
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button :icon="Search" />
|
||||
<el-button :icon="Search" @click="handleSearch" />
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-button color="#E60012" :dark="isDark" @click="addCustomer" style="margin-left: 20px">
|
||||
<el-button type="default" @click="clearSearch" style="margin-left:20px">
|
||||
重置
|
||||
</el-button>
|
||||
<el-button color="#E60012" @click="addCustomer" style="margin-left: 20px">
|
||||
新增用户
|
||||
</el-button>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="showSearchResults" class="customer-table">
|
||||
<el-table :data="searchResults" border style="width: 100%">
|
||||
<el-table-column prop="name" label="姓名" width="120" />
|
||||
<el-table-column prop="phone" label="电话" width="150" />
|
||||
<el-table-column prop="regionText" label="地区" width="200" />
|
||||
<el-table-column prop="address" label="详细地址" width="200" />
|
||||
<el-table-column prop="email" label="电子邮箱" width="200" />
|
||||
<el-table-column prop="customer_type" label="代理商类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.customer_type === 'VIP' ? 'danger' : 'info'">
|
||||
{{ row.customer_type === 'VIP' ? '地区总代理' : '普通代理' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="editCustomer(row)">编辑</el-button>
|
||||
<el-button link type="danger" @click="deleteCustomer(row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top: 10px; color: #909399; font-size: 14px;">
|
||||
找到 {{ searchResults.length }} 条结果
|
||||
<el-button link type="primary" @click="clearSearch">清空搜索</el-button>
|
||||
<div v-if="showSearchResults" class="customer-list">
|
||||
<div v-if="loading" class="loading-container">
|
||||
<el-skeleton :rows="5" animated />
|
||||
</div>
|
||||
|
||||
<div v-else-if="searchResults.length === 0" class="empty-container">
|
||||
<el-empty description="暂无客户数据" />
|
||||
</div>
|
||||
|
||||
|
||||
<div v-else class="customer-table">
|
||||
<el-table :data="searchResults" v-loading="loading" border style="width: 100%">
|
||||
<el-table-column prop="id" label="编号" width="80" />
|
||||
<el-table-column prop="name" label="姓名" width="120" />
|
||||
<el-table-column prop="phone" label="电话" width="150" />
|
||||
<el-table-column label="地区" width="200">
|
||||
<template #default="{ row }">
|
||||
{{ [row.province, row.city, row.district].filter(Boolean).join(' ') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="address" label="详细地址" width="200" />
|
||||
<el-table-column prop="email" label="电子邮箱" width="200" />
|
||||
<el-table-column prop="customer_type" label="代理商类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.customer_type === 'VIP' ? 'danger' : 'info'">
|
||||
{{ row.customer_type === 'VIP' ? '地区总代理' : '普通代理' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="editCustomer(row)">编辑</el-button>
|
||||
<el-button link type="danger" @click="deleteCustomer(row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div style="margin-top: 10px; color: #909399; font-size: 14px;">
|
||||
找到 {{ searchResults.length }} 条结果
|
||||
<el-button link type="primary" @click="clearSearch">清空搜索</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 新增客户表单 -->
|
||||
<div v-if="showAddForm" class="customer-info-label">
|
||||
<el-divider content-position="left">{{ isEditMode ? '编辑客户信息' : '新增客户' }}</el-divider>
|
||||
<el-form :model="form" label-width="auto" style="max-width: 600px" label-position="top">
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
@@ -144,6 +257,4 @@ const clearSearch = () => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user