文件还在测试中

This commit is contained in:
2026-08-08 15:53:53 +08:00
parent 5f1e7adb64
commit 8101177cb5
241 changed files with 18074 additions and 22 deletions
+182
View File
@@ -0,0 +1,182 @@
<?php
/**
* 安装 / 初始化脚本
* 用法:
* CLI: php install/install.php
* Web: 浏览器访问 /install/install.php
* 根据 config 中 app.driver 写入 文件(JSON) 或 MySQL,并生成 theme.css。
*/
define('BASE_PATH', dirname(__DIR__));
require BASE_PATH . '/app/Core/App.php';
Core\App::init();
$cli = PHP_SAPI === 'cli';
$out = function (string $msg) use ($cli) {
echo $cli ? $msg . "\n" : "<p>" . htmlspecialchars($msg) . "</p>\n";
};
/**
* 增量升级模式:仅给已部署的系统补齐新模块的数据表/列,绝不触碰已有业务数据。
* 与 install/upgrade_crm_psi.sql 逻辑等价,但改用 PDO 直连(避免 DELIMITER/存储过程在 PHP 侧不兼容)。
* 用法:php install/install.php --upgrade 或 Web: /install/install.php?upgrade=1
*/
function runUpgrade(): void
{
global $out;
$driver = Core\Db::driver();
if ($driver !== 'mysql') {
$out("⚠ 当前为 file 模式,CRM/PSI 在文件模式下自动生成 JSON,无需数据库升级。");
return;
}
$pdo = Core\Db::pdo();
$pdo->exec("SET NAMES utf8mb4");
$stmts = [
// ===== CRM 客户管理 =====
"CREATE TABLE IF NOT EXISTS `crm_customers` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(120) NOT NULL, `company` VARCHAR(160) DEFAULT '',
`contact` VARCHAR(60) DEFAULT '', `phone` VARCHAR(40) DEFAULT '', `email` VARCHAR(120) DEFAULT '',
`country` VARCHAR(60) DEFAULT '', `type` VARCHAR(20) DEFAULT 'trade', `source` VARCHAR(40) DEFAULT '',
`level` VARCHAR(20) DEFAULT 'C', `remark` TEXT, `owner` VARCHAR(60) DEFAULT '', `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `crm_leads` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `customer_id` INT DEFAULT 0, `title` VARCHAR(200) NOT NULL,
`amount` DECIMAL(12,2) DEFAULT 0, `stage` VARCHAR(20) DEFAULT 'new', `expected_close` VARCHAR(20) DEFAULT '',
`owner` VARCHAR(60) DEFAULT '', `remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `crm_followups` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `customer_id` INT DEFAULT 0, `lead_id` INT DEFAULT 0,
`content` TEXT, `next_at` VARCHAR(20) DEFAULT '', `owner` VARCHAR(60) DEFAULT '', `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
// ===== 进销存 PSI =====
"CREATE TABLE IF NOT EXISTS `psi_materials` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(40) DEFAULT '', `name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '', `unit` VARCHAR(10) DEFAULT '个', `category` VARCHAR(40) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0, `price` DECIMAL(10,2) DEFAULT 0, `supplier_id` INT DEFAULT 0,
`remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `psi_products` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(40) DEFAULT '', `name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '', `unit` VARCHAR(10) DEFAULT '件', `category` VARCHAR(40) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0, `cost` DECIMAL(10,2) DEFAULT 0, `price` DECIMAL(10,2) DEFAULT 0,
`remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `psi_suppliers` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(160) NOT NULL, `contact` VARCHAR(60) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '', `country` VARCHAR(60) DEFAULT '', `remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `psi_purchases` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `order_no` VARCHAR(40) NOT NULL, `supplier_id` INT DEFAULT 0,
`item_type` VARCHAR(10) DEFAULT 'material', `item_id` INT DEFAULT 0, `qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0, `amount` DECIMAL(12,2) DEFAULT 0, `status` VARCHAR(20) DEFAULT 'pending',
`remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `psi_sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `order_no` VARCHAR(40) NOT NULL, `customer` VARCHAR(160) DEFAULT '',
`channel` VARCHAR(20) DEFAULT 'domestic', `item_id` INT DEFAULT 0, `qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0, `amount` DECIMAL(12,2) DEFAULT 0, `status` VARCHAR(20) DEFAULT 'pending',
`remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
"CREATE TABLE IF NOT EXISTS `psi_stock_moves` (
`id` INT AUTO_INCREMENT PRIMARY KEY, `item_type` VARCHAR(10) DEFAULT 'product', `item_id` INT DEFAULT 0,
`direction` VARCHAR(10) DEFAULT 'in', `qty` DECIMAL(12,2) DEFAULT 0, `ref_no` VARCHAR(40) DEFAULT '',
`remark` TEXT, `created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
];
foreach ($stmts as $s) { $pdo->exec($s); }
$out("✓ CRM/PSI 数据表已就绪(CREATE TABLE IF NOT EXISTS,幂等可重复执行)");
// 为 admin_users 补齐分系统角色列(先查 information_schema,存在则跳过,兼容 5.7/8.0
$cols = $pdo->query("SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='admin_users'")->fetchAll(PDO::FETCH_COLUMN);
foreach (['crm_role' => "VARCHAR(20) DEFAULT 'none'", 'psi_role' => "VARCHAR(20) DEFAULT 'none'"] as $c => $def) {
if (!in_array($c, $cols, true)) {
$pdo->exec("ALTER TABLE `admin_users` ADD COLUMN `{$c}` {$def}");
$out("✓ 已添加 admin_users.{$c}");
} else {
$out("⊘ admin_users.{$c} 已存在,跳过");
}
}
$out("✓ 数据升级完成。请登录后台 → 用户管理,将相关账号 crm_role / psi_role 设为 admin。");
}
// 升级模式:绕过 installed.lock,仅增量建表/补列
$isUpgrade = ($cli && in_array('--upgrade', $argv ?? [], true))
|| (!$cli && trim((string)($_GET['upgrade'] ?? '')) === '1');
if ($isUpgrade) {
runUpgrade();
exit;
}
// 质量红线:生产环境二次运行保护。已安装后写入 installed.lock,再次访问直接拒绝,避免数据被清空。
$lock = BASE_PATH . '/storage/installed.lock';
if (is_file($lock) && !($cli && in_array('--force', $argv ?? [], true))) {
$out("⛔ 检测到 installed.lock,系统已安装。如需重置请删除该文件或执行:php install/install.php --force");
exit;
}
$seed = require BASE_PATH . '/install/seed.php';
$driver = Core\Db::driver();
if ($driver === 'file') {
$dir = Core\Db::fileDir();
foreach ($seed as $table => $rows) {
// 确保每条记录带 id(如 settings 种子未含 id),否则文件模式无法按主键更新
$i = 1;
foreach ($rows as &$r) { if (!isset($r['id'])) { $r['id'] = $i; } $i++; }
unset($r);
file_put_contents($dir . "/{$table}.json", json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
$out("✓ 写入 {$table}.json (" . count($rows) . " 条)");
}
} else {
// MySQL:建表 + 插入
$sql = file_get_contents(BASE_PATH . '/install/schema.sql');
$pdo = Core\Db::pdo();
$pdo->exec($sql);
$out("✓ 数据表已创建");
// 幂等升级:为已存在的 admin_users 补齐分系统角色列(已有则忽略)
foreach (['crm_role VARCHAR(20) DEFAULT \'none\'', 'psi_role VARCHAR(20) DEFAULT \'none\''] as $col) {
try { $pdo->exec("ALTER TABLE `admin_users` ADD COLUMN IF NOT EXISTS `{$col}`"); }
catch (\Throwable $e) { /* 5.7 不支持 IF NOT EXISTS 时忽略已存在错误 */ }
}
$out("✓ admin_users 分系统角色列已补齐");
$map = [
'categories' => new App\Models\Category(),
'products' => new App\Models\Product(),
'news' => new App\Models\News(),
'pages' => new App\Models\Page(),
'banners' => new App\Models\Banner(),
'cases' => new App\Models\CustomerCase(),
'admin_users'=> new App\Models\AdminUser(),
'settings' => new App\Models\Setting(),
'crm_customers' => new App\Models\CRM\Customer(),
'crm_leads' => new App\Models\CRM\Lead(),
'crm_followups' => new App\Models\CRM\FollowUp(),
'psi_suppliers' => new App\Models\PSI\Supplier(),
'psi_materials' => new App\Models\PSI\Material(),
'psi_products' => new App\Models\PSI\Product(),
'psi_purchases' => new App\Models\PSI\Purchase(),
'psi_sales' => new App\Models\PSI\Sales(),
'psi_stock_moves'=> new App\Models\PSI\StockMove(),
'orders' => new App\Models\Order(),
'payments' => new App\Models\Payment(),
];
foreach ($seed as $table => $rows) {
if (!isset($map[$table])) { $out("⊘ 跳过未映射表 {$table}(无对应 Model"); continue; }
$m = $map[$table];
foreach ($rows as $r) { $m->insert($r); }
$out("✓ 插入 {$table} (" . count($rows) . " 条)");
}
}
// 生成主题 CSS
Core\Theme::regenerate();
$out("✓ 主题样式 theme.css 已生成");
// 写安装锁(Web 模式自动写;CLI 不写,便于二次部署时手动控制)
if (!$cli) {
@file_put_contents($lock, date('Y-m-d H:i:s') . " installed by " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown') . "\n");
$out("✓ 已写入 installed.lock(再次运行 install 将被拒绝)");
}
$out("");
$out($cli ? "安装完成 ✓" : "安装完成 ✓ <p><a href='" . site_url() . "'>访问前台</a> | <a href='" . site_url('admin') . "'>进入后台</a></p>");
+108
View File
@@ -0,0 +1,108 @@
-- =============================================================
-- 酷冰甲 CMS · PSI 进销存:销售订单 / 采购订单 / 出库单 模块
-- 在已有库上执行一次即可(已存在则忽略)。
-- 说明:单据与明细分离,出库单通过 so_no / so_item_id 关联销售订单,
-- 采购订单收货时写入 psi_purchases 并增加库存,出库单扣减库存。
-- =============================================================
CREATE TABLE IF NOT EXISTS `psi_sales_orders` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`order_no` VARCHAR(40) NOT NULL,
`customer` VARCHAR(120) NOT NULL DEFAULT '',
`salesman` VARCHAR(60) NOT NULL DEFAULT '',
`channel` ENUM('domestic','export') NOT NULL DEFAULT 'domestic',
`region` VARCHAR(60) NOT NULL DEFAULT '',
`status` ENUM('pending','partial','delivered','closed') NOT NULL DEFAULT 'pending',
`delivery_date` DATE NULL,
`remark` TEXT,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_so_no` (`order_no`),
KEY `idx_so_customer` (`customer`),
KEY `idx_so_salesman` (`salesman`),
KEY `idx_so_status` (`status`),
KEY `idx_so_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_sales_order_items` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`so_id` INT UNSIGNED NOT NULL,
`product_id` INT UNSIGNED NOT NULL DEFAULT 0,
`name` VARCHAR(160) NOT NULL DEFAULT '',
`spec` VARCHAR(120) NOT NULL DEFAULT '',
`unit` VARCHAR(20) NOT NULL DEFAULT '',
`qty` INT NOT NULL DEFAULT 0,
`price` DECIMAL(12,2) NOT NULL DEFAULT 0,
`amount` DECIMAL(12,2) NOT NULL DEFAULT 0,
`delivered_qty` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_so_item_so` (`so_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_purchase_orders` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`order_no` VARCHAR(40) NOT NULL,
`supplier_id` INT UNSIGNED NOT NULL DEFAULT 0,
`supplier_name` VARCHAR(120) NOT NULL DEFAULT '',
`salesman` VARCHAR(60) NOT NULL DEFAULT '',
`status` ENUM('pending','partial','received','closed') NOT NULL DEFAULT 'pending',
`expected_at` DATE NULL,
`remark` TEXT,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_po_no` (`order_no`),
KEY `idx_po_supplier` (`supplier_id`),
KEY `idx_po_salesman` (`salesman`),
KEY `idx_po_status` (`status`),
KEY `idx_po_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_purchase_order_items` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`po_id` INT UNSIGNED NOT NULL,
`item_type` ENUM('material','product') NOT NULL DEFAULT 'material',
`item_id` INT UNSIGNED NOT NULL DEFAULT 0,
`name` VARCHAR(160) NOT NULL DEFAULT '',
`spec` VARCHAR(120) NOT NULL DEFAULT '',
`unit` VARCHAR(20) NOT NULL DEFAULT '',
`qty` INT NOT NULL DEFAULT 0,
`price` DECIMAL(12,2) NOT NULL DEFAULT 0,
`amount` DECIMAL(12,2) NOT NULL DEFAULT 0,
`received_qty` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_po_item_po` (`po_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_outbounds` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`order_no` VARCHAR(40) NOT NULL,
`so_no` VARCHAR(40) NOT NULL DEFAULT '',
`customer` VARCHAR(120) NOT NULL DEFAULT '',
`salesman` VARCHAR(60) NOT NULL DEFAULT '',
`warehouse` VARCHAR(60) NOT NULL DEFAULT '',
`status` ENUM('delivered','partial') NOT NULL DEFAULT 'delivered',
`delivery_date` DATE NULL,
`remark` TEXT,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ob_no` (`order_no`),
KEY `idx_ob_so` (`so_no`),
KEY `idx_ob_customer` (`customer`),
KEY `idx_ob_salesman` (`salesman`),
KEY `idx_ob_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_outbound_items` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`ob_id` INT UNSIGNED NOT NULL,
`so_item_id` INT UNSIGNED NOT NULL DEFAULT 0,
`product_id` INT UNSIGNED NOT NULL DEFAULT 0,
`name` VARCHAR(160) NOT NULL DEFAULT '',
`spec` VARCHAR(120) NOT NULL DEFAULT '',
`unit` VARCHAR(20) NOT NULL DEFAULT '',
`qty` INT NOT NULL DEFAULT 0,
`price` DECIMAL(12,2) NOT NULL DEFAULT 0,
`amount` DECIMAL(12,2) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_ob_item_ob` (`ob_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+308
View File
@@ -0,0 +1,308 @@
-- 酷冰甲降温服官网 MySQL 结构
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS `categories` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(120) NOT NULL,
`slug` VARCHAR(120) DEFAULT '',
`icon` VARCHAR(20) DEFAULT '',
`description` TEXT,
`sort_order` INT DEFAULT 0,
`status` TINYINT DEFAULT 1,
`layout` TEXT,
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`category_id` INT DEFAULT 0,
`name` VARCHAR(200) NOT NULL,
`slug` VARCHAR(200) DEFAULT '',
`cover` VARCHAR(255) DEFAULT '',
`summary` TEXT,
`description` TEXT,
`price` DECIMAL(10,2) DEFAULT 0,
`specs` TEXT,
`gallery` TEXT,
`tags` VARCHAR(255) DEFAULT '',
`sort_order` INT DEFAULT 0,
`status` TINYINT DEFAULT 1,
`created_at` VARCHAR(20) DEFAULT '',
`layout` TEXT,
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `news` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(200) NOT NULL,
`slug` VARCHAR(200) DEFAULT '',
`cover` VARCHAR(255) DEFAULT '',
`summary` TEXT,
`content` TEXT,
`author` VARCHAR(60) DEFAULT '',
`published_at` VARCHAR(20) DEFAULT '',
`status` TINYINT DEFAULT 1,
`views` INT DEFAULT 0,
`layout` TEXT,
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `cases` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(200) NOT NULL,
`slug` VARCHAR(200) DEFAULT '',
`customer` VARCHAR(120) DEFAULT '',
`industry` VARCHAR(60) DEFAULT '',
`cover` VARCHAR(255) DEFAULT '',
`summary` TEXT,
`content` TEXT,
`published_at` VARCHAR(20) DEFAULT '',
`sort_order` INT DEFAULT 0,
`status` TINYINT DEFAULT 1,
`views` INT DEFAULT 0,
`layout` TEXT,
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `pages` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`slug` VARCHAR(120) DEFAULT '',
`title` VARCHAR(200) DEFAULT '',
`content` TEXT,
`layout` TEXT,
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
`updated_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `banners` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(200) DEFAULT '',
`subtitle` VARCHAR(255) DEFAULT '',
`image` VARCHAR(255) DEFAULT '',
`link` VARCHAR(255) DEFAULT '',
`sort_order` INT DEFAULT 0,
`status` TINYINT DEFAULT 1
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `admin_users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(60) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`name` VARCHAR(60) DEFAULT '',
`role` VARCHAR(20) DEFAULT 'user',
`crm_role` VARCHAR(20) DEFAULT 'none',
`psi_role` VARCHAR(20) DEFAULT 'none',
`crm_perms` TEXT,
`psi_perms` TEXT,
`status` TINYINT DEFAULT 1,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/* ===================== CRM 客户管理系统 ===================== */
CREATE TABLE IF NOT EXISTS `crm_customers` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(120) NOT NULL,
`company` VARCHAR(160) DEFAULT '',
`contact` VARCHAR(60) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '',
`email` VARCHAR(120) DEFAULT '',
`country` VARCHAR(60) DEFAULT '',
`type` VARCHAR(20) DEFAULT 'brand',
`source` VARCHAR(40) DEFAULT '',
`level` VARCHAR(20) DEFAULT 'C',
`customer_no` VARCHAR(40) DEFAULT '',
`industry` VARCHAR(20) DEFAULT '',
`region` VARCHAR(40) DEFAULT '',
`credit_limit` DECIMAL(12,2) DEFAULT 0,
`status` VARCHAR(20) DEFAULT 'lead',
`remark` TEXT,
`owner` VARCHAR(60) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `crm_contacts` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT NOT NULL,
`name` VARCHAR(80) NOT NULL,
`title` VARCHAR(80) DEFAULT '',
`phone` VARCHAR(60) DEFAULT '',
`email` VARCHAR(120) DEFAULT '',
`wechat` VARCHAR(60) DEFAULT '',
`is_primary` TINYINT DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `crm_leads` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT DEFAULT 0,
`title` VARCHAR(200) NOT NULL,
`amount` DECIMAL(12,2) DEFAULT 0,
`stage` VARCHAR(20) DEFAULT 'new',
`expected_close` VARCHAR(20) DEFAULT '',
`source` VARCHAR(30) DEFAULT '',
`probability` TINYINT DEFAULT 0,
`owner` VARCHAR(60) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `crm_followups` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT DEFAULT 0,
`lead_id` INT DEFAULT 0,
`content` TEXT,
`next_at` VARCHAR(20) DEFAULT '',
`way` VARCHAR(20) DEFAULT '',
`result` VARCHAR(60) DEFAULT '',
`owner` VARCHAR(60) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/* ===================== 进销存 PSI 系统 ===================== */
CREATE TABLE IF NOT EXISTS `psi_materials` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`code` VARCHAR(40) DEFAULT '',
`name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '',
`unit` VARCHAR(10) DEFAULT '',
`category` VARCHAR(40) DEFAULT '',
`composition` VARCHAR(60) DEFAULT '',
`weight_gsm` DECIMAL(8,2) DEFAULT 0,
`width_cm` DECIMAL(8,2) DEFAULT 0,
`color` VARCHAR(40) DEFAULT '',
`batch_no` VARCHAR(40) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`supplier_id` INT DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`code` VARCHAR(40) DEFAULT '',
`name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '',
`unit` VARCHAR(10) DEFAULT '',
`category` VARCHAR(40) DEFAULT '',
`style_no` VARCHAR(40) DEFAULT '',
`color` VARCHAR(40) DEFAULT '',
`size_run` VARCHAR(60) DEFAULT '',
`season` VARCHAR(20) DEFAULT '',
`year` VARCHAR(10) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0,
`cost` DECIMAL(10,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_suppliers` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(160) NOT NULL,
`contact` VARCHAR(60) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '',
`country` VARCHAR(60) DEFAULT '',
`type` VARCHAR(20) DEFAULT '',
`grade` VARCHAR(20) DEFAULT '',
`ontime_rate` DECIMAL(5,2) DEFAULT 0,
`qc_rate` DECIMAL(5,2) DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_purchases` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL,
`supplier_id` INT DEFAULT 0,
`item_type` VARCHAR(10) DEFAULT 'material',
`item_id` INT DEFAULT 0,
`qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`amount` DECIMAL(12,2) DEFAULT 0,
`status` VARCHAR(20) DEFAULT 'pending',
`batch_no` VARCHAR(40) DEFAULT '',
`expected_at` VARCHAR(20) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL,
`customer` VARCHAR(160) DEFAULT '',
`channel` VARCHAR(20) DEFAULT 'domestic',
`item_id` INT DEFAULT 0,
`qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`amount` DECIMAL(12,2) DEFAULT 0,
`status` VARCHAR(20) DEFAULT 'pending',
`region` VARCHAR(40) DEFAULT '',
`batch_no` VARCHAR(40) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_stock_moves` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`item_type` VARCHAR(10) DEFAULT 'product',
`item_id` INT DEFAULT 0,
`direction` VARCHAR(10) DEFAULT 'in',
`qty` DECIMAL(12,2) DEFAULT 0,
`ref_no` VARCHAR(40) DEFAULT '',
`batch_no` VARCHAR(40) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `settings` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`skey` VARCHAR(120) NOT NULL,
`sval` TEXT,
`sgroup` VARCHAR(40) DEFAULT 'site'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `orders` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL,
`product_id` INT DEFAULT 0,
`product_name` VARCHAR(200) DEFAULT '',
`customer_name` VARCHAR(120) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '',
`email` VARCHAR(120) DEFAULT '',
`qty` INT DEFAULT 1,
`amount` DECIMAL(10,2) DEFAULT 0,
`channel` VARCHAR(20) DEFAULT '',
`status` VARCHAR(20) DEFAULT 'pending',
`gateway_trade_no` VARCHAR(120) DEFAULT '',
`paid_at` VARCHAR(20) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `payments` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_id` INT DEFAULT 0,
`order_no` VARCHAR(40) NOT NULL,
`channel` VARCHAR(20) DEFAULT '',
`amount` DECIMAL(10,2) DEFAULT 0,
`trade_no` VARCHAR(120) DEFAULT '',
`status` VARCHAR(20) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT '',
`paid_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_events` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`sys` VARCHAR(20) NOT NULL DEFAULT 'psi',
`type` VARCHAR(40) NOT NULL DEFAULT '',
`level` VARCHAR(20) NOT NULL DEFAULT 'urgent',
`title` VARCHAR(255) NOT NULL DEFAULT '',
`body` TEXT,
`url` VARCHAR(255) NOT NULL DEFAULT '',
`ref_no` VARCHAR(64) NOT NULL DEFAULT '',
`recipients` TEXT,
`channels` VARCHAR(255) NOT NULL DEFAULT '["inapp"]',
`read_by` TEXT,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+157
View File
@@ -0,0 +1,157 @@
<?php
/**
* 种子数据(降温服官网)
* 返回各表的初始数据数组,供 install.php 写入文件(JSON) 或 MySQL。
*/
return [
'categories' => [
['id'=>1,'name'=>'水冷循环降温服','slug'=>'water-cooling','icon'=>'💧','description'=>'内置微型水泵与循环水管,持续带走体表热量,适合长时间高温作业。','sort_order'=>1,'status'=>1],
['id'=>2,'name'=>'相变蓄冷凝胶服','slug'=>'pcm-gel','icon'=>'🧊','description'=>'相变材料(PCM)蓄冷凝胶贴片,无需电源,即穿即凉,轻便无束缚。','sort_order'=>2,'status'=>1],
['id'=>3,'name'=>'涡扇风冷降温服','slug'=>'air-cooling','icon'=>'🌀','description'=>'双涡扇主动送风,加速汗液蒸发,体感直降 8-12℃。','sort_order'=>3,'status'=>1],
['id'=>4,'name'=>'冰袋降温马甲','slug'=>'ice-vest','icon'=>'❄️','description'=>'可替换冰袋/冰晶盒马甲,低成本高效降温,户外与车间通用。','sort_order'=>4,'status'=>1],
['id'=>5,'name'=>'工业降温工作服','slug'=>'industrial','icon'=>'🏭','description'=>'面向钢铁、消防、化工等高温行业的模块化降温工装。','sort_order'=>5,'status'=>1],
['id'=>6,'name'=>'户外清凉服饰','slug'=>'outdoor','icon'=>'🌿','description'=>'骑行、马拉松、巡检等户外场景的轻量降温装备。','sort_order'=>6,'status'=>1],
],
'products' => [
['id'=>1,'category_id'=>1,'name'=>'SQY- Pro 水冷降温套装','slug'=>'sqy-pro-water','cover'=>'','summary'=>'医用级硅胶水管 + 5000mAh 续航,4 档调速,体感直降 10℃。','description'=>"SQY-Pro 水冷降温套装采用分布式毛细水管贴合躯干大血管区域,微型静音水泵驱动冷却液循环,将体表热量高效导出。\n\n· 4 档风速/水速调节,单次续航 6-8 小时\n· 食品级 TPU 水管,亲肤无异味\n· 外套可拆洗,内胆防水防漏\n· 适用:钢铁、焊接、消防、厨房高温区",'price'=>'1299.00','specs'=>'[{"k":"降温方式","v":"水冷循环"},{"k":"续航","v":"6-8 小时"},{"k":"净重","v":"约 1.2kg"},{"k":"档位","v":"4 档可调"},{"k":"适配温度","v":"≤ 45℃ 环境"}]','gallery'=>'[]','tags'=>'水冷,Pro,长续航','sort_order'=>1,'status'=>1,'created_at'=>'2026-03-12'],
['id'=>2,'category_id'=>2,'name'=>'冰晶凝胶蓄冷降温背心','slug'=>'gel-vest','cover'=>'','summary'=>'30 秒速冻,单片蓄冷 2 小时,免电源即穿即凉。','description'=>"采用高分子相变蓄冷凝胶贴片,放入冰箱/冰柜 30 分钟即可凝固,穿着后缓慢相变吸热,无需电池。\n\n· 前后 8 片凝胶,覆盖核心降温区\n· 单片蓄冷时长约 2 小时,可快速更换\n· 马甲式设计,不影响作业动作\n· 适用:户外巡检、物流分拣、赛事保障",'price'=>'399.00','specs'=>'[{"k":"降温方式","v":"相变蓄冷"},{"k":"蓄冷时长","v":"约 2 小时/片"},{"k":"凝胶片","v":"前后 8 片"},{"k":"电源","v":"无需电源"},{"k":"清洗","v":"马甲可水洗"}]','gallery'=>'[]','tags'=>'凝胶,免电源,轻便','sort_order'=>2,'status'=>1,'created_at'=>'2026-03-15'],
['id'=>3,'category_id'=>3,'name'=>'双涡扇风冷降温马甲','slug'=>'fan-vest','cover'=>'','summary'=>'前后双涡扇主动送风,体感直降 8-12℃,USB 供电。','description'=>"前后布置高能效涡扇,将外部空气过滤后送入服装夹层,加速汗液蒸发与对流换热。\n\n· 双涡扇独立开关,3 档风力\n· USB/充电宝供电,移动便捷\n· 网眼透气里料,久穿不闷\n· 适用:建筑、环卫、骑行、军训",'price'=>'299.00','specs'=>'[{"k":"降温方式","v":"涡扇风冷"},{"k":"风力","v":"3 档可调"},{"k":"供电","v":"USB / 充电宝"},{"k":"体感降温","v":"8-12℃"},{"k":"净重","v":"约 0.6kg"}]','gallery'=>'[]','tags'=>'风冷,USB,轻便','sort_order'=>3,'status'=>1,'created_at'=>'2026-03-18'],
['id'=>4,'category_id'=>4,'name'=>'可换冰袋降温马甲','slug'=>'ice-bag-vest','cover'=>'','summary'=>'6 个独立冰袋仓,低成本高效降温,户外车间通用。','description'=>"经典冰袋式降温马甲,6 个独立密封冰袋仓,放入冰晶盒即可使用,性价比之选。\n\n· 前后 6 仓均匀分布,降温均衡\n· 冰袋可反复冻用,损耗低\n· 反光条设计,夜间作业更安全\n· 适用:仓储、农业、临时户外作业",'price'=>'159.00','specs'=>'[{"k":"降温方式","v":"冰袋蓄冷"},{"k":"冰袋仓","v":"6 个独立仓"},{"k":"电源","v":"无需电源"},{"k":"安全","v":"反光条"},{"k":"价格","v":"高性价比"}]','gallery'=>'[]','tags'=>'冰袋,性价比,通用','sort_order'=>4,'status'=>1,'created_at'=>'2026-03-20'],
['id'=>5,'category_id'=>5,'name'=>'工业模块化降温工装','slug'=>'industrial-suit','cover'=>'','summary'=>'为钢铁/消防/化工定制的模块化降温防护服,可集成多种降温芯。','description'=>"面向高温高危行业的模块化降温工装,外层阻燃耐磨,内层可插拔水冷/凝胶/冰袋降温芯,按岗位灵活组合。\n\n· 阻燃防静电外层,符合工装标准\n· 降温芯可插拔替换,一衣多用\n· 多处工具挂点,贴合作业习惯\n· 适用:钢铁、消防、化工、冶炼",'price'=>'1899.00','specs'=>'[{"k":"降温方式","v":"模块化可换芯"},{"k":"外层","v":"阻燃防静电"},{"k":"适配芯","v":"水冷/凝胶/冰袋"},{"k":"定制","v":"支持企业 LOGO 绣字"},{"k":"标准","v":"符合工装规范"}]','gallery'=>'[]','tags'=>'工业,阻燃,定制','sort_order'=>5,'status'=>1,'created_at'=>'2026-03-22'],
['id'=>6,'category_id'=>6,'name'=>'户外轻量降温皮肤衣','slug'=>'skin-coat','cover'=>'','summary'=>'UPF50+ 防晒 + 背部风冷,骑行马拉松巡检必备。','description'=>"超轻防晒皮肤衣集成背部微型风冷模块,UPF50+ 防晒同时主动降温,折叠后仅手掌大小。\n\n· UPF50+ 防晒,透气速干\n· 背部风冷模块,体感更清爽\n· 整衣可收纳,便携出行\n· 适用:骑行、马拉松、户外巡检",'price'=>'259.00','specs'=>'[{"k":"防晒","v":"UPF50+"},{"k":"降温方式","v":"背部风冷"},{"k":"收纳","v":"手掌大小"},{"k":"重量","v":"约 180g"},{"k":"场景","v":"户外轻运动"}]','gallery'=>'[]','tags'=>'户外,防晒,轻量','sort_order'=>6,'status'=>1,'created_at'=>'2026-03-25'],
['id'=>7,'category_id'=>1,'name'=>'SQY-Lite 水冷降温内胆','slug'=>'sqy-lite','cover'=>'','summary'=>'可嵌入现有工装的水冷内胆,升级不加衣。','description'=>"独立水冷内胆,可穿在任意工装内侧,让既有服装秒变降温服,降低整体采购成本。\n\n· 弹性贴合,适配多数尺码工装\n· 微型水泵静音,续航 5 小时\n· 内胆防水,外衣照常清洗\n· 适用:已有工装升级、分批改造",'price'=>'899.00','specs'=>'[{"k":"类型","v":"水冷内胆"},{"k":"续航","v":"约 5 小时"},{"k":"适配","v":"多数工装"},{"k":"噪声","v":"< 30dB"},{"k":"升级","v":"不加衣即可降温"}]','gallery'=>'[]','tags'=>'内胆,升级,静音','sort_order'=>7,'status'=>1,'created_at'=>'2026-03-28'],
['id'=>8,'category_id'=>3,'name'=>'头颈一体风冷降温帽','slug'=>'cool-cap','cover'=>'','summary'=>'头部+颈部环绕送风,快速缓解中暑前兆。','description'=>"针对头部高温聚集设计的头颈一体风冷帽,环绕送风快速带走头颈热量,预防中暑。\n\n· 头颈双区送风,降温更均衡\n· 可拆洗内衬,卫生耐用\n· Type-C 充电,续航 4 小时\n· 适用:交警、巡检、户外指挥",'price'=>'199.00','specs'=>'[{"k":"降温方式","v":"头颈风冷"},{"k":"续航","v":"约 4 小时"},{"k":"充电","v":"Type-C"},{"k":"清洗","v":"内衬可拆洗"},{"k":"场景","v":"高温户外值守"}]','gallery'=>'[]','tags'=>'头颈,防暑,便携','sort_order'=>8,'status'=>1,'created_at'=>'2026-04-01'],
],
'banners' => [
['id'=>1,'title'=>'科技降温 · 清凉一夏','subtitle'=>'相变蓄冷 / 水冷循环 / 涡扇风冷,为高温作业人群定制','image'=>'linear-gradient(135deg,#0ea5e9,#14b8a6)','link'=>'/products','sort_order'=>1,'status'=>1],
['id'=>2,'title'=>'20 年服装定制经验','subtitle'=>'外贸级品质工厂,支持企业 LOGO 绣字与一人一码量体','image'=>'linear-gradient(135deg,#0284c7,#0ea5e9)','link'=>'/page/about','sort_order'=>2,'status'=>1],
['id'=>3,'title'=>'免费拿样 · 5 天出方案','subtitle'=>'提交需求,专属顾问 1 对 1 为您设计降温解决方案','image'=>'linear-gradient(135deg,#14b8a6,#f59e0b)','link'=>'/contact','sort_order'=>3,'status'=>1],
],
'news' => [
['id'=>1,'title'=>'酷冰甲发布新一代水冷降温服 SQY-Pro,体感直降 10℃','slug'=>'sqy-pro-launch','cover'=>'','summary'=>'采用分布式毛细水管与静音水泵,单次续航提升至 8 小时。','content'=>"近日,酷冰甲正式发布新一代水冷降温服 SQY-Pro。该产品采用分布式毛细水管贴合躯干大血管区域,配合微型静音水泵驱动冷却液循环,将体表热量高效导出,体感温度可直降 10℃。\n\n研发团队表示,SQY-Pro 在续航、重量与舒适度上均有显著突破,单次充电可连续工作 8 小时,整机重量控制在 1.2kg 以内,更适合长时间高温作业场景。",'author'=>'酷冰甲','published_at'=>'2026-04-10','status'=>1,'views'=>128],
['id'=>2,'title'=>'夏季高温作业防护指南:如何科学选择降温服','slug'=>'summer-guide','cover'=>'','summary'=>'从降温原理到场景适配,一文读懂水冷、凝胶、风冷怎么选。','content'=>"随着极端高温天气增多,户外与车间作业人员的防暑降温成为关注焦点。本文从降温原理出发,对比水冷循环、相变蓄冷、涡扇风冷三类方案的适用场景,帮助企业根据自身岗位特点科学选型。\n\n· 长时间恒温作业:优先水冷循环\n· 临时/移动作业:凝胶或冰袋更灵活\n· 户外轻运动:风冷皮肤衣更轻便",'author'=>'酷冰甲','published_at'=>'2026-04-05','status'=>1,'views'=>96],
['id'=>3,'title'=>'酷冰甲为某钢铁集团交付模块化降温工装','slug'=>'steel-case','cover'=>'','summary'=>'支持阻燃外层 + 可换降温芯,获一线员工好评。','content'=>"日前,酷冰甲完成对某大型钢铁集团的模块化降温工装交付。该批工装采用阻燃防静电外层,内层可插拔水冷/凝胶降温芯,按岗位灵活组合,获得一线员工与安全管理部分的一致好评。",'author'=>'酷冰甲','published_at'=>'2026-03-30','status'=>1,'views'=>74],
['id'=>4,'title'=>'相变蓄冷技术原理科普:为什么凝胶背心能"自动降温"','slug'=>'pcm-science','cover'=>'','summary'=>'揭秘相变材料(PCM)如何在不耗电的情况下持续吸热。','content'=>"相变材料(PCM)在一定温度区间内会发生固-液相变并吸收大量潜热。凝胶背心正是利用这一特性,在凝固状态下穿着时缓慢相变吸热,从而在不耗电的情况下实现持续降温。本文带你读懂背后的科学。",'author'=>'酷冰甲','published_at'=>'2026-03-22','status'=>1,'views'=>61],
],
'cases' => [
['id'=>1,'title'=>'某大型钢铁集团模块化降温工装交付','slug'=>'steel-group-cases','customer'=>'某大型钢铁集团','industry'=>'钢铁冶炼','cover'=>'','summary'=>'阻燃外层 + 可换降温芯,覆盖高炉、轧线等高温岗位,获一线员工好评。','content'=>"日前,酷冰甲完成对某大型钢铁集团的模块化降温工装批量交付。该批工装采用阻燃防静电外层,内层可插拔水冷 / 凝胶 / 冰袋降温芯,按岗位灵活组合,覆盖高炉、轧线、铸造等核心高温岗位。\n\n交付后,一线员工体感温度明显下降,安全管理部对降温效果与穿着舒适度给予一致好评,并表示将在更多分厂推广使用。",'published_at'=>'2026-03-30','sort_order'=>1,'status'=>1,'views'=>0],
['id'=>2,'title'=>'某消防救援支队头颈一体风冷降温装备','slug'=>'fire-rescue-cases','customer'=>'某地消防救援支队','industry'=>'消防救援','cover'=>'','summary'=>'头颈双区环绕送风,快速缓解中暑前兆,保障高温救援。','content'=>"针对夏季高温救援与训练场景,酷冰甲为某消防救援支队定制头颈一体风冷降温装备。该装备头颈双区环绕送风,Type-C 快充、续航 4 小时,可拆洗内衬卫生耐用,显著缓解指战员中暑前兆,保障长时间高温救援作业安全。",'published_at'=>'2026-04-02','sort_order'=>2,'status'=>1,'views'=>0],
['id'=>3,'title'=>'某化工企业相变蓄冷凝胶背心','slug'=>'chemical-gel-cases','customer'=>'某化工生产企业','industry'=>'化工生产','cover'=>'','summary'=>'免电源即穿即凉,30 秒速冻、单片蓄冷 2 小时,巡检更安心。','content'=>"某化工生产企业为巡检与检修岗位引入酷冰甲相变蓄冷凝胶背心。产品免电源、30 秒速冻、单片蓄冷约 2 小时,可快速更换,马甲式设计不影响作业动作,让一线员工在罐区、管线等高温区域巡检更安心。",'published_at'=>'2026-04-06','sort_order'=>3,'status'=>1,'views'=>0],
['id'=>4,'title'=>'某环卫集团涡扇风冷马甲批量定制','slug'=>'sanitation-fan-cases','customer'=>'某城市环卫集团','industry'=>'环卫保洁','cover'=>'','summary'=>'USB 供电、3 档风力,覆盖道路保洁与垃圾转运岗位。','content'=>"某城市环卫集团批量定制酷冰甲双涡扇风冷降温马甲,USB / 充电宝即可供电,3 档风力可调,覆盖道路保洁、垃圾转运等户外岗位。轻量透气、反光线条提升夜间作业安全,获得环卫工人的普遍认可。",'published_at'=>'2026-04-12','sort_order'=>4,'status'=>1,'views'=>0],
],
'pages' => [
['id'=>1,'slug'=>'about','title'=>'关于酷冰甲','content'=>"<p>苏州酷冰甲服饰有限公司拥有 20 年服装行业经验,从事职业装内销与外贸,专注高温作业人群的降温服装研发与定制。</p><p>公司具备完整、科学的质量管理体系,生产工厂具有多年外贸代工经验,引进德国进口设备,按欧美外贸级别标准出货。我们为钢铁、消防、化工、环卫、物流、户外等行业提供整体降温服装解决方案。</p><p>我们坚持「柔性化生产、一人一码、量身定制」,10 套起订,交付后提供包换包修与免费保养指导,让客户的权益得到保障。</p>",'layout'=>'','updated_at'=>'2026-04-01'],
['id'=>2,'slug'=>'service','title'=>'服务与优势','content'=>"<p><b>柔性化生产</b>:小单亦可定制,10 套起订,灵活补单。</p><p><b>量身打造</b>:设计师结合企业文化与功能需求定向设计,5 天出具方案。</p><p><b>一人一码</b>:资深打版师打板、上门量体,高度还原设计稿,合身合体。</p><p><b>外贸级品质</b>:156 道工序层层把控,欧美出口级标准。</p><p><b>售后无忧</b>:交付 3 个月内包换包修改,2 年内免费返修,免费教授日常保养。</p>",'layout'=>'','updated_at'=>'2026-04-01'],
['id'=>3,'slug'=>'cases','title'=>'客户案例','content'=>"<p>众多企事业单位选择了酷冰甲降温服装定制服务,覆盖钢铁冶炼、消防救援、化工生产、环卫保洁、物流仓储、户外赛事等场景。</p><p>我们提供从需求沟通、上门量体、方案设计、批量生产到成衣交付的全流程服务,并支持企业 LOGO 绣字与个性化定制。</p>",'layout'=>'','updated_at'=>'2026-04-01'],
['id'=>4,'slug'=>'honor','title'=>'荣誉资质','content'=>"<p>酷冰甲先后获得行业多项荣誉与资质认证,包括质量管理体系认证、外贸级生产资质及多家机构颁发的合作荣誉。</p><p>我们持续以品质与客户利益为先,售后及时响应客户反馈,10 秒接通,为客户解决问题。</p>",'layout'=>'','updated_at'=>'2026-04-01'],
],
'admin_users' => [
['id'=>1,'username'=>'admin','password'=>password_hash('admin888', PASSWORD_DEFAULT),'name'=>'超级管理员','role'=>'super_admin','crm_role'=>'admin','psi_role'=>'admin','status'=>1,'created_at'=>'2026-01-01'],
['id'=>2,'username'=>'editor','password'=>password_hash('editor888', PASSWORD_DEFAULT),'name'=>'内容管理员','role'=>'admin','status'=>1,'created_at'=>'2026-01-01'],
['id'=>3,'username'=>'writer','password'=>password_hash('writer888', PASSWORD_DEFAULT),'name'=>'编辑员','role'=>'user','status'=>1,'created_at'=>'2026-01-01'],
],
'settings' => [
['skey'=>'site_name','sval'=>'酷冰甲 · 降温服','sgroup'=>'site'],
['skey'=>'site_slogan','sval'=>'科技降温 · 清凉一夏','sgroup'=>'site'],
['skey'=>'contact_phone','sval'=>'400-1783-998','sgroup'=>'site'],
['skey'=>'contact_email','sval'=>'service@st-joyapparel.com','sgroup'=>'site'],
['skey'=>'contact_address','sval'=>'江苏省苏州市工业园区','sgroup'=>'site'],
['skey'=>'icp','sval'=>'苏ICP备10206899号','sgroup'=>'site'],
['skey'=>'seo_title','sval'=>'酷冰甲降温服 - 科技降温服装定制','sgroup'=>'site'],
['skey'=>'seo_keywords','sval'=>'降温服,降温工作服,水冷降温服,相变蓄冷凝胶服,清凉服定制','sgroup'=>'site'],
['skey'=>'seo_description','sval'=>'酷冰甲专注降温服研发与定制,采用相变蓄冷与循环水冷技术,为高温作业人群提供清凉解决方案。','sgroup'=>'site'],
['skey'=>'preset','sval'=>'ocean','sgroup'=>'theme'],
['skey'=>'primary','sval'=>'#0ea5e9','sgroup'=>'theme'],
['skey'=>'primary_600','sval'=>'#0284c7','sgroup'=>'theme'],
['skey'=>'secondary','sval'=>'#14b8a6','sgroup'=>'theme'],
['skey'=>'accent','sval'=>'#f59e0b','sgroup'=>'theme'],
['skey'=>'bg','sval'=>'#ffffff','sgroup'=>'theme'],
['skey'=>'surface','sval'=>'#f8fafc','sgroup'=>'theme'],
['skey'=>'text','sval'=>'#0f172a','sgroup'=>'theme'],
['skey'=>'muted','sval'=>'#64748b','sgroup'=>'theme'],
['skey'=>'border','sval'=>'#e2e8f0','sgroup'=>'theme'],
['skey'=>'nav_bg','sval'=>'rgba(255,255,255,0.72)','sgroup'=>'theme'],
['skey'=>'font','sval'=>"'Noto Sans SC', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",'sgroup'=>'theme'],
['skey'=>'radius','sval'=>'16','sgroup'=>'theme'],
['skey'=>'container','sval'=>'1200','sgroup'=>'theme'],
['skey'=>'header','sval'=>'center','sgroup'=>'theme'],
['skey'=>'default_mode','sval'=>'light','sgroup'=>'theme'],
['skey'=>'custom_css','sval'=>'','sgroup'=>'theme'],
['skey'=>'pay_enabled','sval'=>'1','sgroup'=>'pay'],
['skey'=>'pay_mode','sval'=>'demo','sgroup'=>'pay'],
['skey'=>'pay_alipay_appid','sval'=>'','sgroup'=>'pay'],
['skey'=>'pay_alipay_private_key','sval'=>'','sgroup'=>'pay'],
['skey'=>'pay_alipay_public_key','sval'=>'','sgroup'=>'pay'],
['skey'=>'pay_alipay_gateway','sval'=>'https://openapi.alipay.com/gateway.do','sgroup'=>'pay'],
['skey'=>'pay_wechat_mchid','sval'=>'','sgroup'=>'pay'],
['skey'=>'pay_wechat_appid','sval'=>'','sgroup'=>'pay'],
['skey'=>'pay_wechat_key','sval'=>'','sgroup'=>'pay'],
// 事件通知(邮件 + 企业微信)
['skey'=>'notify_enabled','sval'=>'0','sgroup'=>'notify'],
['skey'=>'notify_email_enabled','sval'=>'0','sgroup'=>'notify'],
['skey'=>'notify_email_smtp_host','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_email_smtp_port','sval'=>'465','sgroup'=>'notify'],
['skey'=>'notify_email_smtp_user','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_email_smtp_pass','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_email_from','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_email_to','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_wechat_enabled','sval'=>'0','sgroup'=>'notify'],
['skey'=>'notify_wechat_webhook','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_wechat_mention','sval'=>'','sgroup'=>'notify'],
['skey'=>'notify_lowstock_enabled','sval'=>'1','sgroup'=>'notify'],
['skey'=>'notify_lowstock_threshold','sval'=>'20','sgroup'=>'notify'],
],
'orders' => [],
'payments' => [],
/* ===================== CRM 客户管理(示例数据)===================== */
'crm_customers' => [
['id'=>1,'name'=>'张明','company'=>'苏州恒利纺织有限公司','contact'=>'张经理','phone'=>'13800001111','email'=>'zhang@hengli.com','country'=>'中国','type'=>'trade','source'=>'转介绍','level'=>'A','remark'=>'年采购面料约 50 万米,信用良好','owner'=>'admin','created_at'=>'2026-03-10'],
['id'=>2,'name'=>'John Smith','company'=>'Global Apparel Importers Ltd','contact'=>'John','phone'=>'+1-415-555-0199','email'=>'john@globalapparel.com','country'=>'美国','type'=>'export','source'=>'展会','level'=>'A','remark'=>'北美户外品牌采购商,首单预计 3000 件','owner'=>'admin','created_at'=>'2026-03-15'],
['id'=>3,'name'=>'李婷','company'=>'杭州清凉服饰连锁','contact'=>'李店长','phone'=>'13900002222','email'=>'','country'=>'中国','type'=>'retail','source'=>'官网','level'=>'B','remark'=>'长三角 12 家门店,夏季终端零售','owner'=>'admin','created_at'=>'2026-04-02'],
],
'crm_leads' => [
['id'=>1,'customer_id'=>2,'title'=>'SQY-Pro 水冷套装出口订单','amount'=>389700.00,'stage'=>'negotiation','expected_close'=>'2026-08-30','owner'=>'admin','remark'=>'客户要求 CE 认证,已提供','created_at'=>'2026-05-10'],
['id'=>2,'customer_id'=>1,'title'=>'冰丝面料年度框架','amount'=>900000.00,'stage'=>'proposal','expected_close'=>'2026-09-15','owner'=>'admin','remark'=>'需寄样确认色牢度','created_at'=>'2026-05-20'],
['id'=>3,'customer_id'=>3,'title'=>'门店夏季补货','amount'=>60000.00,'stage'=>'new','expected_close'=>'2026-06-30','owner'=>'admin','remark'=>'','created_at'=>'2026-05-25'],
],
'crm_followups' => [
['id'=>1,'customer_id'=>2,'lead_id'=>1,'content'=>'邮件确认 CE 证书已收到,进入价格谈判','next_at'=>'2026-07-30','owner'=>'admin','created_at'=>'2026-07-01'],
['id'=>2,'customer_id'=>1,'lead_id'=>2,'content'=>'寄出冰丝面料样品 3 色,跟进回传检测报告','next_at'=>'2026-07-28','owner'=>'admin','created_at'=>'2026-07-05'],
],
/* ===================== 进销存 PSI(示例数据)===================== */
'psi_suppliers' => [
['id'=>1,'name'=>'苏州恒利纺织有限公司','contact'=>'张经理','phone'=>'13800001111','country'=>'中国','remark'=>'主营冰丝、相变面料,交期稳定','created_at'=>'2026-03-10'],
['id'=>2,'name'=>'Shenzhen CoolTech Electronics','contact'=>'Tony','phone'=>'+86-755-8888-0011','country'=>'中国','remark'=>'双涡扇模组、PCBA 供应商','created_at'=>'2026-03-12'],
],
'psi_materials' => [
['id'=>1,'code'=>'M001','name'=>'冰丝降温面料','spec'=>'75D 平纹','unit'=>'米','category'=>'面料','stock'=>500.00,'price'=>18.00,'supplier_id'=>1,'remark'=>'主面料','created_at'=>'2026-03-10'],
['id'=>2,'code'=>'M002','name'=>'PCM 蓄冷凝胶片','spec'=>'5mm 网格','unit'=>'片','category'=>'辅料','stock'=>300.00,'price'=>6.50,'supplier_id'=>0,'remark'=>'相变材料','created_at'=>'2026-03-12'],
['id'=>3,'code'=>'M003','name'=>'双涡扇模组','spec'=>'DC5V 0.25A','unit'=>'个','category'=>'电子件','stock'=>200.00,'price'=>45.00,'supplier_id'=>2,'remark'=>'风冷核心','created_at'=>'2026-03-12'],
],
'psi_products' => [
['id'=>1,'code'=>'P001','name'=>'SQY-Pro 水冷降温套装','spec'=>'4 档调速','unit'=>'件','category'=>'水冷','stock'=>70.00,'cost'=>720.00,'price'=>1299.00,'remark'=>'旗舰款','created_at'=>'2026-03-15'],
['id'=>2,'code'=>'P002','name'=>'冰晶凝胶蓄冷背心','spec'=>'8 片凝胶','unit'=>'件','category'=>'相变','stock'=>200.00,'cost'=>180.00,'price'=>399.00,'remark'=>'免电源','created_at'=>'2026-03-18'],
['id'=>3,'code'=>'P003','name'=>'双涡扇风冷马甲','spec'=>'双涡扇 3 档','unit'=>'件','category'=>'风冷','stock'=>150.00,'cost'=>140.00,'price'=>299.00,'remark'=>'USB 供电','created_at'=>'2026-03-20'],
],
'psi_purchases' => [
['id'=>1,'order_no'=>'PO2026-001','supplier_id'=>1,'item_type'=>'material','item_id'=>1,'qty'=>200.00,'price'=>18.00,'amount'=>3600.00,'status'=>'received','remark'=>'期初采购','created_at'=>'2026-03-20'],
['id'=>2,'order_no'=>'PO2026-002','supplier_id'=>2,'item_type'=>'material','item_id'=>3,'qty'=>100.00,'price'=>45.00,'amount'=>4500.00,'status'=>'pending','remark'=>'待交货','created_at'=>'2026-06-10'],
],
'psi_sales' => [
['id'=>1,'order_no'=>'SO2026-001','customer'=>'某钢铁集团','channel'=>'domestic','item_id'=>1,'qty'=>30.00,'price'=>1299.00,'amount'=>38970.00,'status'=>'shipped','remark'=>'首批交付','created_at'=>'2026-05-15'],
['id'=>2,'order_no'=>'SO2026-002','customer'=>'Global Apparel Importers Ltd','channel'=>'export','item_id'=>2,'qty'=>50.00,'price'=>399.00,'amount'=>19950.00,'status'=>'pending','remark'=>'信用证待开','created_at'=>'2026-06-20'],
],
'psi_stock_moves' => [
['id'=>1,'item_type'=>'material','item_id'=>1,'direction'=>'in','qty'=>300.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-10'],
['id'=>2,'item_type'=>'material','item_id'=>1,'direction'=>'in','qty'=>200.00,'ref_no'=>'PO2026-001','remark'=>'采购入库','created_at'=>'2026-03-20'],
['id'=>3,'item_type'=>'material','item_id'=>2,'direction'=>'in','qty'=>300.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-12'],
['id'=>4,'item_type'=>'material','item_id'=>3,'direction'=>'in','qty'=>200.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-12'],
['id'=>5,'item_type'=>'product','item_id'=>1,'direction'=>'in','qty'=>100.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-15'],
['id'=>6,'item_type'=>'product','item_id'=>1,'direction'=>'out','qty'=>30.00,'ref_no'=>'SO2026-001','remark'=>'销售出库','created_at'=>'2026-05-15'],
['id'=>7,'item_type'=>'product','item_id'=>2,'direction'=>'in','qty'=>200.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-18'],
['id'=>8,'item_type'=>'product','item_id'=>3,'direction'=>'in','qty'=>150.00,'ref_no'=>'INIT','remark'=>'期初入库','created_at'=>'2026-03-20'],
],
];
+139
View File
@@ -0,0 +1,139 @@
-- 酷冰甲 CMS 升级脚本:新增 CRM(客户管理)与 PSI(进销存)模块
-- 用法:在远端 MySQL 执行本文件(phpMyAdmin / 命令行均可)。
-- 幂等,可重复执行;兼容 MySQL 5.7 与 8.05.7 不支持 ADD COLUMN IF NOT EXISTS,故用存储过程判断)。
SET NAMES utf8mb4;
/* ===================== CRM 客户管理系统 ===================== */
CREATE TABLE IF NOT EXISTS `crm_customers` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(120) NOT NULL,
`company` VARCHAR(160) DEFAULT '',
`contact` VARCHAR(60) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '',
`email` VARCHAR(120) DEFAULT '',
`country` VARCHAR(60) DEFAULT '',
`type` VARCHAR(20) DEFAULT 'trade',
`source` VARCHAR(40) DEFAULT '',
`level` VARCHAR(20) DEFAULT 'C',
`remark` TEXT,
`owner` VARCHAR(60) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `crm_leads` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT DEFAULT 0,
`title` VARCHAR(200) NOT NULL,
`amount` DECIMAL(12,2) DEFAULT 0,
`stage` VARCHAR(20) DEFAULT 'new',
`expected_close` VARCHAR(20) DEFAULT '',
`owner` VARCHAR(60) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `crm_followups` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT DEFAULT 0,
`lead_id` INT DEFAULT 0,
`content` TEXT,
`next_at` VARCHAR(20) DEFAULT '',
`owner` VARCHAR(60) DEFAULT '',
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/* ===================== 进销存 PSI 系统 ===================== */
CREATE TABLE IF NOT EXISTS `psi_materials` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`code` VARCHAR(40) DEFAULT '',
`name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '',
`unit` VARCHAR(10) DEFAULT '',
`category` VARCHAR(40) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`supplier_id` INT DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`code` VARCHAR(40) DEFAULT '',
`name` VARCHAR(160) NOT NULL,
`spec` VARCHAR(120) DEFAULT '',
`unit` VARCHAR(10) DEFAULT '',
`category` VARCHAR(40) DEFAULT '',
`stock` DECIMAL(12,2) DEFAULT 0,
`cost` DECIMAL(10,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_suppliers` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(160) NOT NULL,
`contact` VARCHAR(60) DEFAULT '',
`phone` VARCHAR(40) DEFAULT '',
`country` VARCHAR(60) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_purchases` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL,
`supplier_id` INT DEFAULT 0,
`item_type` VARCHAR(10) DEFAULT 'material',
`item_id` INT DEFAULT 0,
`qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`amount` DECIMAL(12,2) DEFAULT 0,
`status` VARCHAR(20) DEFAULT 'pending',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL,
`customer` VARCHAR(160) DEFAULT '',
`channel` VARCHAR(20) DEFAULT 'domestic',
`item_id` INT DEFAULT 0,
`qty` DECIMAL(12,2) DEFAULT 0,
`price` DECIMAL(10,2) DEFAULT 0,
`amount` DECIMAL(12,2) DEFAULT 0,
`status` VARCHAR(20) DEFAULT 'pending',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `psi_stock_moves` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`item_type` VARCHAR(10) DEFAULT 'product',
`item_id` INT DEFAULT 0,
`direction` VARCHAR(10) DEFAULT 'in',
`qty` DECIMAL(12,2) DEFAULT 0,
`ref_no` VARCHAR(40) DEFAULT '',
`remark` TEXT,
`created_at` VARCHAR(20) DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/* 为 admin_users 补齐分系统角色列(幂等,兼容 5.7) */
DROP PROCEDURE IF EXISTS `add_crm_psi_cols`;
DELIMITER $$
CREATE PROCEDURE `add_crm_psi_cols`()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='admin_users' AND COLUMN_NAME='crm_role') THEN
ALTER TABLE `admin_users` ADD COLUMN `crm_role` VARCHAR(20) DEFAULT 'none';
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='admin_users' AND COLUMN_NAME='psi_role') THEN
ALTER TABLE `admin_users` ADD COLUMN `psi_role` VARCHAR(20) DEFAULT 'none';
END IF;
END$$
DELIMITER ;
CALL `add_crm_psi_cols`();
DROP PROCEDURE IF EXISTS `add_crm_psi_cols`;
-- 升级完成后,登录后台 → 用户管理,将超级管理员/相关账号的 crm_role、psi_role 设为 admin。
@@ -0,0 +1,200 @@
-- ============================================================
-- PSI 订单/出库与业务表建表 —— 服装厂成衣标准
-- ============================================================
-- 包含:销售订单、采购订单、出库单 共 6 张表
-- + 修复 psi_purchases 缺少列
-- 各表均已补齐品牌/款号/色号/尺码明细/箱重/体积等成衣行业必备字段
-- ============================================================
-- -------------------------------------------
-- 1. 销售订单主表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_sales_orders` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL COMMENT '订单编号 SO+年月日+流水',
`customer` VARCHAR(100) NOT NULL COMMENT '客户名称',
`customer_po` VARCHAR(80) DEFAULT '' COMMENT '客户采购单号(国际成衣贸易必备)',
`brand` VARCHAR(100) DEFAULT '' COMMENT '品牌',
`salesman` VARCHAR(50) DEFAULT '' COMMENT '业务员',
`channel` VARCHAR(20) DEFAULT 'domestic' COMMENT '销售渠道 domestic/export',
`region` VARCHAR(60) DEFAULT '' COMMENT '销售区域',
`currency` VARCHAR(10) DEFAULT 'CNY' COMMENT '币种 CNY/USD/EUR',
`payment_terms` VARCHAR(50) DEFAULT '' COMMENT '付款条件 T/T,L/C,D/P,OA',
`incoterm` VARCHAR(10) DEFAULT '' COMMENT '贸易术语 FOB/CIF/EXW/CFR/DDP',
`shipping_mark` VARCHAR(200) DEFAULT '' COMMENT '唛头',
`style_count` INT DEFAULT 0 COMMENT '款数',
`total_qty` INT DEFAULT 0 COMMENT '总数量',
`total_amount` DECIMAL(12,2) DEFAULT 0 COMMENT '总金额',
`delivery_date` VARCHAR(20) DEFAULT '' COMMENT '预计交付日期',
`remark` TEXT COMMENT '备注',
`status` VARCHAR(20) DEFAULT 'pending' COMMENT '状态 pending/partial/delivered/closed',
`created_at` VARCHAR(20) DEFAULT '' COMMENT '创建时间',
`updated_at` VARCHAR(20) DEFAULT '' COMMENT '最后修改时间',
INDEX `idx_so_customer` (`customer`),
INDEX `idx_so_salesman` (`salesman`),
INDEX `idx_so_status` (`status`),
INDEX `idx_so_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='销售订单主表';
-- -------------------------------------------
-- 2. 销售订单明细表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_sales_order_items` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`so_id` INT NOT NULL COMMENT '关联销售订单ID',
`product_id` INT DEFAULT 0 COMMENT '关联成品ID',
`style_no` VARCHAR(60) DEFAULT '' COMMENT '款号/货号',
`name` VARCHAR(120) NOT NULL COMMENT '商品名称',
`spec` VARCHAR(100) DEFAULT '' COMMENT '规格',
`color_code` VARCHAR(30) DEFAULT '' COMMENT '色号',
`size_detail` TEXT COMMENT '尺码明细 JSON [{size:\"S\",qty:100},...]',
`unit` VARCHAR(20) DEFAULT '' COMMENT '单位',
`qty` INT DEFAULT 0 COMMENT '数量',
`price` DECIMAL(10,2) DEFAULT 0 COMMENT '单价',
`amount` DECIMAL(12,2) DEFAULT 0 COMMENT '金额',
`unit_price_cny` DECIMAL(10,2) DEFAULT 0 COMMENT '人民币单价(外单换算用)',
`packing` VARCHAR(60) DEFAULT '' COMMENT '包装方式(独色独码/混色混码)',
`delivered_qty` INT DEFAULT 0 COMMENT '已交付数量',
INDEX `idx_soi_so_id` (`so_id`),
INDEX `idx_soi_product_id` (`product_id`),
INDEX `idx_soi_style_no` (`style_no`),
FOREIGN KEY (`so_id`) REFERENCES `psi_sales_orders`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='销售订单明细';
-- -------------------------------------------
-- 3. 采购订单主表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_purchase_orders` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL COMMENT '订单编号 PO+年月日+流水',
`contract_no` VARCHAR(80) DEFAULT '' COMMENT '合同号',
`supplier_id` INT DEFAULT 0 COMMENT '供应商ID',
`supplier_name` VARCHAR(100) DEFAULT '' COMMENT '供应商名称',
`brand` VARCHAR(100) DEFAULT '' COMMENT '品牌',
`salesman` VARCHAR(50) DEFAULT '' COMMENT '采购员',
`currency` VARCHAR(10) DEFAULT 'CNY' COMMENT '币种',
`payment_terms` VARCHAR(50) DEFAULT '' COMMENT '付款条件',
`total_qty` INT DEFAULT 0 COMMENT '总数量',
`total_amount` DECIMAL(12,2) DEFAULT 0 COMMENT '总金额',
`expected_at` VARCHAR(20) DEFAULT '' COMMENT '预计到货日期',
`remark` TEXT COMMENT '备注',
`status` VARCHAR(20) DEFAULT 'pending' COMMENT '状态 pending/received/closed',
`created_at` VARCHAR(20) DEFAULT '' COMMENT '创建时间',
`updated_at` VARCHAR(20) DEFAULT '' COMMENT '最后修改时间',
INDEX `idx_po_supplier` (`supplier_id`),
INDEX `idx_po_status` (`status`),
INDEX `idx_po_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购订单主表';
-- -------------------------------------------
-- 4. 采购订单明细表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_purchase_order_items` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`po_id` INT NOT NULL COMMENT '关联采购订单ID',
`item_type` VARCHAR(10) DEFAULT 'product' COMMENT '类型 product/material',
`item_id` INT DEFAULT 0 COMMENT '关联物料/成品ID',
`style_no` VARCHAR(60) DEFAULT '' COMMENT '款号/货号',
`name` VARCHAR(120) NOT NULL COMMENT '商品名称',
`spec` VARCHAR(100) DEFAULT '' COMMENT '规格',
`color_code` VARCHAR(30) DEFAULT '' COMMENT '色号',
`size_detail` TEXT COMMENT '尺码明细 JSON',
`material_code` VARCHAR(60) DEFAULT '' COMMENT '物料编码',
`unit` VARCHAR(20) DEFAULT '' COMMENT '单位',
`qty` INT DEFAULT 0 COMMENT '数量',
`price` DECIMAL(10,2) DEFAULT 0 COMMENT '单价',
`amount` DECIMAL(12,2) DEFAULT 0 COMMENT '金额',
`delivery_date` VARCHAR(20) DEFAULT '' COMMENT '预计交期',
`received_qty` INT DEFAULT 0 COMMENT '已收货数量',
INDEX `idx_poi_po_id` (`po_id`),
INDEX `idx_poi_item_type` (`item_type`),
INDEX `idx_poi_style_no` (`style_no`),
FOREIGN KEY (`po_id`) REFERENCES `psi_purchase_orders`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购订单明细';
-- -------------------------------------------
-- 5. 出库单主表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_outbounds` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`order_no` VARCHAR(40) NOT NULL COMMENT '出库单号 OUT+年月日+流水',
`so_no` VARCHAR(40) DEFAULT '' COMMENT '关联销售订单号',
`customer` VARCHAR(100) DEFAULT '' COMMENT '客户',
`customer_po` VARCHAR(80) DEFAULT '' COMMENT '客户采购单号',
`brand` VARCHAR(100) DEFAULT '' COMMENT '品牌',
`salesman` VARCHAR(50) DEFAULT '' COMMENT '业务员',
`warehouse` VARCHAR(60) DEFAULT '' COMMENT '出库仓库',
`carton_count` INT DEFAULT 0 COMMENT '箱数',
`container_no` VARCHAR(100) DEFAULT '' COMMENT '柜号/箱号范围',
`seal_no` VARCHAR(60) DEFAULT '' COMMENT '封条号',
`packing_list_no` VARCHAR(60) DEFAULT '' COMMENT '装箱单号',
`shipping_line` VARCHAR(80) DEFAULT '' COMMENT '船公司/快递',
`voyage` VARCHAR(60) DEFAULT '' COMMENT '航次/航班',
`port_of_loading` VARCHAR(60) DEFAULT '' COMMENT '装运港',
`port_of_discharge` VARCHAR(60) DEFAULT '' COMMENT '卸货港',
`etd` VARCHAR(20) DEFAULT '' COMMENT '预计离港日',
`eta` VARCHAR(20) DEFAULT '' COMMENT '预计到港日',
`gross_weight` DECIMAL(10,2) DEFAULT 0 COMMENT '毛重 KG',
`net_weight` DECIMAL(10,2) DEFAULT 0 COMMENT '净重 KG',
`volume` DECIMAL(10,3) DEFAULT 0 COMMENT '体积 CBM',
`status` VARCHAR(20) DEFAULT 'delivered' COMMENT '状态 delivered/partial',
`delivery_date` VARCHAR(20) DEFAULT '' COMMENT '实际交付日期',
`remark` TEXT COMMENT '备注',
`created_at` VARCHAR(20) DEFAULT '' COMMENT '创建时间',
`updated_at` VARCHAR(20) DEFAULT '' COMMENT '最后修改时间',
INDEX `idx_ob_so_no` (`so_no`),
INDEX `idx_ob_customer` (`customer`),
INDEX `idx_ob_status` (`status`),
INDEX `idx_ob_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='出库单主表';
-- -------------------------------------------
-- 6. 出库单明细表
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_outbound_items` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`ob_id` INT NOT NULL COMMENT '关联出库单ID',
`so_item_id` INT DEFAULT 0 COMMENT '关联销售订单明细ID',
`product_id` INT DEFAULT 0 COMMENT '成品ID',
`style_no` VARCHAR(60) DEFAULT '' COMMENT '款号/货号',
`name` VARCHAR(120) NOT NULL COMMENT '商品名称',
`spec` VARCHAR(100) DEFAULT '' COMMENT '规格',
`color_code` VARCHAR(30) DEFAULT '' COMMENT '色号',
`size_detail` TEXT COMMENT '尺码明细 JSON',
`carton_no` VARCHAR(40) DEFAULT '' COMMENT '箱号',
`unit` VARCHAR(20) DEFAULT '' COMMENT '单位',
`qty` INT DEFAULT 0 COMMENT '数量',
`price` DECIMAL(10,2) DEFAULT 0 COMMENT '单价',
`amount` DECIMAL(12,2) DEFAULT 0 COMMENT '金额',
`unit_weight` DECIMAL(10,2) DEFAULT 0 COMMENT '单件重量 g/KG',
INDEX `idx_obi_ob_id` (`ob_id`),
INDEX `idx_obi_product_id` (`product_id`),
INDEX `idx_obi_so_item_id` (`so_item_id`),
INDEX `idx_obi_style_no` (`style_no`),
FOREIGN KEY (`ob_id`) REFERENCES `psi_outbounds`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='出库单明细';
-- -------------------------------------------
-- 7. 修复 psi_purchases —— 补齐 PurchaseOrdersController::receive() 所需的列
-- -------------------------------------------
-- 使用 INFORMATION_SCHEMA 动态检测是否存在列,兼容 MySQL 5.7+ / MariaDB 10.2+
DROP PROCEDURE IF EXISTS tmp_psi_purchases_alter;
DELIMITER $$
CREATE PROCEDURE tmp_psi_purchases_alter()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'psi_purchases' AND COLUMN_NAME = 'product_id') THEN
ALTER TABLE `psi_purchases` ADD COLUMN `product_id` INT DEFAULT 0 COMMENT '成品ID(采购订单收货时使用)' AFTER `item_id`;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'psi_purchases' AND COLUMN_NAME = 'supplier') THEN
ALTER TABLE `psi_purchases` ADD COLUMN `supplier` VARCHAR(100) DEFAULT '' COMMENT '供应商名称' AFTER `supplier_id`;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'psi_purchases' AND COLUMN_NAME = 'brand') THEN
ALTER TABLE `psi_purchases` ADD COLUMN `brand` VARCHAR(100) DEFAULT '' COMMENT '品牌' AFTER `supplier`;
END IF;
END$$
DELIMITER ;
CALL tmp_psi_purchases_alter();
DROP PROCEDURE IF EXISTS tmp_psi_purchases_alter;
@@ -0,0 +1,46 @@
-- ============================================================
-- 事件通知(邮件 + 企业微信)数据升级包
-- ============================================================
-- 作用:
-- 1) 创建 psi_events 紧急事件表(Notify 服务使用,首次触发也会自动建表,这里提前建好)
-- 2) 写入 notify_* 通知设置(INSERT IGNORE,重复执行不会重复插入)
-- 说明:
-- 本文件专供后台「数据库升级」面板(/admin/upgrade)使用;
-- 若已通过「数据升级」按钮执行过,这里仍为幂等安全。
-- ============================================================
-- -------------------------------------------
-- 1. 紧急事件表(站内提醒 + 邮件/企业微信推送记录)
-- -------------------------------------------
CREATE TABLE IF NOT EXISTS `psi_events` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`sys` VARCHAR(20) NOT NULL DEFAULT 'psi',
`type` VARCHAR(40) NOT NULL DEFAULT '',
`level` VARCHAR(20) NOT NULL DEFAULT 'urgent',
`title` VARCHAR(255) NOT NULL DEFAULT '',
`body` TEXT,
`url` VARCHAR(255) NOT NULL DEFAULT '',
`ref_no` VARCHAR(64) NOT NULL DEFAULT '',
`recipients` TEXT,
`channels` VARCHAR(255) NOT NULL DEFAULT '["inapp"]',
`read_by` TEXT,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- -------------------------------------------
-- 2. 通知设置(缺则插入)
-- -------------------------------------------
INSERT IGNORE INTO `settings` (`skey`,`sval`,`sgroup`) VALUES
('notify_enabled','0','notify'),
('notify_email_enabled','0','notify'),
('notify_email_smtp_host','','notify'),
('notify_email_smtp_port','465','notify'),
('notify_email_smtp_user','','notify'),
('notify_email_smtp_pass','','notify'),
('notify_email_from','','notify'),
('notify_email_to','','notify'),
('notify_wechat_enabled','0','notify'),
('notify_wechat_webhook','','notify'),
('notify_wechat_mention','','notify'),
('notify_lowstock_enabled','1','notify'),
('notify_lowstock_threshold','20','notify');
@@ -0,0 +1,20 @@
-- 给 psi_sales 表增加 item_type 字段,用于精确识别成品/物料类型
-- 幂等升级:可多次安全执行
DROP PROCEDURE IF EXISTS `psi_add_item_type`;
DELIMITER $$
CREATE PROCEDURE `psi_add_item_type`()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='psi_sales' AND COLUMN_NAME='item_type') THEN
ALTER TABLE psi_sales ADD COLUMN item_type VARCHAR(16) DEFAULT '' AFTER item_id;
END IF;
END$$
DELIMITER ;
CALL `psi_add_item_type`();
DROP PROCEDURE IF EXISTS `psi_add_item_type`;
-- 如果有 stock_moves 记录,尝试补齐现有数据的 item_type
UPDATE psi_sales s
LEFT JOIN psi_stock_moves m ON m.ref_no = s.order_no AND m.item_id = s.item_id AND m.qty = s.qty
SET s.item_type = m.item_type
WHERE s.item_type = '' AND m.item_type IS NOT NULL AND m.item_type != '';
+31
View File
@@ -0,0 +1,31 @@
-- 新增 page_seo 表:支持后台逐页设置 SEO(标题/描述/关键词/Open Graph 等)
-- 幂等升级:可多次安全执行(CREATE TABLE IF NOT EXISTS + INSERT IGNORE
CREATE TABLE IF NOT EXISTS `page_seo` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`page_key` VARCHAR(64) NOT NULL COMMENT '页面标识(home/products/product_category/news/cases/about/contact)',
`page_label` VARCHAR(64) NOT NULL COMMENT '后台显示名称',
`title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '页面标题',
`description` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '页面描述',
`keywords` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '关键词,逗号分隔',
`og_title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '社交分享标题',
`og_description` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '社交分享描述',
`og_image` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '社交分享图',
`og_type` VARCHAR(32) NOT NULL DEFAULT 'website',
`canonical` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '规范链接',
`noindex` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否禁止收录',
`sort` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_page_key` (`page_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='逐页SEO设置';
-- 种子数据:默认文案已满足 SEO 建议字数
-- 首页标题≥35字符 / 描述≥120字符 / 分类页描述≥80字符 / 关键词≥10个(部分页面按语义给 6-10 个)
INSERT IGNORE INTO `page_seo` (`page_key`,`page_label`,`title`,`description`,`keywords`,`og_type`,`sort`) VALUES
('home','首页','酷冰甲降温服官网 | 科技降温服定制·水冷循环·相变蓄冷·风冷背心·10套起订','酷冰甲专注降温服的研发、生产与定制,提供水冷循环、相变蓄冷、风冷制冷、冰袋背心等多系列降温装备,广泛适用于消防、工业、电力、钢铁、环卫及户外高温作业场景。支持企业LOGO刺绣、尺寸与面料定制,10套起订,7天打样,全国发货,为您提供一站式高温防护解决方案。','降温服,降温背心,水冷降温服,相变降温服,制冷背心,工业降温服,消防降温服,高温作业防护,降温服定制,酷冰甲','website',10),
('products','产品中心','降温服产品中心 - 水冷/相变/风冷多系列 | 酷冰甲','酷冰甲降温服产品中心,系统展示水冷循环降温服、相变冰袋降温背心、风冷制冷背心、冰马甲等多系列产品,按使用场景与降温方式分类,参数规格与适用行业一目了然。支持企业批量定制、LOGO刺绣与免费拿样,提供专业选型建议与透明报价,助力高温作业安全防护。','降温服产品,水冷降温服,相变降温服,风冷降温服,制冷背心,冰马甲,工业降温装备,降温服批发,降温服定制,酷冰甲产品','website',20),
('product_category','产品分类页','{cat}降温服 - 酷冰甲科技降温·定制批发','酷冰甲{cat}系列降温服,采用科技降温方案,专为高温作业与户外暴晒场景设计,具备清凉持久、轻便透气、可循环重复使用等特点。支持企业定制、LOGO刺绣与小批量批发,10套起订,7天打样,全国发货。','{cat}降温服,{cat},降温服定制,降温背心,工业降温,酷冰甲','website',25),
('news','新闻列表','降温服行业新闻与动态 - 酷冰甲官网','酷冰甲降温服行业新闻中心,汇集高温防护政策解读、降温技术深度解析、产品应用案例、客户现场实录与行业前沿动态,持续分享降温服选型、使用、保养与清洗知识,帮助企业做好高温作业人员的健康与安全防护。我们关注每一次技术迭代,也记录每一处真实应用,让高温防护更有依据、更可落地。','降温服新闻,降温技术,高温防护,工业降温,降温服应用,行业动态,酷冰甲资讯,降温服知识','website',30),
('cases','客户案例','客户案例 - 酷冰甲降温服应用实录','酷冰甲降温服客户案例展示,覆盖消防、电力、钢铁、环卫、户外施工、车间制造等高温作业场景的真实合作项目,逐一呈现降温方案设计思路、现场使用效果与客户真实反馈,并附上适用行业与选型建议,为同类企业的高温防护升级提供可参考、可复用的实战样本,切实降低高温作业风险。','降温服案例,客户案例,高温作业,降温方案,消防降温,工业应用,酷冰甲案例','website',40),
('about','关于我们','关于酷冰甲 - 科技降温服研发与定制厂家','酷冰甲专注降温服的研发、生产与定制,拥有水冷循环、相变蓄冷、风冷制冷等多条成熟产品线,长期服务消防、工业、电力、钢铁等高温作业领域。工厂直供、支持ODM/OEM与来样定制,提供从需求沟通、方案设计、打样生产到售后维护的全流程服务,做您身边靠谱的高温防护伙伴。','关于酷冰甲,降温服厂家,降温服工厂,降温服研发,ODM定制,降温服生产,酷冰甲品牌','website',50),
('contact','联系我们','联系酷冰甲 - 降温服定制咨询与报价','联系酷冰甲,获取降温服定制方案与专属报价。我们支持企业批量采购、LOGO刺绣、尺寸与面料定制,提供在线咨询、电话与邮件多种沟通方式。7天打样、全国发货,专业团队一对一对接您的高温防护需求,从选型到交付全程跟进,确保交付准时可靠,让合作更省心、更可靠。','联系酷冰甲,降温服定制,降温服报价,降温服采购,企业定制,降温服厂家,酷冰甲联系','website',60);
+12
View File
@@ -0,0 +1,12 @@
-- 006 页面编辑模式:为 pages 表增加 mode 字段
-- 用途:后台「页面」编辑支持「固定版面 fixed / 可视化编辑 builder」两种模式
-- 幂等:用 information_schema 判断列是否存在,存在则跳过(兼容 MySQL 5.7 / 8.x 全版本及 MariaDB
-- 旧数据默认 'fixed',渲染行为不变;已用可视化编辑器存过 layout 的页面可手动置为 'builder'
-- 应用方式:后台「系统 / 数据库升级」→ 找到本文件 → 点「升级」
SET @db = DATABASE();
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'pages' AND COLUMN_NAME = 'mode');
SET @sql = IF(@has = 0, 'ALTER TABLE `pages` ADD COLUMN `mode` VARCHAR(16) NOT NULL DEFAULT \'fixed\' AFTER `layout`', 'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
@@ -0,0 +1,12 @@
-- 007 产品编辑模式:为 products 表增加 mode 字段
-- 用途:后台「产品」编辑支持「固定版面 fixed / 可视化编辑 builder」两种模式(选择框切换)
-- 幂等:用 information_schema 判断列是否存在,存在则跳过(兼容 MySQL 5.7 / 8.x 全版本及 MariaDB
-- 旧数据默认 'fixed',渲染行为不变;已用可视化编辑器存过 layout 的产品可手动置为 'builder'
-- 应用方式:后台「系统 / 数据库升级」→ 找到本文件 → 点「升级」
SET @db = DATABASE();
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'products' AND COLUMN_NAME = 'mode');
SET @sql = IF(@has = 0, 'ALTER TABLE `products` ADD COLUMN `mode` VARCHAR(16) NOT NULL DEFAULT \'fixed\' AFTER `layout`', 'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
@@ -0,0 +1,22 @@
-- 008 编辑模式扩展:为 news / cases / categories 表增加 mode 字段
-- 用途:后台新闻、客户案例、分类编辑支持「固定版面 fixed / 可视化编辑 builder」两种模式(与产品/单页一致)
-- 幂等:用 information_schema 判断列是否存在,存在则跳过(兼容 MySQL 5.7 / 8.x 全版本及 MariaDB
-- 旧数据默认 'fixed',渲染行为不变;已用可视化编辑器存过 layout 的记录可手动置为 'builder'
-- 应用方式:后台「系统 / 数据库升级」→ 找到本文件 → 点「升级」
SET @db = DATABASE();
-- news
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'news' AND COLUMN_NAME = 'mode');
SET @sql = IF(@has = 0, 'ALTER TABLE `news` ADD COLUMN `mode` VARCHAR(16) NOT NULL DEFAULT \'fixed\' AFTER `layout`', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- cases
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'cases' AND COLUMN_NAME = 'mode');
SET @sql = IF(@has = 0, 'ALTER TABLE `cases` ADD COLUMN `mode` VARCHAR(16) NOT NULL DEFAULT \'fixed\' AFTER `layout`', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- categories
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'categories' AND COLUMN_NAME = 'mode');
SET @sql = IF(@has = 0, 'ALTER TABLE `categories` ADD COLUMN `mode` VARCHAR(16) NOT NULL DEFAULT \'fixed\' AFTER `layout`', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+37
View File
@@ -0,0 +1,37 @@
数据库升级包目录(install/upgrades
================================================
用途
----
将「升级脚本」(.sql 文件)放入本目录后,进入后台「数据库升级」页面,
系统会自动扫描并提示「发现 N 个可升级数据库脚本」,管理员可一键或逐个执行。
每次执行都会在 db_upgrades 表中留下记录(文件名、内容指纹 MD5、执行时间、操作人),
便于追溯与审计。
命名建议
--------
序号_功能描述.sql 例如 001_add_member_level.sql
序号便于排序与阅读,文件名(不含路径)作为唯一标识写入 db_upgrades。
若同一文件内容被修改后再次放入,系统会识别为「内容已变更」并提示重新升级。
编写规范
--------
1. 仅放 DDL / DML 的标准 MySQL 脚本;多条语句以分号(;)分隔,自动拆分执行。
2. 优先使用「幂等写法」,避免重复执行报错,例如:
CREATE TABLE IF NOT EXISTS xxx (...); -- 全版本支持
INSERT INTO ... ON DUPLICATE KEY UPDATE ...; -- 全版本支持
注意:ALTER TABLE ... ADD COLUMN IF NOT EXISTS 仅 MySQL 8.0.28+ / MariaDB 10.8+ 支持,
旧版本(含多数宝塔默认的 MySQL 5.7 与 MariaDB 10.4/10.6)会直接报 1064 语法错误。
跨版本安全的「加列」幂等方式(强烈推荐):
SET @db = DATABASE();
SET @has = (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='yyy' AND COLUMN_NAME='zzz');
SET @sql = IF(@has=0, 'ALTER TABLE `yyy` ADD COLUMN `zzz` VARCHAR(16) NOT NULL DEFAULT \'x\'', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
3. 不建议在升级包中执行 DROP TABLE / TRUNCATE 等破坏性语句,除非确有必要。
4. 升级前请务必备份数据库。
说明
----
- 本目录下的 examples/ 子目录为示例,不会被自动扫描(仅扫描本目录根下的 *.sql)。
- 想试用示例时,请将 examples/ 中的文件复制到本目录根下再执行。
@@ -0,0 +1,13 @@
-- 示例升级包:演示「幂等」写法,可安全多次执行
-- 复制本文件到上级目录(install/upgrades/)根下,即可在后台「数据库升级」中看到并升级。
-- 1) 为新模块创建一张表(若已存在则跳过)
CREATE TABLE IF NOT EXISTS psi_demo_log (
id INT AUTO_INCREMENT PRIMARY KEY,
msg VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='示例升级包日志表';
-- 2) 写入一条演示记录(依赖唯一键可避免重复)
INSERT INTO psi_demo_log (msg) VALUES ('示例升级包已执行')
ON DUPLICATE KEY UPDATE msg = VALUES(msg);