2026-03-27 09:05:41 +00:00
-- PostgreSQL 17 full initialization script for public schema
2026-03-20 08:39:07 +00:00
-- Usage:
2026-03-27 09:05:41 +00:00
-- psql -d your_database -f sql/init_full_pg17.sql
--
-- Structure:
-- 1) base schema objects
-- 2) indexes / triggers / comments
-- 3) compatibility absorption for old environments
--
-- Notes:
-- - This is the current canonical initialization entry.
-- - Historical incremental scripts are archived under sql/archive/.
2026-03-20 08:39:07 +00:00
begin ;
set search_path to public ;
2026-03-27 09:05:41 +00:00
-- =====================================================================
-- Section 1. Utilities
-- =====================================================================
2026-03-20 08:39:07 +00:00
-- Unified trigger function for updated_at maintenance.
create or replace function set_updated_at ( )
returns trigger
language plpgsql
as $ $
begin
new . updated_at = now ( ) ;
return new ;
end ;
$ $ ;
create or replace function create_trigger_if_not_exists ( trigger_name text , table_name text )
returns void
language plpgsql
as $ $
begin
if not exists (
select 1
from pg_trigger t
join pg_class c on c . oid = t . tgrelid
join pg_namespace n on n . oid = c . relnamespace
where t . tgname = trigger_name
and c . relname = table_name
and n . nspname = current_schema ( )
) then
execute format (
' create trigger %I before update on %I for each row execute function set_updated_at() ' ,
trigger_name ,
table_name
) ;
end if ;
end ;
$ $ ;
2026-04-01 09:24:06 +00:00
create or replace function comment_on_column_if_exists ( p_table_name text , p_column_name text , p_comment_text text )
returns void
language plpgsql
as $ $
begin
if exists (
select 1
from information_schema . columns c
where c . table_schema = current_schema ( )
and c . table_name = p_table_name
and c . column_name = p_column_name
) then
execute format (
' comment on column %I.%I is %L ' ,
p_table_name ,
p_column_name ,
p_comment_text
) ;
end if ;
end ;
$ $ ;
2026-03-27 09:05:41 +00:00
-- =====================================================================
-- Section 2. Base tables
-- =====================================================================
2026-03-20 08:39:07 +00:00
create table if not exists sys_user (
id bigint generated by default as identity primary key ,
user_code varchar ( 50 ) ,
username varchar ( 50 ) not null ,
real_name varchar ( 50 ) not null ,
mobile varchar ( 20 ) ,
email varchar ( 100 ) ,
2026-03-23 07:21:09 +00:00
org_id bigint ,
2026-03-20 08:39:07 +00:00
job_title varchar ( 100 ) ,
status smallint not null default 1 ,
hire_date date ,
avatar_url varchar ( 255 ) ,
password_hash varchar ( 255 ) ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint uk_sys_user_username unique ( username ) ,
2026-03-23 07:21:09 +00:00
constraint uk_sys_user_mobile unique ( mobile )
2026-03-20 08:39:07 +00:00
) ;
create table if not exists crm_customer (
id bigint generated by default as identity primary key ,
customer_code varchar ( 50 ) ,
customer_name varchar ( 200 ) not null ,
customer_type varchar ( 50 ) ,
industry varchar ( 50 ) ,
province varchar ( 50 ) ,
city varchar ( 50 ) ,
address varchar ( 255 ) ,
owner_user_id bigint ,
source varchar ( 50 ) ,
status varchar ( 30 ) not null default ' potential '
check ( status in ( ' potential ' , ' following ' , ' won ' , ' lost ' ) ) ,
remark text ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint uk_crm_customer_code unique ( customer_code )
) ;
create table if not exists crm_opportunity (
id bigint generated by default as identity primary key ,
opportunity_code varchar ( 50 ) not null ,
opportunity_name varchar ( 200 ) not null ,
customer_id bigint not null ,
owner_user_id bigint not null ,
2026-03-26 09:29:55 +00:00
sales_expansion_id bigint ,
channel_expansion_id bigint ,
2026-04-01 09:24:06 +00:00
pre_sales_id bigint ,
pre_sales_name varchar ( 100 ) ,
2026-03-26 09:29:55 +00:00
project_location varchar ( 100 ) ,
operator_name varchar ( 100 ) ,
2026-03-20 08:39:07 +00:00
amount numeric ( 18 , 2 ) not null default 0 ,
expected_close_date date ,
2026-04-01 09:24:06 +00:00
confidence_pct varchar ( 1 ) not null default ' C ' check ( confidence_pct in ( ' A ' , ' B ' , ' C ' ) ) ,
2026-03-26 09:29:55 +00:00
stage varchar ( 50 ) not null default ' initial_contact ' ,
2026-03-20 08:39:07 +00:00
opportunity_type varchar ( 50 ) ,
product_type varchar ( 100 ) ,
source varchar ( 50 ) ,
2026-03-26 09:29:55 +00:00
competitor_name varchar ( 200 ) ,
2026-03-27 09:05:41 +00:00
archived boolean not null default false ,
2026-03-20 08:39:07 +00:00
pushed_to_oms boolean not null default false ,
oms_push_time timestamptz ,
description text ,
status varchar ( 30 ) not null default ' active '
check ( status in ( ' active ' , ' won ' , ' lost ' , ' closed ' ) ) ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint uk_crm_opportunity_code unique ( opportunity_code ) ,
constraint fk_crm_opportunity_customer foreign key ( customer_id ) references crm_customer ( id )
) ;
create table if not exists crm_opportunity_followup (
id bigint generated by default as identity primary key ,
opportunity_id bigint not null ,
followup_time timestamptz not null ,
followup_type varchar ( 50 ) not null ,
content text not null ,
next_action varchar ( 255 ) ,
followup_user_id bigint not null ,
2026-03-26 09:29:55 +00:00
source_type varchar ( 30 ) ,
source_id bigint ,
2026-03-20 08:39:07 +00:00
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint fk_crm_opportunity_followup_opportunity
foreign key ( opportunity_id ) references crm_opportunity ( id ) on delete cascade
) ;
create table if not exists crm_sales_expansion (
id bigint generated by default as identity primary key ,
2026-03-26 09:29:55 +00:00
employee_no varchar ( 50 ) not null ,
2026-03-20 08:39:07 +00:00
candidate_name varchar ( 50 ) not null ,
2026-03-26 09:29:55 +00:00
office_name varchar ( 100 ) ,
2026-03-20 08:39:07 +00:00
mobile varchar ( 20 ) ,
email varchar ( 100 ) ,
2026-03-26 09:29:55 +00:00
target_dept varchar ( 100 ) ,
2026-03-20 08:39:07 +00:00
industry varchar ( 50 ) ,
title varchar ( 100 ) ,
intent_level varchar ( 20 ) not null default ' medium '
check ( intent_level in ( ' high ' , ' medium ' , ' low ' ) ) ,
stage varchar ( 50 ) not null default ' initial_contact ' ,
has_desktop_exp boolean not null default false ,
in_progress boolean not null default true ,
employment_status varchar ( 20 ) not null default ' active '
check ( employment_status in ( ' active ' , ' left ' , ' joined ' , ' abandoned ' ) ) ,
expected_join_date date ,
owner_user_id bigint not null ,
remark text ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( )
) ;
create table if not exists crm_channel_expansion (
id bigint generated by default as identity primary key ,
2026-03-26 09:29:55 +00:00
channel_code varchar ( 50 ) ,
2026-03-20 08:39:07 +00:00
province varchar ( 50 ) ,
2026-04-01 09:24:06 +00:00
city varchar ( 50 ) ,
2026-03-26 09:29:55 +00:00
channel_name varchar ( 200 ) not null ,
office_address varchar ( 255 ) ,
channel_industry varchar ( 100 ) ,
2026-04-01 09:24:06 +00:00
certification_level varchar ( 100 ) ,
2026-03-20 08:39:07 +00:00
annual_revenue numeric ( 18 , 2 ) ,
staff_size integer check ( staff_size is null or staff_size > = 0 ) ,
2026-03-26 09:29:55 +00:00
contact_established_date date ,
intent_level varchar ( 20 ) not null default ' medium '
check ( intent_level in ( ' high ' , ' medium ' , ' low ' ) ) ,
has_desktop_exp boolean not null default false ,
2026-03-20 08:39:07 +00:00
contact_name varchar ( 50 ) ,
contact_title varchar ( 100 ) ,
contact_mobile varchar ( 20 ) ,
2026-03-26 09:29:55 +00:00
channel_attribute varchar ( 100 ) ,
internal_attribute varchar ( 100 ) ,
2026-03-20 08:39:07 +00:00
stage varchar ( 50 ) not null default ' initial_contact ' ,
landed_flag boolean not null default false ,
expected_sign_date date ,
owner_user_id bigint not null ,
remark text ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( )
) ;
2026-03-26 09:29:55 +00:00
create table if not exists crm_channel_expansion_contact (
id bigint generated by default as identity primary key ,
channel_expansion_id bigint not null ,
contact_name varchar ( 50 ) ,
contact_mobile varchar ( 20 ) ,
contact_title varchar ( 100 ) ,
sort_order integer not null default 1 ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint fk_crm_channel_expansion_contact_channel
foreign key ( channel_expansion_id ) references crm_channel_expansion ( id ) on delete cascade
) ;
2026-03-20 08:39:07 +00:00
create table if not exists crm_expansion_followup (
id bigint generated by default as identity primary key ,
biz_type varchar ( 20 ) not null check ( biz_type in ( ' sales ' , ' channel ' ) ) ,
biz_id bigint not null ,
followup_time timestamptz not null ,
followup_type varchar ( 50 ) not null ,
content text not null ,
next_action varchar ( 255 ) ,
followup_user_id bigint not null ,
2026-03-26 09:29:55 +00:00
visit_start_time timestamptz ,
evaluation_content text ,
next_plan text ,
source_type varchar ( 30 ) ,
source_id bigint ,
2026-03-20 08:39:07 +00:00
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( )
) ;
create table if not exists work_checkin (
id bigint generated by default as identity primary key ,
user_id bigint not null ,
checkin_date date not null ,
checkin_time timestamptz not null ,
2026-03-26 09:29:55 +00:00
biz_type varchar ( 20 ) check ( biz_type is null or biz_type in ( ' sales ' , ' channel ' , ' opportunity ' ) ) ,
biz_id bigint ,
biz_name varchar ( 200 ) ,
2026-03-20 08:39:07 +00:00
longitude numeric ( 10 , 6 ) ,
latitude numeric ( 10 , 6 ) ,
location_text varchar ( 255 ) not null ,
remark varchar ( 500 ) ,
2026-03-26 09:29:55 +00:00
user_name varchar ( 100 ) ,
dept_name varchar ( 200 ) ,
2026-03-20 08:39:07 +00:00
status varchar ( 30 ) not null default ' normal '
check ( status in ( ' normal ' , ' abnormal ' , ' reissue ' ) ) ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( )
) ;
create table if not exists work_daily_report (
id bigint generated by default as identity primary key ,
user_id bigint not null ,
report_date date not null ,
work_content text ,
tomorrow_plan text ,
source_type varchar ( 30 ) not null default ' manual '
check ( source_type in ( ' manual ' , ' voice ' ) ) ,
submit_time timestamptz ,
status varchar ( 30 ) not null default ' draft '
check ( status in ( ' draft ' , ' submitted ' , ' read ' , ' reviewed ' ) ) ,
score integer check ( score is null or score between 0 and 100 ) ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint uk_work_daily_report_user_date unique ( user_id , report_date )
) ;
create table if not exists work_daily_report_comment (
id bigint generated by default as identity primary key ,
report_id bigint not null ,
reviewer_user_id bigint not null ,
score integer check ( score is null or score between 0 and 100 ) ,
comment_content text ,
reviewed_at timestamptz not null default now ( ) ,
created_at timestamptz not null default now ( ) ,
constraint fk_work_daily_report_comment_report
foreign key ( report_id ) references work_daily_report ( id ) on delete cascade
) ;
create table if not exists work_todo (
id bigint generated by default as identity primary key ,
user_id bigint not null ,
title varchar ( 200 ) not null ,
biz_type varchar ( 30 ) not null default ' other '
check ( biz_type in ( ' opportunity ' , ' expansion ' , ' report ' , ' other ' ) ) ,
biz_id bigint ,
due_date timestamptz ,
status varchar ( 20 ) not null default ' todo '
check ( status in ( ' todo ' , ' done ' , ' canceled ' ) ) ,
priority varchar ( 20 ) not null default ' medium '
check ( priority in ( ' high ' , ' medium ' , ' low ' ) ) ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( )
) ;
create table if not exists sys_activity_log (
id bigint generated by default as identity primary key ,
biz_type varchar ( 30 ) not null ,
biz_id bigint ,
action_type varchar ( 50 ) not null ,
title varchar ( 200 ) not null ,
content varchar ( 500 ) ,
operator_user_id bigint ,
created_at timestamptz not null default now ( )
) ;
2026-03-27 09:05:41 +00:00
-- =====================================================================
-- Section 3. Indexes / triggers / comments
-- =====================================================================
2026-03-26 09:29:55 +00:00
do $ $
begin
if not exists (
select 1
from pg_constraint
where conname = ' fk_crm_opportunity_channel_expansion '
) then
alter table crm_opportunity
add constraint fk_crm_opportunity_channel_expansion
foreign key ( channel_expansion_id ) references crm_channel_expansion ( id ) ;
end if ;
end $ $ ;
2026-03-20 08:39:07 +00:00
create index if not exists idx_crm_customer_owner on crm_customer ( owner_user_id ) ;
create index if not exists idx_crm_customer_name on crm_customer ( customer_name ) ;
2026-03-27 09:05:41 +00:00
do $ $
begin
if exists (
select 1
from information_schema . columns
where table_schema = current_schema ( )
and table_name = ' sys_user '
and column_name = ' org_id '
) then
execute ' create index if not exists idx_sys_user_org_id on sys_user(org_id) ' ;
end if ;
end ;
$ $ ;
2026-03-26 09:29:55 +00:00
create unique index if not exists uk_crm_sales_expansion_owner_employee_no
on crm_sales_expansion ( owner_user_id , employee_no ) ;
2026-03-20 08:39:07 +00:00
create index if not exists idx_crm_opportunity_customer on crm_opportunity ( customer_id ) ;
create index if not exists idx_crm_opportunity_owner on crm_opportunity ( owner_user_id ) ;
2026-03-26 09:29:55 +00:00
create index if not exists idx_crm_opportunity_sales_expansion on crm_opportunity ( sales_expansion_id ) ;
2026-03-20 08:39:07 +00:00
create index if not exists idx_crm_opportunity_stage on crm_opportunity ( stage ) ;
create index if not exists idx_crm_opportunity_expected_close on crm_opportunity ( expected_close_date ) ;
2026-03-27 09:05:41 +00:00
create index if not exists idx_crm_opportunity_archived on crm_opportunity ( archived ) ;
2026-03-20 08:39:07 +00:00
create index if not exists idx_crm_opportunity_followup_opportunity_time
on crm_opportunity_followup ( opportunity_id , followup_time desc ) ;
create index if not exists idx_crm_opportunity_followup_user on crm_opportunity_followup ( followup_user_id ) ;
create index if not exists idx_crm_sales_expansion_owner on crm_sales_expansion ( owner_user_id ) ;
create index if not exists idx_crm_sales_expansion_stage on crm_sales_expansion ( stage ) ;
create index if not exists idx_crm_sales_expansion_mobile on crm_sales_expansion ( mobile ) ;
create index if not exists idx_crm_channel_expansion_owner on crm_channel_expansion ( owner_user_id ) ;
create index if not exists idx_crm_channel_expansion_stage on crm_channel_expansion ( stage ) ;
create index if not exists idx_crm_channel_expansion_name on crm_channel_expansion ( channel_name ) ;
2026-03-26 09:29:55 +00:00
create index if not exists idx_crm_channel_expansion_contact_channel on crm_channel_expansion_contact ( channel_expansion_id ) ;
create index if not exists idx_crm_opportunity_channel_expansion on crm_opportunity ( channel_expansion_id ) ;
2026-03-20 08:39:07 +00:00
create index if not exists idx_crm_expansion_followup_biz_time
on crm_expansion_followup ( biz_type , biz_id , followup_time desc ) ;
create index if not exists idx_crm_expansion_followup_user on crm_expansion_followup ( followup_user_id ) ;
create index if not exists idx_work_checkin_user_date on work_checkin ( user_id , checkin_date desc ) ;
create index if not exists idx_work_daily_report_user_date on work_daily_report ( user_id , report_date desc ) ;
create index if not exists idx_work_daily_report_status on work_daily_report ( status ) ;
create index if not exists idx_work_daily_report_comment_report on work_daily_report_comment ( report_id ) ;
create index if not exists idx_sys_activity_log_created on sys_activity_log ( created_at desc ) ;
create index if not exists idx_sys_activity_log_biz on sys_activity_log ( biz_type , biz_id ) ;
select create_trigger_if_not_exists ( ' trg_sys_user_updated_at ' , ' sys_user ' ) ;
select create_trigger_if_not_exists ( ' trg_crm_customer_updated_at ' , ' crm_customer ' ) ;
select create_trigger_if_not_exists ( ' trg_crm_opportunity_updated_at ' , ' crm_opportunity ' ) ;
select create_trigger_if_not_exists ( ' trg_crm_opportunity_followup_updated_at ' , ' crm_opportunity_followup ' ) ;
select create_trigger_if_not_exists ( ' trg_crm_sales_expansion_updated_at ' , ' crm_sales_expansion ' ) ;
select create_trigger_if_not_exists ( ' trg_crm_channel_expansion_updated_at ' , ' crm_channel_expansion ' ) ;
2026-03-26 09:29:55 +00:00
select create_trigger_if_not_exists ( ' trg_crm_channel_expansion_contact_updated_at ' , ' crm_channel_expansion_contact ' ) ;
2026-03-20 08:39:07 +00:00
select create_trigger_if_not_exists ( ' trg_crm_expansion_followup_updated_at ' , ' crm_expansion_followup ' ) ;
select create_trigger_if_not_exists ( ' trg_work_checkin_updated_at ' , ' work_checkin ' ) ;
select create_trigger_if_not_exists ( ' trg_work_daily_report_updated_at ' , ' work_daily_report ' ) ;
select create_trigger_if_not_exists ( ' trg_work_todo_updated_at ' , ' work_todo ' ) ;
comment on table sys_user is ' 系统用户 ' ;
comment on table crm_customer is ' 客户主表 ' ;
comment on table crm_opportunity is ' 商机主表 ' ;
comment on table crm_opportunity_followup is ' 商机跟进记录 ' ;
comment on table crm_sales_expansion is ' 销售人员拓展 ' ;
comment on table crm_channel_expansion is ' 渠道拓展 ' ;
2026-03-26 09:29:55 +00:00
comment on table crm_channel_expansion_contact is ' 渠道拓展联系人 ' ;
2026-03-20 08:39:07 +00:00
comment on table crm_expansion_followup is ' 拓展跟进记录 ' ;
comment on table work_checkin is ' 外勤打卡 ' ;
comment on table work_daily_report is ' 日报 ' ;
comment on table work_daily_report_comment is ' 日报点评 ' ;
comment on table work_todo is ' 待办事项 ' ;
comment on table sys_activity_log is ' 首页动态日志 ' ;
commit ;
2026-03-27 09:05:41 +00:00
-- =====================================================================
-- Compatibility DDL section
-- Purpose:
-- 1) make this script usable for both fresh installs and old-environment upgrades
-- 2) absorb historical DDL migration scripts into a single deployment entry
-- 3) keep base-framework tables managed by unisbase itself
--
-- Base framework dependencies not created here:
-- sys_org, sys_dict_item, sys_tenant_user, sys_role, sys_user_role ...
-- =====================================================================
begin ;
set search_path to public ;
-- sys_user compatibility: dept_id -> org_id
DO $ $
BEGIN
IF to_regclass ( ' public.sys_user ' ) IS NOT NULL THEN
IF NOT EXISTS (
SELECT 1
FROM information_schema . columns
WHERE table_schema = ' public '
AND table_name = ' sys_user '
AND column_name = ' org_id '
) THEN
ALTER TABLE public . sys_user ADD COLUMN org_id bigint ;
END IF ;
IF EXISTS (
SELECT 1
FROM information_schema . columns
WHERE table_schema = ' public '
AND table_name = ' sys_user '
AND column_name = ' dept_id '
) THEN
EXECUTE ' update public.sys_user set org_id = coalesce(org_id, dept_id) where dept_id is not null ' ;
ALTER TABLE public . sys_user DROP COLUMN dept_id ;
END IF ;
END IF ;
END $ $ ;
DROP INDEX IF EXISTS public . idx_sys_user_dept_id ;
CREATE INDEX IF NOT EXISTS idx_sys_user_org_id ON public . sys_user ( org_id ) ;
-- crm_sales_expansion compatibility: ensure employee_no / office_name / target_dept text
ALTER TABLE IF EXISTS crm_sales_expansion
ADD COLUMN IF NOT EXISTS employee_no varchar ( 50 ) ,
ADD COLUMN IF NOT EXISTS office_name varchar ( 100 ) ,
ADD COLUMN IF NOT EXISTS target_dept varchar ( 100 ) ;
DO $ $
BEGIN
IF to_regclass ( ' public.crm_sales_expansion ' ) IS NOT NULL THEN
IF EXISTS (
SELECT 1
FROM information_schema . columns
WHERE table_schema = ' public '
AND table_name = ' crm_sales_expansion '
AND column_name = ' target_dept_id '
) THEN
UPDATE crm_sales_expansion s
SET target_dept = COALESCE (
NULL IF ( s . target_dept , ' ' ) ,
(
SELECT d . item_label
FROM sys_dict_item d
WHERE d . type_code = ' tz_ssbm '
AND d . item_value = s . target_dept_id : : varchar
AND d . status = 1
AND COALESCE ( d . is_deleted , 0 ) = 0
ORDER BY d . sort_order ASC NULL S LAST , d . dict_item_id ASC
LIMIT 1
) ,
(
SELECT o . org_name
FROM sys_org o
WHERE o . id = s . target_dept_id
LIMIT 1
) ,
s . target_dept_id : : varchar
)
WHERE s . target_dept_id IS NOT NULL ;
ALTER TABLE crm_sales_expansion DROP COLUMN target_dept_id ;
END IF ;
UPDATE crm_sales_expansion
SET employee_no = concat ( ' EMP ' , lpad ( id : : text , 6 , ' 0 ' ) )
WHERE employee_no IS NULL OR btrim ( employee_no ) = ' ' ;
WITH duplicated AS (
SELECT
id ,
row_number ( ) over ( partition by owner_user_id , employee_no order by id asc ) AS rn
FROM crm_sales_expansion
WHERE employee_no IS NOT NULL
AND btrim ( employee_no ) < > ' '
)
UPDATE crm_sales_expansion s
SET employee_no = concat ( s . employee_no , ' - ' , s . id )
FROM duplicated d
WHERE s . id = d . id
AND d . rn > 1 ;
IF NOT EXISTS (
SELECT 1 FROM crm_sales_expansion WHERE employee_no IS NULL OR btrim ( employee_no ) = ' '
) THEN
ALTER TABLE crm_sales_expansion
ALTER COLUMN employee_no SET NOT NULL ;
END IF ;
END IF ;
END $ $ ;
DO $ $
BEGIN
IF to_regclass ( ' public.crm_sales_expansion ' ) IS NOT NULL THEN
IF NOT EXISTS (
SELECT 1
FROM pg_indexes
WHERE schemaname = ' public '
AND indexname = ' uk_crm_sales_expansion_owner_employee_no '
) THEN
CREATE UNIQUE INDEX uk_crm_sales_expansion_owner_employee_no
ON crm_sales_expansion ( owner_user_id , employee_no ) ;
END IF ;
END IF ;
END $ $ ;
-- crm_opportunity compatibility: absorb old extension fields and relationships
ALTER TABLE IF EXISTS crm_opportunity
ADD COLUMN IF NOT EXISTS sales_expansion_id bigint ,
ADD COLUMN IF NOT EXISTS channel_expansion_id bigint ,
2026-04-01 09:24:06 +00:00
ADD COLUMN IF NOT EXISTS pre_sales_id bigint ,
ADD COLUMN IF NOT EXISTS pre_sales_name varchar ( 100 ) ,
2026-03-27 09:05:41 +00:00
ADD COLUMN IF NOT EXISTS project_location varchar ( 100 ) ,
ADD COLUMN IF NOT EXISTS operator_name varchar ( 100 ) ,
ADD COLUMN IF NOT EXISTS competitor_name varchar ( 200 ) ;
DO $ $
BEGIN
IF to_regclass ( ' public.crm_opportunity ' ) IS NOT NULL THEN
ALTER TABLE public . crm_opportunity
DROP CONSTRAINT IF EXISTS crm_opportunity_stage_check ;
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = ' fk_crm_opportunity_sales_expansion '
) THEN
ALTER TABLE public . crm_opportunity
ADD CONSTRAINT fk_crm_opportunity_sales_expansion
FOREIGN KEY ( sales_expansion_id ) REFERENCES public . crm_sales_expansion ( id ) ;
END IF ;
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = ' fk_crm_opportunity_channel_expansion '
) THEN
ALTER TABLE public . crm_opportunity
ADD CONSTRAINT fk_crm_opportunity_channel_expansion
FOREIGN KEY ( channel_expansion_id ) REFERENCES public . crm_channel_expansion ( id ) ;
END IF ;
END IF ;
END $ $ ;
-- crm_channel_expansion compatibility: absorb detail columns and contact sub-table
ALTER TABLE IF EXISTS crm_channel_expansion
ADD COLUMN IF NOT EXISTS channel_code varchar ( 50 ) ,
ADD COLUMN IF NOT EXISTS office_address varchar ( 255 ) ,
ADD COLUMN IF NOT EXISTS channel_industry varchar ( 100 ) ,
2026-04-01 09:24:06 +00:00
ADD COLUMN IF NOT EXISTS city varchar ( 50 ) ,
ADD COLUMN IF NOT EXISTS certification_level varchar ( 100 ) ,
2026-03-27 09:05:41 +00:00
ADD COLUMN IF NOT EXISTS contact_established_date date ,
ADD COLUMN IF NOT EXISTS intent_level varchar ( 20 ) ,
ADD COLUMN IF NOT EXISTS has_desktop_exp boolean ,
ADD COLUMN IF NOT EXISTS channel_attribute varchar ( 100 ) ,
ADD COLUMN IF NOT EXISTS internal_attribute varchar ( 100 ) ;
DO $ $
BEGIN
IF to_regclass ( ' public.crm_channel_expansion ' ) IS NOT NULL THEN
IF EXISTS (
SELECT 1
FROM information_schema . columns
WHERE table_schema = ' public '
AND table_name = ' crm_channel_expansion '
AND column_name = ' industry '
) THEN
EXECUTE ' update public.crm_channel_expansion set channel_industry = coalesce(channel_industry, industry) where channel_industry is null and industry is not null ' ;
END IF ;
UPDATE crm_channel_expansion
SET intent_level = COALESCE ( intent_level , ' medium ' ) ,
has_desktop_exp = COALESCE ( has_desktop_exp , false ) ;
ALTER TABLE crm_channel_expansion
ALTER COLUMN intent_level SET DEFAULT ' medium ' ,
ALTER COLUMN has_desktop_exp SET DEFAULT false ;
IF EXISTS (
SELECT 1 FROM crm_channel_expansion WHERE intent_level IS NULL
) THEN
RAISE NOTICE ' crm_channel_expansion.intent_level still has null values before not-null enforcement ' ;
ELSE
ALTER TABLE crm_channel_expansion
ALTER COLUMN intent_level SET NOT NULL ;
END IF ;
IF EXISTS (
SELECT 1 FROM crm_channel_expansion WHERE has_desktop_exp IS NULL
) THEN
RAISE NOTICE ' crm_channel_expansion.has_desktop_exp still has null values before not-null enforcement ' ;
ELSE
ALTER TABLE crm_channel_expansion
ALTER COLUMN has_desktop_exp SET NOT NULL ;
END IF ;
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = ' crm_channel_expansion_intent_level_check '
) THEN
ALTER TABLE crm_channel_expansion
ADD CONSTRAINT crm_channel_expansion_intent_level_check
CHECK ( intent_level IN ( ' high ' , ' medium ' , ' low ' ) ) ;
END IF ;
END IF ;
END $ $ ;
CREATE TABLE IF NOT EXISTS crm_channel_expansion_contact (
id bigint generated by default as identity primary key ,
channel_expansion_id bigint not null ,
contact_name varchar ( 50 ) ,
contact_mobile varchar ( 20 ) ,
contact_title varchar ( 100 ) ,
sort_order integer not null default 1 ,
created_at timestamptz not null default now ( ) ,
updated_at timestamptz not null default now ( ) ,
constraint fk_crm_channel_expansion_contact_channel
foreign key ( channel_expansion_id ) references crm_channel_expansion ( id ) on delete cascade
) ;
DO $ $
BEGIN
IF to_regclass ( ' public.crm_channel_expansion ' ) IS NOT NULL
AND to_regclass ( ' public.crm_channel_expansion_contact ' ) IS NOT NULL THEN
INSERT INTO crm_channel_expansion_contact (
channel_expansion_id ,
contact_name ,
contact_mobile ,
contact_title ,
sort_order ,
created_at ,
updated_at
)
SELECT c . id , c . contact_name , c . contact_mobile , c . contact_title , 1 , now ( ) , now ( )
FROM crm_channel_expansion c
WHERE ( COALESCE ( btrim ( c . contact_name ) , ' ' ) < > ' '
OR COALESCE ( btrim ( c . contact_mobile ) , ' ' ) < > ' '
OR COALESCE ( btrim ( c . contact_title ) , ' ' ) < > ' ' )
AND NOT EXISTS (
SELECT 1
FROM crm_channel_expansion_contact cc
WHERE cc . channel_expansion_id = c . id
) ;
END IF ;
END $ $ ;
-- follow-up compatibility: source fields and structured work-report fields
ALTER TABLE IF EXISTS crm_expansion_followup
ADD COLUMN IF NOT EXISTS visit_start_time timestamptz ,
ADD COLUMN IF NOT EXISTS evaluation_content text ,
ADD COLUMN IF NOT EXISTS next_plan text ,
ADD COLUMN IF NOT EXISTS source_type varchar ( 30 ) ,
ADD COLUMN IF NOT EXISTS source_id bigint ;
ALTER TABLE IF EXISTS crm_opportunity_followup
ADD COLUMN IF NOT EXISTS source_type varchar ( 30 ) ,
ADD COLUMN IF NOT EXISTS source_id bigint ;
-- work_checkin compatibility: relation fields
ALTER TABLE IF EXISTS work_checkin
ADD COLUMN IF NOT EXISTS biz_type varchar ( 20 ) ,
ADD COLUMN IF NOT EXISTS biz_id bigint ,
ADD COLUMN IF NOT EXISTS biz_name varchar ( 200 ) ,
ADD COLUMN IF NOT EXISTS user_name varchar ( 100 ) ,
ADD COLUMN IF NOT EXISTS dept_name varchar ( 200 ) ;
DO $ $
BEGIN
IF to_regclass ( ' public.work_checkin ' ) IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conrelid = ' public.work_checkin ' : : regclass
AND conname = ' work_checkin_biz_type_check '
) THEN
ALTER TABLE public . work_checkin
ADD CONSTRAINT work_checkin_biz_type_check
CHECK ( biz_type IS NULL OR biz_type IN ( ' sales ' , ' channel ' , ' opportunity ' ) ) ;
END IF ;
END $ $ ;
-- additional indexes absorbed from historical DDLs
CREATE INDEX IF NOT EXISTS idx_crm_opportunity_channel_expansion
ON crm_opportunity ( channel_expansion_id ) ;
CREATE INDEX IF NOT EXISTS idx_crm_expansion_followup_source
ON crm_expansion_followup ( source_type , source_id ) ;
CREATE INDEX IF NOT EXISTS idx_crm_opportunity_followup_source
ON crm_opportunity_followup ( source_type , source_id ) ;
CREATE INDEX IF NOT EXISTS idx_crm_channel_expansion_contact_channel
ON crm_channel_expansion_contact ( channel_expansion_id ) ;
2026-04-01 09:24:06 +00:00
-- Column comments
WITH column_comments ( table_name , column_name , comment_text ) AS (
VALUES
( ' sys_user ' , ' id ' , ' 用户主键 ' ) ,
( ' sys_user ' , ' user_id ' , ' 用户ID ' ) ,
( ' sys_user ' , ' user_code ' , ' 工号/员工编号 ' ) ,
( ' sys_user ' , ' username ' , ' 登录账号 ' ) ,
( ' sys_user ' , ' real_name ' , ' 姓名 ' ) ,
( ' sys_user ' , ' display_name ' , ' 显示名称 ' ) ,
( ' sys_user ' , ' mobile ' , ' 手机号 ' ) ,
( ' sys_user ' , ' phone ' , ' 手机号 ' ) ,
( ' sys_user ' , ' email ' , ' 邮箱 ' ) ,
( ' sys_user ' , ' org_id ' , ' 所属组织ID ' ) ,
( ' sys_user ' , ' job_title ' , ' 职位 ' ) ,
( ' sys_user ' , ' status ' , ' 用户状态 ' ) ,
( ' sys_user ' , ' hire_date ' , ' 入职日期 ' ) ,
( ' sys_user ' , ' avatar_url ' , ' 头像地址 ' ) ,
( ' sys_user ' , ' password_hash ' , ' 密码哈希 ' ) ,
( ' sys_user ' , ' created_at ' , ' 创建时间 ' ) ,
( ' sys_user ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' sys_user ' , ' is_deleted ' , ' 逻辑删除标记 ' ) ,
( ' sys_user ' , ' pwd_reset_required ' , ' 首次登录是否需要重置密码 ' ) ,
( ' sys_user ' , ' is_platform_admin ' , ' 是否平台管理员 ' ) ,
( ' crm_customer ' , ' id ' , ' 客户主键 ' ) ,
( ' crm_customer ' , ' customer_code ' , ' 客户编码 ' ) ,
( ' crm_customer ' , ' customer_name ' , ' 客户名称 ' ) ,
( ' crm_customer ' , ' customer_type ' , ' 客户类型 ' ) ,
( ' crm_customer ' , ' industry ' , ' 行业 ' ) ,
( ' crm_customer ' , ' province ' , ' 省份 ' ) ,
( ' crm_customer ' , ' city ' , ' 城市 ' ) ,
( ' crm_customer ' , ' address ' , ' 详细地址 ' ) ,
( ' crm_customer ' , ' owner_user_id ' , ' 当前负责人ID ' ) ,
( ' crm_customer ' , ' source ' , ' 客户来源 ' ) ,
( ' crm_customer ' , ' status ' , ' 客户状态 ' ) ,
( ' crm_customer ' , ' remark ' , ' 备注说明 ' ) ,
( ' crm_customer ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_customer ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_opportunity ' , ' id ' , ' 商机主键 ' ) ,
( ' crm_opportunity ' , ' opportunity_code ' , ' 商机编号 ' ) ,
( ' crm_opportunity ' , ' opportunity_name ' , ' 商机名称 ' ) ,
( ' crm_opportunity ' , ' customer_id ' , ' 客户ID ' ) ,
( ' crm_opportunity ' , ' owner_user_id ' , ' 商机负责人ID ' ) ,
( ' crm_opportunity ' , ' sales_expansion_id ' , ' 关联销售拓展ID ' ) ,
( ' crm_opportunity ' , ' channel_expansion_id ' , ' 关联渠道拓展ID ' ) ,
( ' crm_opportunity ' , ' pre_sales_id ' , ' 售前ID ' ) ,
( ' crm_opportunity ' , ' pre_sales_name ' , ' 售前姓名 ' ) ,
( ' crm_opportunity ' , ' project_location ' , ' 项目所在地 ' ) ,
( ' crm_opportunity ' , ' operator_name ' , ' 运作方 ' ) ,
( ' crm_opportunity ' , ' amount ' , ' 商机金额 ' ) ,
( ' crm_opportunity ' , ' expected_close_date ' , ' 预计结单日期 ' ) ,
( ' crm_opportunity ' , ' confidence_pct ' , ' 把握度等级(A/B/C) ' ) ,
( ' crm_opportunity ' , ' stage ' , ' 商机阶段 ' ) ,
( ' crm_opportunity ' , ' opportunity_type ' , ' 商机类型 ' ) ,
( ' crm_opportunity ' , ' product_type ' , ' 产品类型 ' ) ,
( ' crm_opportunity ' , ' source ' , ' 商机来源 ' ) ,
( ' crm_opportunity ' , ' competitor_name ' , ' 竞品名称 ' ) ,
( ' crm_opportunity ' , ' archived ' , ' 是否归档 ' ) ,
( ' crm_opportunity ' , ' pushed_to_oms ' , ' 是否已推送OMS ' ) ,
( ' crm_opportunity ' , ' oms_push_time ' , ' 推送OMS时间 ' ) ,
( ' crm_opportunity ' , ' description ' , ' 商机说明/备注 ' ) ,
( ' crm_opportunity ' , ' status ' , ' 商机状态 ' ) ,
( ' crm_opportunity ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_opportunity ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_opportunity_followup ' , ' id ' , ' 跟进记录主键 ' ) ,
( ' crm_opportunity_followup ' , ' opportunity_id ' , ' 商机ID ' ) ,
( ' crm_opportunity_followup ' , ' followup_time ' , ' 跟进时间 ' ) ,
( ' crm_opportunity_followup ' , ' followup_type ' , ' 跟进方式 ' ) ,
( ' crm_opportunity_followup ' , ' content ' , ' 跟进内容 ' ) ,
( ' crm_opportunity_followup ' , ' next_action ' , ' 下一步动作 ' ) ,
( ' crm_opportunity_followup ' , ' followup_user_id ' , ' 跟进人ID ' ) ,
( ' crm_opportunity_followup ' , ' source_type ' , ' 来源类型 ' ) ,
( ' crm_opportunity_followup ' , ' source_id ' , ' 来源记录ID ' ) ,
( ' crm_opportunity_followup ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_opportunity_followup ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_sales_expansion ' , ' id ' , ' 销售拓展主键 ' ) ,
( ' crm_sales_expansion ' , ' employee_no ' , ' 工号/员工编号 ' ) ,
( ' crm_sales_expansion ' , ' candidate_name ' , ' 候选人姓名 ' ) ,
( ' crm_sales_expansion ' , ' office_name ' , ' 办事处/代表处 ' ) ,
( ' crm_sales_expansion ' , ' mobile ' , ' 手机号 ' ) ,
( ' crm_sales_expansion ' , ' email ' , ' 邮箱 ' ) ,
( ' crm_sales_expansion ' , ' target_dept ' , ' 所属部门 ' ) ,
( ' crm_sales_expansion ' , ' industry ' , ' 所属行业 ' ) ,
( ' crm_sales_expansion ' , ' title ' , ' 职务 ' ) ,
( ' crm_sales_expansion ' , ' intent_level ' , ' 合作意向 ' ) ,
( ' crm_sales_expansion ' , ' stage ' , ' 跟进阶段 ' ) ,
( ' crm_sales_expansion ' , ' has_desktop_exp ' , ' 是否有云桌面经验 ' ) ,
( ' crm_sales_expansion ' , ' in_progress ' , ' 是否持续跟进中 ' ) ,
( ' crm_sales_expansion ' , ' employment_status ' , ' 候选人状态 ' ) ,
( ' crm_sales_expansion ' , ' expected_join_date ' , ' 预计入职日期 ' ) ,
( ' crm_sales_expansion ' , ' owner_user_id ' , ' 负责人ID ' ) ,
( ' crm_sales_expansion ' , ' remark ' , ' 备注说明 ' ) ,
( ' crm_sales_expansion ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_sales_expansion ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_channel_expansion ' , ' id ' , ' 渠道拓展主键 ' ) ,
( ' crm_channel_expansion ' , ' channel_code ' , ' 渠道编码 ' ) ,
( ' crm_channel_expansion ' , ' province ' , ' 省份 ' ) ,
( ' crm_channel_expansion ' , ' city ' , ' 市 ' ) ,
( ' crm_channel_expansion ' , ' channel_name ' , ' 渠道名称 ' ) ,
( ' crm_channel_expansion ' , ' office_address ' , ' 办公地址 ' ) ,
( ' crm_channel_expansion ' , ' channel_industry ' , ' 聚焦行业 ' ) ,
( ' crm_channel_expansion ' , ' certification_level ' , ' 认证级别 ' ) ,
( ' crm_channel_expansion ' , ' industry ' , ' 行业(兼容旧字段) ' ) ,
( ' crm_channel_expansion ' , ' annual_revenue ' , ' 年营收 ' ) ,
( ' crm_channel_expansion ' , ' staff_size ' , ' 人员规模 ' ) ,
( ' crm_channel_expansion ' , ' contact_established_date ' , ' 建立联系日期 ' ) ,
( ' crm_channel_expansion ' , ' intent_level ' , ' 合作意向 ' ) ,
( ' crm_channel_expansion ' , ' has_desktop_exp ' , ' 是否有云桌面经验 ' ) ,
( ' crm_channel_expansion ' , ' contact_name ' , ' 主联系人姓名(兼容旧结构) ' ) ,
( ' crm_channel_expansion ' , ' contact_title ' , ' 主联系人职务(兼容旧结构) ' ) ,
( ' crm_channel_expansion ' , ' contact_mobile ' , ' 主联系人电话(兼容旧结构) ' ) ,
( ' crm_channel_expansion ' , ' channel_attribute ' , ' 渠道属性编码,多个值逗号分隔 ' ) ,
( ' crm_channel_expansion ' , ' internal_attribute ' , ' 新华三内部属性编码,多个值逗号分隔 ' ) ,
( ' crm_channel_expansion ' , ' stage ' , ' 渠道合作阶段 ' ) ,
( ' crm_channel_expansion ' , ' landed_flag ' , ' 是否已落地 ' ) ,
( ' crm_channel_expansion ' , ' expected_sign_date ' , ' 预计签约日期 ' ) ,
( ' crm_channel_expansion ' , ' owner_user_id ' , ' 负责人ID ' ) ,
( ' crm_channel_expansion ' , ' remark ' , ' 备注说明 ' ) ,
( ' crm_channel_expansion ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_channel_expansion ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_channel_expansion_contact ' , ' id ' , ' 联系人主键 ' ) ,
( ' crm_channel_expansion_contact ' , ' channel_expansion_id ' , ' 渠道拓展ID ' ) ,
( ' crm_channel_expansion_contact ' , ' contact_name ' , ' 联系人姓名 ' ) ,
( ' crm_channel_expansion_contact ' , ' contact_mobile ' , ' 联系人电话 ' ) ,
( ' crm_channel_expansion_contact ' , ' contact_title ' , ' 联系人职务 ' ) ,
( ' crm_channel_expansion_contact ' , ' sort_order ' , ' 排序号 ' ) ,
( ' crm_channel_expansion_contact ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_channel_expansion_contact ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' crm_expansion_followup ' , ' id ' , ' 跟进记录主键 ' ) ,
( ' crm_expansion_followup ' , ' biz_type ' , ' 业务类型 ' ) ,
( ' crm_expansion_followup ' , ' biz_id ' , ' 业务对象ID ' ) ,
( ' crm_expansion_followup ' , ' followup_time ' , ' 跟进时间 ' ) ,
( ' crm_expansion_followup ' , ' followup_type ' , ' 跟进方式 ' ) ,
( ' crm_expansion_followup ' , ' content ' , ' 跟进内容 ' ) ,
( ' crm_expansion_followup ' , ' next_action ' , ' 下一步动作 ' ) ,
( ' crm_expansion_followup ' , ' followup_user_id ' , ' 跟进人ID ' ) ,
( ' crm_expansion_followup ' , ' visit_start_time ' , ' 拜访开始时间 ' ) ,
( ' crm_expansion_followup ' , ' evaluation_content ' , ' 评估内容 ' ) ,
( ' crm_expansion_followup ' , ' next_plan ' , ' 后续规划 ' ) ,
( ' crm_expansion_followup ' , ' source_type ' , ' 来源类型 ' ) ,
( ' crm_expansion_followup ' , ' source_id ' , ' 来源记录ID ' ) ,
( ' crm_expansion_followup ' , ' created_at ' , ' 创建时间 ' ) ,
( ' crm_expansion_followup ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' work_checkin ' , ' id ' , ' 打卡记录主键 ' ) ,
( ' work_checkin ' , ' user_id ' , ' 打卡人ID ' ) ,
( ' work_checkin ' , ' checkin_date ' , ' 打卡日期 ' ) ,
( ' work_checkin ' , ' checkin_time ' , ' 打卡时间 ' ) ,
( ' work_checkin ' , ' biz_type ' , ' 关联对象类型 ' ) ,
( ' work_checkin ' , ' biz_id ' , ' 关联对象ID ' ) ,
( ' work_checkin ' , ' biz_name ' , ' 关联对象名称 ' ) ,
( ' work_checkin ' , ' longitude ' , ' 经度 ' ) ,
( ' work_checkin ' , ' latitude ' , ' 纬度 ' ) ,
( ' work_checkin ' , ' location_text ' , ' 打卡地点 ' ) ,
( ' work_checkin ' , ' remark ' , ' 备注说明(含现场照片元数据) ' ) ,
( ' work_checkin ' , ' user_name ' , ' 打卡人姓名快照 ' ) ,
( ' work_checkin ' , ' dept_name ' , ' 所属部门快照 ' ) ,
( ' work_checkin ' , ' status ' , ' 打卡状态 ' ) ,
( ' work_checkin ' , ' created_at ' , ' 创建时间 ' ) ,
( ' work_checkin ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' work_daily_report ' , ' id ' , ' 日报主键 ' ) ,
( ' work_daily_report ' , ' user_id ' , ' 提交人ID ' ) ,
( ' work_daily_report ' , ' report_date ' , ' 日报日期 ' ) ,
( ' work_daily_report ' , ' work_content ' , ' 今日工作内容(含结构化明细元数据) ' ) ,
( ' work_daily_report ' , ' tomorrow_plan ' , ' 明日工作计划(含结构化计划项元数据) ' ) ,
( ' work_daily_report ' , ' source_type ' , ' 提交来源 ' ) ,
( ' work_daily_report ' , ' submit_time ' , ' 提交时间 ' ) ,
( ' work_daily_report ' , ' status ' , ' 日报状态 ' ) ,
( ' work_daily_report ' , ' score ' , ' 日报评分 ' ) ,
( ' work_daily_report ' , ' created_at ' , ' 创建时间 ' ) ,
( ' work_daily_report ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' work_daily_report_comment ' , ' id ' , ' 点评记录主键 ' ) ,
( ' work_daily_report_comment ' , ' report_id ' , ' 日报ID ' ) ,
( ' work_daily_report_comment ' , ' reviewer_user_id ' , ' 点评人ID ' ) ,
( ' work_daily_report_comment ' , ' score ' , ' 点评评分 ' ) ,
( ' work_daily_report_comment ' , ' comment_content ' , ' 点评内容 ' ) ,
( ' work_daily_report_comment ' , ' reviewed_at ' , ' 点评时间 ' ) ,
( ' work_daily_report_comment ' , ' created_at ' , ' 创建时间 ' ) ,
( ' work_todo ' , ' id ' , ' 待办主键 ' ) ,
( ' work_todo ' , ' user_id ' , ' 所属用户ID ' ) ,
( ' work_todo ' , ' title ' , ' 待办标题 ' ) ,
( ' work_todo ' , ' biz_type ' , ' 业务类型 ' ) ,
( ' work_todo ' , ' biz_id ' , ' 业务对象ID ' ) ,
( ' work_todo ' , ' due_date ' , ' 截止时间 ' ) ,
( ' work_todo ' , ' status ' , ' 待办状态 ' ) ,
( ' work_todo ' , ' priority ' , ' 优先级 ' ) ,
( ' work_todo ' , ' created_at ' , ' 创建时间 ' ) ,
( ' work_todo ' , ' updated_at ' , ' 更新时间 ' ) ,
( ' sys_activity_log ' , ' id ' , ' 动态主键 ' ) ,
( ' sys_activity_log ' , ' biz_type ' , ' 业务类型 ' ) ,
( ' sys_activity_log ' , ' biz_id ' , ' 业务对象ID ' ) ,
( ' sys_activity_log ' , ' action_type ' , ' 动作类型 ' ) ,
( ' sys_activity_log ' , ' title ' , ' 动态标题 ' ) ,
( ' sys_activity_log ' , ' content ' , ' 动态内容 ' ) ,
( ' sys_activity_log ' , ' operator_user_id ' , ' 操作人ID ' ) ,
( ' sys_activity_log ' , ' created_at ' , ' 创建时间 ' )
)
SELECT comment_on_column_if_exists ( table_name , column_name , comment_text )
FROM column_comments ;
2026-04-02 02:07:21 +00:00
INSERT INTO sys_dict_item ( type_code , item_label , item_value , sort_order , status , is_deleted , remark )
SELECT v . type_code , v . item_label , v . item_value , v . sort_order , 1 , 0 , ' 商机建设类型 '
FROM (
VALUES
( ' sj_jslx ' , ' 新建 ' , ' 新建 ' , 1 ) ,
( ' sj_jslx ' , ' 扩容 ' , ' 扩容 ' , 2 ) ,
( ' sj_jslx ' , ' 替换 ' , ' 替换 ' , 3 )
) AS v ( type_code , item_label , item_value , sort_order )
WHERE NOT EXISTS (
SELECT 1
FROM sys_dict_item s
WHERE s . type_code = v . type_code
AND s . item_value = v . item_value
AND COALESCE ( s . is_deleted , 0 ) = 0
) ;
2026-03-27 09:05:41 +00:00
commit ;