diff --git a/database/db_init.sql b/database/db_init.sql index 02ad5c9..029af34 100644 --- a/database/db_init.sql +++ b/database/db_init.sql @@ -190,6 +190,7 @@ CREATE INDEX idx_oplog_time ON sys_operation_log (created_at); DROP TABLE IF EXISTS customer CASCADE; CREATE TABLE customer ( id BIGSERIAL PRIMARY KEY, + customer_no VARCHAR(64) NOT NULL UNIQUE, customer_name VARCHAR(128) NOT NULL, province VARCHAR(64), city VARCHAR(64), @@ -201,11 +202,13 @@ CREATE TABLE customer ( fax VARCHAR(20), customer_level VARCHAR(32), status SMALLINT NOT NULL DEFAULT 1, + salesman_id BIGINT REFERENCES sys_user(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); COMMENT ON TABLE customer IS '客户信息表'; COMMENT ON COLUMN customer.id IS '自增主键'; +COMMENT ON COLUMN customer.customer_no IS '客户业务编号(KH+YYYYMMDD+3位序号)'; COMMENT ON COLUMN customer.customer_name IS '客户名称'; COMMENT ON COLUMN customer.province IS '省'; COMMENT ON COLUMN customer.city IS '市'; @@ -217,10 +220,13 @@ COMMENT ON COLUMN customer.postal_code IS '邮编'; COMMENT ON COLUMN customer.fax IS '传真'; COMMENT ON COLUMN customer.customer_level IS '客户级别(学校/医院等)'; COMMENT ON COLUMN customer.status IS '状态:1意向 2签约 3运维中 4终止'; +COMMENT ON COLUMN customer.salesman_id IS '负责业务员(→ sys_user.id)'; COMMENT ON COLUMN customer.created_at IS '创建时间'; COMMENT ON COLUMN customer.updated_at IS '更新时间'; -CREATE INDEX idx_customer_name ON customer (customer_name); -CREATE INDEX idx_customer_region ON customer (province, city, district); +CREATE INDEX idx_customer_name ON customer (customer_name); +CREATE INDEX idx_customer_salesman ON customer (salesman_id); +CREATE INDEX idx_customer_status ON customer (status); +CREATE INDEX idx_customer_region ON customer (province, city, district); CREATE TRIGGER trg_customer_updated_at BEFORE UPDATE ON customer FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at(); @@ -233,7 +239,8 @@ CREATE TABLE customer_department ( contact_person VARCHAR(64), contact_phone VARCHAR(20), function_desc TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); COMMENT ON TABLE customer_department IS '客户部门信息表'; COMMENT ON COLUMN customer_department.id IS '自增主键'; @@ -243,7 +250,10 @@ COMMENT ON COLUMN customer_department.contact_person IS '联系人'; COMMENT ON COLUMN customer_department.contact_phone IS '电话'; COMMENT ON COLUMN customer_department.function_desc IS '职能'; COMMENT ON COLUMN customer_department.created_at IS '创建时间'; -CREATE INDEX idx_cust_dept_customer ON customer_department (customer_id); +COMMENT ON COLUMN customer_department.updated_at IS '更新时间'; +CREATE INDEX idx_dept_customer ON customer_department (customer_id); +CREATE TRIGGER trg_customer_department_updated_at BEFORE UPDATE ON customer_department + FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at(); -- 10. 客户拜访信息表 DROP TABLE IF EXISTS customer_visit CASCADE; @@ -362,7 +372,8 @@ CREATE TABLE customer_account ( wx_openid VARCHAR(128), status SMALLINT NOT NULL DEFAULT 1, last_login_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); COMMENT ON TABLE customer_account IS '客户访问账号表(小程序登录)'; COMMENT ON COLUMN customer_account.id IS '自增主键'; @@ -373,7 +384,11 @@ COMMENT ON COLUMN customer_account.wx_openid IS '微信 openid'; COMMENT ON COLUMN customer_account.status IS '状态:1启用 0禁用'; COMMENT ON COLUMN customer_account.last_login_at IS '最后登录时间'; COMMENT ON COLUMN customer_account.created_at IS '创建时间'; -CREATE UNIQUE INDEX idx_cust_account_phone ON customer_account (phone); +COMMENT ON COLUMN customer_account.updated_at IS '更新时间'; +CREATE INDEX idx_account_customer ON customer_account (customer_id); +CREATE UNIQUE INDEX uk_account_phone ON customer_account (phone); +CREATE TRIGGER trg_customer_account_updated_at BEFORE UPDATE ON customer_account + FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at(); -- ============================================================ -- 三、智电设备域(1 张表) diff --git a/database/migrations/20260823_customer_module.sql b/database/migrations/20260823_customer_module.sql new file mode 100644 index 0000000..1ad7ab5 --- /dev/null +++ b/database/migrations/20260823_customer_module.sql @@ -0,0 +1,227 @@ +-- ============================================================ +-- 增量更新脚本:客户管理模块结构补全 +-- 日期:2026-08-23 +-- 数据库:PostgreSQL 15+ (xintong) +-- 说明:客户管理核心模块(客户信息/客户部门/客户访问账号)表结构 +-- 与 Sequelize Entity 定义对齐,补齐缺失列、索引及 updated_at 触发器。 +-- 脚本幂等,可重复执行。 +-- +-- 更新内容: +-- 1. customer 表 +-- - 新增列 customer_no VARCHAR(64) NOT NULL UNIQUE(客户业务编号) +-- - 新增列 salesman_id BIGINT REFERENCES sys_user(id)(负责业务员) +-- - 新增索引 idx_customer_salesman (salesman_id) +-- - 新增索引 idx_customer_status (status) +-- 2. customer_department 表 +-- - 新增列 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +-- - 新增触发器 trg_customer_department_updated_at +-- - 重命名索引 idx_cust_dept_customer → idx_dept_customer(若新索引已存在则删除旧索引) +-- 3. customer_account 表 +-- - 新增列 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +-- - 新增触发器 trg_customer_account_updated_at +-- - 新增索引 idx_account_customer (customer_id) +-- - 重命名唯一索引 idx_cust_account_phone → uk_account_phone +-- +-- 用法: +-- psql -U postgres -d xintong -f 20260823_customer_module.sql +-- ============================================================ + +BEGIN; + +-- ============================================================ +-- 1. customer 表:补 customer_no、salesman_id 列及索引 +-- ============================================================ + +-- 1.1 新增 customer_no 列(客户业务编号 KH+YYYYMMDD+3位序号) +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'customer' AND column_name = 'customer_no' + ) THEN + ALTER TABLE customer ADD COLUMN customer_no VARCHAR(64) NOT NULL; + ALTER TABLE customer ADD CONSTRAINT uk_customer_no UNIQUE (customer_no); + COMMENT ON COLUMN customer.customer_no IS '客户业务编号(KH+YYYYMMDD+3位序号)'; + RAISE NOTICE 'customer: 已新增列 customer_no'; + ELSE + RAISE NOTICE 'customer: 列 customer_no 已存在,跳过'; + END IF; +END $$; + +-- 1.2 新增 salesman_id 列(负责业务员,关联 sys_user.id) +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'customer' AND column_name = 'salesman_id' + ) THEN + ALTER TABLE customer ADD COLUMN salesman_id BIGINT REFERENCES sys_user(id); + COMMENT ON COLUMN customer.salesman_id IS '负责业务员(→ sys_user.id)'; + RAISE NOTICE 'customer: 已新增列 salesman_id'; + ELSE + RAISE NOTICE 'customer: 列 salesman_id 已存在,跳过'; + END IF; +END $$; + +-- 1.3 新增索引 idx_customer_salesman +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer' AND indexname = 'idx_customer_salesman' + ) THEN + CREATE INDEX idx_customer_salesman ON customer (salesman_id); + RAISE NOTICE 'customer: 已创建索引 idx_customer_salesman'; + ELSE + RAISE NOTICE 'customer: 索引 idx_customer_salesman 已存在,跳过'; + END IF; +END $$; + +-- 1.4 新增索引 idx_customer_status +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer' AND indexname = 'idx_customer_status' + ) THEN + CREATE INDEX idx_customer_status ON customer (status); + RAISE NOTICE 'customer: 已创建索引 idx_customer_status'; + ELSE + RAISE NOTICE 'customer: 索引 idx_customer_status 已存在,跳过'; + END IF; +END $$; + +-- ============================================================ +-- 2. customer_department 表:补 updated_at 列、触发器,重命名索引 +-- ============================================================ + +-- 2.1 新增 updated_at 列 +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'customer_department' AND column_name = 'updated_at' + ) THEN + ALTER TABLE customer_department + ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + COMMENT ON COLUMN customer_department.updated_at IS '更新时间'; + RAISE NOTICE 'customer_department: 已新增列 updated_at'; + ELSE + RAISE NOTICE 'customer_department: 列 updated_at 已存在,跳过'; + END IF; +END $$; + +-- 2.2 新增 updated_at 触发器 +DROP TRIGGER IF EXISTS trg_customer_department_updated_at ON customer_department; +CREATE TRIGGER trg_customer_department_updated_at BEFORE UPDATE ON customer_department + FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at(); + +-- 2.3 重命名索引 idx_cust_dept_customer → idx_dept_customer +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_department' AND indexname = 'idx_cust_dept_customer' + ) AND NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_department' AND indexname = 'idx_dept_customer' + ) THEN + ALTER INDEX idx_cust_dept_customer RENAME TO idx_dept_customer; + RAISE NOTICE 'customer_department: 已重命名索引 idx_cust_dept_customer → idx_dept_customer'; + ELSE + RAISE NOTICE 'customer_department: 索引重命名已跳过(源不存在或目标已存在)'; + END IF; +END $$; + +-- 2.4 删除可能残留的旧索引 idx_cust_dept_customer(新旧并存时清理冗余) +DROP INDEX IF EXISTS idx_cust_dept_customer; + +-- 2.5 兜底:确保 idx_dept_customer 存在 +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_department' AND indexname = 'idx_dept_customer' + ) THEN + CREATE INDEX idx_dept_customer ON customer_department (customer_id); + RAISE NOTICE 'customer_department: 已创建索引 idx_dept_customer'; + ELSE + RAISE NOTICE 'customer_department: 索引 idx_dept_customer 已存在,跳过'; + END IF; +END $$; + +-- ============================================================ +-- 3. customer_account 表:补 updated_at 列、触发器,新增/重命名索引 +-- ============================================================ + +-- 3.1 新增 updated_at 列 +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'customer_account' AND column_name = 'updated_at' + ) THEN + ALTER TABLE customer_account + ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + COMMENT ON COLUMN customer_account.updated_at IS '更新时间'; + RAISE NOTICE 'customer_account: 已新增列 updated_at'; + ELSE + RAISE NOTICE 'customer_account: 列 updated_at 已存在,跳过'; + END IF; +END $$; + +-- 3.2 新增 updated_at 触发器 +DROP TRIGGER IF EXISTS trg_customer_account_updated_at ON customer_account; +CREATE TRIGGER trg_customer_account_updated_at BEFORE UPDATE ON customer_account + FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at(); + +-- 3.3 新增 customer_id 普通索引 idx_account_customer +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_account' AND indexname = 'idx_account_customer' + ) THEN + CREATE INDEX idx_account_customer ON customer_account (customer_id); + RAISE NOTICE 'customer_account: 已创建索引 idx_account_customer'; + ELSE + RAISE NOTICE 'customer_account: 索引 idx_account_customer 已存在,跳过'; + END IF; +END $$; + +-- 3.4 重命名唯一索引 idx_cust_account_phone → uk_account_phone +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_account' AND indexname = 'idx_cust_account_phone' + ) AND NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_account' AND indexname = 'uk_account_phone' + ) THEN + ALTER INDEX idx_cust_account_phone RENAME TO uk_account_phone; + RAISE NOTICE 'customer_account: 已重命名索引 idx_cust_account_phone → uk_account_phone'; + ELSE + RAISE NOTICE 'customer_account: 索引重命名已跳过(源不存在或目标已存在)'; + END IF; +END $$; + +-- 3.5 兜底:确保 uk_account_phone 存在 +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_indexes WHERE tablename = 'customer_account' AND indexname = 'uk_account_phone' + ) THEN + CREATE UNIQUE INDEX uk_account_phone ON customer_account (phone); + RAISE NOTICE 'customer_account: 已创建唯一索引 uk_account_phone'; + ELSE + RAISE NOTICE 'customer_account: 索引 uk_account_phone 已存在,跳过'; + END IF; +END $$; + +COMMIT; + +-- ============================================================ +-- 验证查询(可选,不报错即表示结构正确) +-- ============================================================ +SELECT 'customer' AS tbl, column_name FROM information_schema.columns + WHERE table_name = 'customer' AND column_name IN ('customer_no', 'salesman_id') +UNION ALL +SELECT 'customer_department', column_name FROM information_schema.columns + WHERE table_name = 'customer_department' AND column_name = 'updated_at' +UNION ALL +SELECT 'customer_account', column_name FROM information_schema.columns + WHERE table_name = 'customer_account' AND column_name = 'updated_at' +ORDER BY tbl, column_name;