修正了更多功能
This commit is contained in:
29
db.js
29
db.js
@@ -59,9 +59,9 @@ async function initDB() {
|
|||||||
city VARCHAR(50) DEFAULT NULL COMMENT '市',
|
city VARCHAR(50) DEFAULT NULL COMMENT '市',
|
||||||
district VARCHAR(50) DEFAULT NULL COMMENT '区',
|
district VARCHAR(50) DEFAULT NULL COMMENT '区',
|
||||||
address VARCHAR(200) DEFAULT NULL COMMENT '详细地址',
|
address VARCHAR(200) DEFAULT NULL COMMENT '详细地址',
|
||||||
customer_type VARCHAR(20) DEFAULT 'Normal' COMMENT '客户类型: VIP-地区总代理, Normal-普通代理',
|
|
||||||
email VARCHAR(100) DEFAULT NULL COMMENT '电子邮箱',
|
email VARCHAR(100) DEFAULT NULL COMMENT '电子邮箱',
|
||||||
remark TEXT DEFAULT NULL COMMENT '备注信息',
|
remark TEXT DEFAULT NULL COMMENT '备注信息',
|
||||||
|
responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID (用于数据范围隔离)',
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
@@ -69,8 +69,6 @@ async function initDB() {
|
|||||||
KEY idx_customers_phone (phone)
|
KEY idx_customers_phone (phone)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='加盟商信息表'
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='加盟商信息表'
|
||||||
`)
|
`)
|
||||||
// 确保 customer_type 列存在(兼容旧表)
|
|
||||||
try { await pool.query(`ALTER TABLE customers ADD COLUMN customer_type VARCHAR(20) DEFAULT 'Normal' COMMENT '客户类型: VIP-地区总代理, Normal-普通代理' AFTER address`) } catch {}
|
|
||||||
await pool.query(`
|
await pool.query(`
|
||||||
CREATE TABLE IF NOT EXISTS employees (
|
CREATE TABLE IF NOT EXISTS employees (
|
||||||
id INT NOT NULL AUTO_INCREMENT COMMENT '员工ID (主键)',
|
id INT NOT NULL AUTO_INCREMENT COMMENT '员工ID (主键)',
|
||||||
@@ -125,6 +123,8 @@ async function initDB() {
|
|||||||
employee_id INT DEFAULT NULL COMMENT '业务员ID (关联员工表)',
|
employee_id INT DEFAULT NULL COMMENT '业务员ID (关联员工表)',
|
||||||
status VARCHAR(20) NOT NULL DEFAULT '生效' COMMENT '合同状态: 草稿/生效/完成/作废',
|
status VARCHAR(20) NOT NULL DEFAULT '生效' COMMENT '合同状态: 草稿/生效/完成/作废',
|
||||||
remark TEXT DEFAULT NULL COMMENT '备注',
|
remark TEXT DEFAULT NULL COMMENT '备注',
|
||||||
|
type VARCHAR(20) NOT NULL DEFAULT 'franchise' COMMENT '合同类型: franchise-加盟合同, supply-采购合同',
|
||||||
|
responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID (用于数据范围隔离)',
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
@@ -143,6 +143,7 @@ async function initDB() {
|
|||||||
handle_status VARCHAR(20) NOT NULL DEFAULT '待处理' COMMENT '处理状态: 待处理/处理中/已完成',
|
handle_status VARCHAR(20) NOT NULL DEFAULT '待处理' COMMENT '处理状态: 待处理/处理中/已完成',
|
||||||
service_date DATE DEFAULT NULL COMMENT '售后日期',
|
service_date DATE DEFAULT NULL COMMENT '售后日期',
|
||||||
remark TEXT DEFAULT NULL COMMENT '备注',
|
remark TEXT DEFAULT NULL COMMENT '备注',
|
||||||
|
responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID (用于数据范围隔离)',
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
@@ -203,27 +204,7 @@ async function initDB() {
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商信息表'
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商信息表'
|
||||||
`)
|
`)
|
||||||
|
|
||||||
// ============ 2.4 旧表迁移(兼容已有数据库) ============
|
// ============ 2.4 种子数据 ============
|
||||||
// users 表:删除 real_name、role,新增 is_active、role_id、employee_id、department
|
|
||||||
try { await pool.query(`ALTER TABLE users DROP COLUMN real_name`) } catch {}
|
|
||||||
try { await pool.query(`ALTER TABLE users DROP COLUMN role`) } catch {}
|
|
||||||
try { await pool.query(`ALTER TABLE users CHANGE COLUMN status is_active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '账号状态: 0-禁用, 1-启用'`) } catch {}
|
|
||||||
try { await pool.query(`ALTER TABLE users ADD COLUMN role_id INT DEFAULT NULL COMMENT '角色ID' AFTER is_active`) } catch {}
|
|
||||||
try { await pool.query(`ALTER TABLE users ADD COLUMN employee_id INT DEFAULT NULL COMMENT '员工ID' AFTER role_id`) } catch {}
|
|
||||||
try { await pool.query(`ALTER TABLE users ADD COLUMN department VARCHAR(100) DEFAULT NULL COMMENT '所属部门' AFTER employee_id`) } catch {}
|
|
||||||
|
|
||||||
// customers 表:新增 responsible_user_id
|
|
||||||
try { await pool.query(`ALTER TABLE customers ADD COLUMN responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID'`) } catch {}
|
|
||||||
|
|
||||||
// contracts 表:新增 type
|
|
||||||
try { await pool.query(`ALTER TABLE contracts ADD COLUMN type VARCHAR(20) DEFAULT 'franchise' COMMENT '合同类型: franchise-加盟合同, supply-采购合同'`) } catch {}
|
|
||||||
// contracts 表:新增 responsible_user_id(用于数据范围隔离)
|
|
||||||
try { await pool.query(`ALTER TABLE contracts ADD COLUMN responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID'`) } catch {}
|
|
||||||
|
|
||||||
// after_sales 表:新增 responsible_user_id(用于数据范围隔离)
|
|
||||||
try { await pool.query(`ALTER TABLE after_sales ADD COLUMN responsible_user_id INT DEFAULT NULL COMMENT '负责人用户ID'`) } catch {}
|
|
||||||
|
|
||||||
// ============ 2.5 种子数据 ============
|
|
||||||
await seedRolesAndPermissions()
|
await seedRolesAndPermissions()
|
||||||
await seedDefaultUsers()
|
await seedDefaultUsers()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ function pagination(query) {
|
|||||||
async function list(req, res) {
|
async function list(req, res) {
|
||||||
try {
|
try {
|
||||||
const { page, pageSize, offset } = pagination(req.query)
|
const { page, pageSize, offset } = pagination(req.query)
|
||||||
const { name, phone, province, city, customer_type } = req.query
|
const { name, phone, province, city } = req.query
|
||||||
|
|
||||||
let where = 'WHERE 1=1'
|
let where = 'WHERE 1=1'
|
||||||
const params = []
|
const params = []
|
||||||
@@ -45,10 +45,6 @@ async function list(req, res) {
|
|||||||
where += ' AND city = ?'
|
where += ' AND city = ?'
|
||||||
params.push(city)
|
params.push(city)
|
||||||
}
|
}
|
||||||
if (customer_type) {
|
|
||||||
where += ' AND customer_type = ?'
|
|
||||||
params.push(customer_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查总数
|
// 查总数
|
||||||
const [[{ total }]] = await pool.query(
|
const [[{ total }]] = await pool.query(
|
||||||
@@ -109,7 +105,7 @@ async function detail(req, res) {
|
|||||||
async function create(req, res) {
|
async function create(req, res) {
|
||||||
const {
|
const {
|
||||||
name, phone, province, city, district,
|
name, phone, province, city, district,
|
||||||
address, customer_type, email, remark, responsible_user_id,
|
address, email, remark, responsible_user_id,
|
||||||
} = req.body || {}
|
} = req.body || {}
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@@ -121,10 +117,10 @@ async function create(req, res) {
|
|||||||
const ownerId = responsible_user_id || req.user.id
|
const ownerId = responsible_user_id || req.user.id
|
||||||
|
|
||||||
const [result] = await pool.query(
|
const [result] = await pool.query(
|
||||||
`INSERT INTO customers (name, phone, province, city, district, address, customer_type, email, remark, responsible_user_id)
|
`INSERT INTO customers (name, phone, province, city, district, address, email, remark, responsible_user_id)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
[name, phone || null, province || null, city || null, district || null,
|
[name, phone || null, province || null, city || null, district || null,
|
||||||
address || null, customer_type || 'Normal', email || null, remark || null, ownerId]
|
address || null, email || null, remark || null, ownerId]
|
||||||
)
|
)
|
||||||
const [rows] = await pool.query('SELECT * FROM customers WHERE id = ?', [result.insertId])
|
const [rows] = await pool.query('SELECT * FROM customers WHERE id = ?', [result.insertId])
|
||||||
res.json({ code: 0, message: 'ok', data: rows[0] })
|
res.json({ code: 0, message: 'ok', data: rows[0] })
|
||||||
@@ -139,7 +135,7 @@ async function update(req, res) {
|
|||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
const fields = [
|
const fields = [
|
||||||
'name', 'phone', 'province', 'city', 'district',
|
'name', 'phone', 'province', 'city', 'district',
|
||||||
'address', 'customer_type', 'email', 'remark', 'responsible_user_id',
|
'address', 'email', 'remark', 'responsible_user_id',
|
||||||
]
|
]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ async function main() {
|
|||||||
|
|
||||||
r = await req('POST', '/api/customers', {
|
r = await req('POST', '/api/customers', {
|
||||||
name: 'CRUD测试加盟商', phone: '13800007777', province: '河南', city: '郑州',
|
name: 'CRUD测试加盟商', phone: '13800007777', province: '河南', city: '郑州',
|
||||||
customer_type: 'VIP', email: 'test@mixue.com',
|
email: 'test@mixue.com',
|
||||||
}, tokens.admin)
|
}, tokens.admin)
|
||||||
check('admin POST /api/customers (创建)', r, 200)
|
check('admin POST /api/customers (创建)', r, 200)
|
||||||
const custCrudId = r.body?.data?.id
|
const custCrudId = r.body?.data?.id
|
||||||
@@ -478,9 +478,6 @@ async function main() {
|
|||||||
|
|
||||||
r = await req('GET', '/api/customers?name=CRUD', null, tokens.admin)
|
r = await req('GET', '/api/customers?name=CRUD', null, tokens.admin)
|
||||||
check('GET /api/customers?name=CRUD (搜索)', r, 200)
|
check('GET /api/customers?name=CRUD (搜索)', r, 200)
|
||||||
|
|
||||||
r = await req('GET', '/api/customers?customer_type=VIP', null, tokens.admin)
|
|
||||||
check('GET /api/customers?customer_type=VIP (筛选)', r, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = await req('GET', '/api/customers/99999', null, tokens.admin)
|
r = await req('GET', '/api/customers/99999', null, tokens.admin)
|
||||||
|
|||||||
Reference in New Issue
Block a user