ThinkWo 开发文档DOCS v1.0.45
快速开始
文档首页 / 附录 / 数据字典

数据字典

共 19 张表,表前缀统一 tw_(安装时可改)。所有时间字段都是 int 时间戳,不是 datetime;所有"软状态"用 tinyint 存 1/0。

一、表关系总览

tw_language 语言 └──(lang 字段贯穿几乎所有表) tw_sort 栏目树(pid 自关联) ├──tw_content 内容(sort_id 外键) │ ├──tw_attachment 附件(ico / images 存路径) │ └──tw_price 阶梯价(product_id) └──tw_sort_field 栏目自定义字段定义(sort_id 外键) tw_slide_group 幻灯片分组(code 唯一) └──tw_slide 幻灯片条目(group_id + lang) tw_admin_group 角色 ├──tw_admin 管理员(group_id) └──tw_admin_rule 权限节点(rules 存 ID 列表) tw_inquiry 询盘 ←── tw_cart 询价车(sid 会话) tw_setting 设置键值对 tw_redirect 301/302 tw_plugin 插件状态与配置 tw_currency 货币与汇率 tw_visit 访客会话(一台设备一个会话一行) └──tw_visit_page 页面浏览明细(visit_id 外键)

二、tw_sort — 栏目

树形结构,pid=0 为一级。同一语言下 slug 唯一。

字段类型说明
idint unsigned主键
langvarchar(10)语言代码,如 en
pidint unsigned上级栏目 ID,0 = 一级
typevarchar(10)list 列表 / page 单页 / link 外链
name / subnamevarchar栏目名称 / 副标题
slugvarchar(100)URL 别名,与 lang 组成唯一键
ico / picvarchar(255)栏目缩略图 / 栏目大图(相对路径)
descriptiontext栏目简介,列表页顶部展示
seo_title / seo_keywords / seo_descriptionvarcharSEO 三要素
canonicalvarchar(255)自定义 canonical,留空则自指
trans_keyvarchar(64)跨语言配对键(hreflang 用)
template_listvarchar(50)列表页模板名,默认 lists
template_detailvarchar(50)详情页模板名,默认 detail
template_pagevarchar(50)单页模板名,默认 page
linkvarchar(255)外链地址(type=link 时使用)
statustinyint(1)1 显示 / 0 隐藏
sortint排序,越小越前
createtime / updatetimeint创建 / 更新时间戳

三、tw_content — 内容

产品、新闻、案例、单页正文都用这一张表,靠 sort_id 区分。

字段类型说明
idint unsigned主键
langvarchar(10)语言代码
sort_idint unsigned所属栏目
title / subtitlevarchar标题 / 副标题(产品常用作一句话卖点)
slugvarchar(120)URL 别名,与 lang 组成唯一键
icovarchar(255)缩略图(列表卡片用)
imagestext图集,JSON 数组字符串,如 ["/uploads/a.jpg"]
summaryvarchar(500)摘要,列表卡片与 meta description 兜底
contentmediumtext正文,原始 HTML(模板输出需 |html_entity_decode|raw)
tagsvarchar(255)标签,逗号分隔,如 cnc,aluminum
seo_title / seo_keywords / seo_descriptionvarcharSEO 三要素
canonicalvarchar(255)自定义 canonical
noindextinyint(1)1 = 输出 noindex,follow
attrvarchar(50)推荐属性,逗号分隔:recommend / hot / new
author / sourcevarchar作者 / 来源(新闻用)
metavarchar(1000)扩展属性(v1.0.43 起)。栏目没有自定义字段时 = 后台内容表单「扩展」文本框的原文(如价格卡里的 ¥4800);栏目定义了自定义字段时 = JSON {"字段键":"值"},后台「扩展」框自动隐藏。模板取 {$list.meta} 拿原文,取 {$list.字段键} 拿解析后的单项
viewsint unsigned浏览量,可用于"热门"排序
price / unitdecimal(12,2) / varchar参考价 / 单位(如 pcs)
model_no / moqvarchar产品型号 / 最小起订量
trans_keyvarchar(64)跨语言配对键
statustinyint(1)1 发布 / 0 草稿
sortint排序
publish_timeint unsigned发布时间,列表默认按它倒序
createtime / updatetimeint创建 / 更新
想给内容多加几个字段,不要急着加列(v1.0.44 起有更好的办法)

先走栏目自定义字段:栏目管理 → 字段,定义几个字段键,值会自动存进 meta(JSON), 模板用 {$list.字段键} 就能取到,全程不用改表、不用改程序。详见 栏目自定义字段。

只有两种情况才需要真的加列:① 要在 {tw:list} 里做排序 / 筛选 / 统计(meta 里的 JSON 不方便查); ② 值会很长(超过 meta 的 1000 字上限)。加列后列表标签仍拿不到——需要把字段加进 Tags::lists() 的 field() 白名单,详情页 $content 则是自动全字段。

四、tw_language — 语言

字段类型说明
codevarchar(10)语言代码,决定 URL 前缀:en(默认语言无前缀)、zh-cn
name / native_namevarchar(50)显示名 / 本地名(如 中文)
regionvarchar(20)hreflang 区域码,如 en-US、zh-CN,同时输出到 <html lang>
dirvarchar(3)ltr 或 rtl(阿拉伯语/希伯来语)
is_defaulttinyint(1)默认语言:URL 不带前缀,且是 hreflang 的 x-default
sort / statusint / tinyint排序 / 启用状态
只能有一个默认语言

新增语言时注意把其他语言的 is_default 置 0,否则 URL 前缀逻辑会混乱。

五、tw_inquiry — 询盘

字段类型说明
novarchar(32)询盘编号,如 TWQ20260101001,唯一
langvarchar(10)提交时的语言
name / email / phone / whatsappvarchar客户联系方式
company / countryvarchar公司 / 国家
subject / messagevarchar / text主题 / 正文
product_id / product_nameint / varchar关联产品(名称是快照,产品改名不影响历史记录)
itemstext询价车明细 JSON
amount / currencydecimal / varchar合计金额 / 币种
source_url / ip / uavarchar来源页、IP、浏览器 UA(反查刷单用)
statusvarchar(20)new / read / quoted / replied / won / closed
prioritytinyint1 高 / 2 中 / 3 低
remarktext内部跟进备注(客户端看不到)
admin_idint最后处理人
createtime / updatetimeint提交 / 更新

六、tw_cart — 询价车

不是购物车(不付款),是"客户攒一批产品,一起发询盘"。

字段类型说明
sidvarchar(64)浏览器会话 ID(cookie 里的标识,非会员体系)
langvarchar(10)加购时的语言
product_id / product_name / product_urlint / varchar产品信息快照
price / qty / currencydecimal / int / varchar参考价、数量、币种

七、tw_price — 阶梯价

字段类型说明
product_idint产品 ID
langvarchar(10)语言(不同语言可独立定价)
min_qtyint unsigned起订量(该档从这里开始)
pricedecimal(12,2)单价
unitvarchar(20)单位

八、tw_attachment — 附件

字段类型说明
namevarchar(255)原始文件名
path / urlvarchar相对路径 / 完整访问地址
ext / mime / sizevarchar / int扩展名 / MIME / 字节数
width / heightint图片宽高(用于输出 width/height 防 CLS)
webpvarchar(255)WebP 版本路径
hashvarchar(64)文件哈希,用于查重
admin_idint上传者

九、tw_setting — 设置

极简键值表,skey 唯一。sgroup 只用于后台分组展示:base / seo / contact / mail / system。

字段类型说明
skeyvarchar(64)键,如 site_name、phone
svaluetext值(统一存字符串,布尔用 1/0)
sgroupvarchar(30)分组

代码里读:tw_setting('phone') 或 Settings::get('phone');写:Settings::set('phone', '...')(会自动清缓存)。

十、tw_admin / tw_admin_group / tw_admin_rule — 权限

tw_admin 管理员

字段说明
group_id所属角色组
username / password / salt账号 / 密码哈希 / 盐(不要手工改这三列,用后台改密码)
nickname / email / avatar资料
login_ip / login_time最后登录信息
login_fail / lock_until连续失败次数 / 锁定到期时间(防爆破)
status1 启用 / 0 禁用

tw_admin_group 角色

字段说明
name角色名,如"运营"
rules权限节点 ID 列表(逗号分隔),* 表示全部权限

tw_admin_rule 权限节点

字段说明
pid上级节点,0 = 一级菜单
typemenu 菜单 / button 按钮级权限 / link 外链
name权限标识,如 content/index
pathURL 路径(控制器/方法)
plugin所属插件名,空表示核心功能

菜单定义在 app/admin/menu.php,进入后台时按版本号自动同步到这张表。

十一、tw_redirect — 跳转

字段说明
from_path旧地址路径,如 /old-page.html(不带域名)
to_path新地址,站内路径或完整外链
code301 永久 / 302 临时
hits命中次数,用来判断哪些老链接还有流量
status1 启用 / 0 停用

十二、tw_plugin — 插件状态

字段说明
name插件目录名,唯一
title / version / author / description从 plugin.json 同步
status1 启用 / 0 停用
config插件配置 JSON

十三、tw_currency — 货币

多货币展示用,前台按 rate 换算,基准货币的 rate 固定 1.000000。

字段说明
code货币代码,如 USD / EUR
name / symbol名称与符号,如 US Dollar / $
rate对基准货币的汇率,decimal(12,6)
status / sort启用状态与排序

十四、tw_visit / tw_visit_page — 访客统计

两张表配合使用:tw_visit 一个会话一行(聚合数据,后台列表读它); tw_visit_page 一次页面浏览一行(明细,后台「访问详情」的浏览轨迹读它)。写入全部由 Visit.php 完成,sid 唯一键保证同一会话只更新不新建。

tw_visit — 访客会话

字段类型说明
sidvarchar(32)会话 ID(唯一键),前端 sessionStorage 存 30 分钟
vidvarchar(32)访客 ID,前端 cookie 存 1 年,用于识别回访
ipvarchar(45)兼容 IPv6
uavarchar(500)原始 User-Agent
device / browser / osvarchar由 UA 解析:desktop / mobile / tablet
langvarchar(10)访问时的语言站点,如 en
referer / ref_hostvarchar来源页与来源域名(Google / Facebook 判断依据)
landing / last_urlvarchar(500)落地页与最后停留页
pages / durationint浏览页数、累计停留秒数
first_time / last_timeint本次会话开始 / 最后活动时间

tw_visit_page — 页面浏览明细

字段类型说明
visit_idint关联 tw_visit.id
sid / vidvarchar(32)冗余存一份,便于按会话/访客直查
url / titlevarchar页面路径与标题(前台传什么存什么)
sort_id / content_idint能对应到栏目/内容时填入,用于页面热度聚合
referervarchar(500)进入本页时的来源
enter_time / leave_time / durationint进入、离开时间与停留秒数
这两张表会持续增长

默认保留 90 天(站点设置 visit_keep_days),过期记录在写入时按概率触发清理。 数据量大时可把保留天数调小,或定期 DELETE FROM tw_visit WHERE first_time < UNIX_TIMESTAMP(NOW() - INTERVAL 30 DAY), 再执行 OPTIMIZE TABLE 回收空间。

十五、tw_sort_field — 栏目自定义字段定义

v1.0.44 新增。一条记录 = 栏目表单上的一个输入框。值不存在这张表,存在 tw_content.meta 的 JSON 里;本表只定义"有哪些字段、叫什么、什么类型"。

字段类型说明
sort_idint unsigned字段挂在哪个栏目上(栏目删了要一起清)
namevarchar(50)字段名称,后台表单上显示的中文标签,如「主按钮链接」
fkeyvarchar(50)字段键,模板里用的变量名,如 cta1_url。同栏目内唯一,只允许小写字母/数字/下划线,留空时后台按中文名自动生成 cf_拼音
typevarchar(10)text 单行 / textarea 多行 / select 下拉 / switch 开关
optionsvarchar(500)下拉选项,一行一个(只对 select 有效)。存的是选项文字本身,不是序号
defvalvarchar(200)默认值,新增内容时预填
sort / statusint / tinyint(1)排序 / 1 启用 0 停用(停用后表单不再渲染该输入框,已存的值保留)
createtime / updatetimeint时间戳
这张表没有唯一键

同栏目 fkey 不重复是靠后台保存时校验的(Sort::fieldSave()),手工 INSERT 绕过去就会出现两个同名键、后者覆盖前者。 另外系统保留名(title / summary / content / meta / url / lines / cf 等)会被直接拒绝。

十六、tw_slide_group — 幻灯片分组

一个分组 = 前台一个位置的图集(首页轮播、内页 banner、优势配图…)。靠 code 而不是 id 调用,换站迁移时 id 会变、code 不会。

字段类型说明
namevarchar(80)分组名称,后台列表显示用
codevarchar(60)调用标识(唯一键),模板里写 {tw:slide group="home"}
remarkvarchar(255)用途说明 / 尺寸建议,只给编辑看
width / heightint unsigned建议尺寸(像素),后台提示用,程序不做校验
status / sorttinyint(1) / int1 启用 / 0 停用;排序

十七、tw_slide — 幻灯片条目

一张图一条记录。多语言用 lang 区分;当前语言下该分组没有启用条目时,整组回退到默认语言——所以只做一个语言的站不用为每种语言重复上传同一张图。

字段类型说明
group_idint unsigned所属分组
langvarchar(10)语言代码
title / subtitle / summaryvarchar主标题 / 副标题 / 描述
image / image_mobilevarchar(500)电脑图 / 手机图(手机图留空则用电脑图)
videovarchar(500)视频地址(mp4),可空;有值时模板可用 {$slide.has_video} 判断
url / target / btn_textvarchar跳转链接 / _self·_blank / 按钮文字
start_time / end_timeint unsigned定时上下线窗口,0 = 不限;查询时按当前时间过滤
status / sorttinyint(1) / int1 启用 / 0 停用;排序(同 sort 按 id 升序)

标签用法见 标签与函数 → slide / slidegroup;栏目还可以绑一个默认分组(tw_sort.slide_group 存 code),这样同一套内页模板能按栏目出不同 banner。

十八、常用 SQL

看某个栏目下有多少条内容

SELECT s.name, COUNT(c.id) AS total
FROM tw_sort s
LEFT JOIN tw_content c ON c.sort_id = s.id AND c.status = 1
WHERE s.lang = 'en'
GROUP BY s.id
ORDER BY s.sort;

本月询盘按国家统计

SELECT country, COUNT(*) AS cnt
FROM tw_inquiry
WHERE createtime >= UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-01'))
GROUP BY country
ORDER BY cnt DESC;

查没填 SEO 描述的内容

SELECT id, title FROM tw_content
WHERE status = 1 AND (seo_description = '' OR seo_description IS NULL);

批量补 trans_key(按 slug 配对)

UPDATE tw_content SET trans_key = CONCAT('c-', slug)
WHERE trans_key = '' AND slug != '';

看今天来了多少人、从哪些渠道来

SELECT IF(ref_host = '', 'direct', ref_host) AS channel,
       COUNT(*) AS sessions,
       SUM(pages) AS pv,
       ROUND(AVG(duration)) AS avg_sec
FROM tw_visit
WHERE first_time >= UNIX_TIMESTAMP(CURDATE())
GROUP BY channel
ORDER BY sessions DESC;

哪几页留人最久(近 7 天)

SELECT url, COUNT(*) AS pv, ROUND(AVG(duration)) AS avg_sec
FROM tw_visit_page
WHERE enter_time >= UNIX_TIMESTAMP(NOW() - INTERVAL 7 DAY)
GROUP BY url
HAVING pv >= 5
ORDER BY avg_sec DESC
LIMIT 20;

清理 30 天前的访客数据

DELETE p FROM tw_visit_page p
JOIN tw_visit v ON v.id = p.visit_id
WHERE v.first_time < UNIX_TIMESTAMP(NOW() - INTERVAL 30 DAY);

DELETE FROM tw_visit WHERE first_time < UNIX_TIMESTAMP(NOW() - INTERVAL 30 DAY);

查某栏目定义了哪些自定义字段

SELECT f.name, f.fkey, f.type, f.options, f.defval
FROM tw_sort_field f
JOIN tw_sort s ON s.id = f.sort_id
WHERE s.slug = 'home-hero' AND f.status = 1
ORDER BY f.sort;

取内容里某个自定义字段的值(meta 是 JSON)

SELECT id, title,
       JSON_UNQUOTE(JSON_EXTRACT(meta, '$.badge')) AS badge
FROM tw_content
WHERE sort_id = 20006 AND status = 1;
改库前先备份

任何 UPDATE / DELETE 前先 mysqldump 单表;批量操作先用 SELECT 查一遍影响范围(把 UPDATE 改成 SELECT COUNT(*) 试跑)。

ThinkWo CMS v1.0.45 开发文档 · 基于 ThinkPHP 8.1.4 + LayUI 2.12 · 文档随代码更新