feat: build.sh 按 webapp-deploy 技能重写一键部署(venv+clone全模块+四步安装+/healthz门禁);加 start/stop;/healthz钩子;密码加密
This commit is contained in:
parent
93dadab835
commit
8057ba2888
@ -53,5 +53,22 @@ def init():
|
||||
load_world_sync()
|
||||
|
||||
|
||||
|
||||
|
||||
# ── /healthz 健康检查(部署门禁:GET /healthz 必须 200)──
|
||||
# ahapp_built 钩子在应用构建完成时由 ConfiguredServer 触发,拿到 aiohttp app 注册路由。
|
||||
from appPublic.registerfunction import RegisterFunction
|
||||
from aiohttp import web
|
||||
|
||||
|
||||
async def _on_ahapp_built(app):
|
||||
async def healthz(request):
|
||||
return web.json_response({"status": "ok", "app": "scense", "port": 9380})
|
||||
app.router.add_get("/healthz", healthz)
|
||||
|
||||
|
||||
RegisterFunction().register("ahapp_built", _on_ahapp_built)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
webapp(init)
|
||||
|
||||
171
build.sh
Normal file → Executable file
171
build.sh
Normal file → Executable file
@ -1,73 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# 唤景平台世界模式(scense)一键部署脚本 —— 测试环境
|
||||
# 部署目录 ~/scense_app,应用端口 9380,数据库 localhost:3306/scense (test/test123)
|
||||
# 部署目录 ~/scense_app,应用端口 9380,数据库 localhost:3306/scense
|
||||
# 规范:产线技能库 webapp-deploy(含「模块安装四步」)
|
||||
#
|
||||
# 按 web-application-spec 的 8 步完整集成:
|
||||
# 1) 代码导入(git clone 模块到 pkgs/) 2) 依赖安装(pip install -e)
|
||||
# 3) 前端软链 wwwroot/{模块} 4) i18n 合并
|
||||
# 5) 建表(json2ddl) 6) CRUD 生成(xls2ui)
|
||||
# 7) 初始化数据 8) 运行挂载(load_{模块})
|
||||
# 步骤:
|
||||
# 0) venv
|
||||
# 1) 创建 pkgs/,全部模块 git clone 进来(基础共享包 + 6 业务模块;禁止 mv 源码)
|
||||
# 2) pip install 全部模块(-e,失败即退出)
|
||||
# 3) bricks 前端构建 + wwwroot/bricks 软链
|
||||
# 4) 建库 + 基础框架表与初始业务表(scripts/ddl.sql,幂等 IF NOT EXISTS)
|
||||
# 5) i18n 合并
|
||||
# 6) 逐模块四步安装:① models/json2ddl 建表 ② json/build.sh(xls2ui) ③ wwwroot 软链 ④ 数据导入
|
||||
# 7) 应用代码同步 + runtime 目录
|
||||
# 8) 重启 + 健康检查(/healthz 必须 200,否则 exit 1)
|
||||
# 硬性约束:set -euo pipefail,任何一步失败立即终止,禁止带病启动。
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
APP_NAME="scense"
|
||||
APP_PORT=9380
|
||||
APP_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
DEPLOY_DIR="${DEPLOY_DIR:-$HOME/scense_app}"
|
||||
VENV="${DEPLOY_DIR}/venv"
|
||||
APP_PORT="${APP_PORT:-9380}"
|
||||
DB_HOST="${DB_HOST:-localhost}"
|
||||
DB_PORT="${DB_PORT:-3306}"
|
||||
DB_NAME="${DB_NAME:-scense}"
|
||||
DB_USER="${DB_USER:-test}"
|
||||
DB_PASSWORD="${DB_PASSWORD:-test123}"
|
||||
GIT_HTTPS="https://git.opencomputing.cn/yumoqing"
|
||||
|
||||
# 基础模块(框架层)与业务模块
|
||||
FOUNDATION_MODULES="apppublic sqlor ahserver bricks"
|
||||
DB_MODULES="appbase rbac"
|
||||
FOUNDATION_PKGS="apppublic sqlor ahserver rbac xls2ddl appbase bricks-for-python bricks"
|
||||
BUSINESS_MODULES="world scene entity script_engine world_snapshot world_sync"
|
||||
|
||||
echo "==> [1/8] sync code"
|
||||
mkdir -p "${DEPLOY_DIR}/app" "${DEPLOY_DIR}/conf" "${DEPLOY_DIR}/wwwroot" \
|
||||
"${DEPLOY_DIR}/files" "${DEPLOY_DIR}/logs" "${DEPLOY_DIR}/pkgs"
|
||||
rsync -avz --delete \
|
||||
"${APP_DIR}/app/" "${DEPLOY_DIR}/app/" \
|
||||
"${APP_DIR}/conf/" "${DEPLOY_DIR}/conf/" \
|
||||
"${APP_DIR}/wwwroot/" "${DEPLOY_DIR}/wwwroot/" \
|
||||
"${APP_DIR}/scripts/" "${DEPLOY_DIR}/scripts/"
|
||||
APP_SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
mkdir -p "${DEPLOY_DIR}"
|
||||
|
||||
echo "==> [2/8] clone + install modules"
|
||||
echo "==> [0/9] venv"
|
||||
if [ ! -x "${VENV}/bin/python" ]; then
|
||||
python3 -m venv "${VENV}"
|
||||
fi
|
||||
"${VENV}/bin/pip" install -q --upgrade pip >/dev/null 2>&1 || true
|
||||
"${VENV}/bin/pip" install -q wheel >/dev/null 2>&1 || true
|
||||
|
||||
echo "==> [1/9] clone modules into pkgs/ (git clone only, no mv)"
|
||||
cd "${DEPLOY_DIR}"
|
||||
mkdir -p pkgs
|
||||
for m in ${FOUNDATION_MODULES} ${DB_MODULES} ${BUSINESS_MODULES}; do
|
||||
if [ ! -d "pkgs/${m}" ]; then
|
||||
git clone "git@git.opencomputing.cn:org/${m}.git" "pkgs/${m}" || \
|
||||
git clone "https://git.opencomputing.cn/org/${m}.git" "pkgs/${m}" || true
|
||||
fi
|
||||
if [ -d "pkgs/${m}" ]; then
|
||||
(cd "pkgs/${m}" && git pull --ff-only || true)
|
||||
if [ -f "pkgs/${m}/pyproject.toml" ] || [ -f "pkgs/${m}/setup.py" ]; then
|
||||
pip install -e "pkgs/${m}" || true
|
||||
for m in ${FOUNDATION_PKGS} ${BUSINESS_MODULES}; do
|
||||
if [ ! -d "pkgs/${m}/.git" ]; then
|
||||
rm -rf "pkgs/${m}"
|
||||
git clone -q "${GIT_HTTPS}/${m}.git" "pkgs/${m}" || { echo "ERROR: clone ${m} failed" >&2; exit 1; }
|
||||
echo " cloned ${m}"
|
||||
else
|
||||
export PYTHONPATH="${DEPLOY_DIR}/pkgs/${m}:${PYTHONPATH:-}"
|
||||
git -C "pkgs/${m}" pull -q --ff-only || echo "WARN: pull ${m} failed, using existing"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> [3/8] wwwroot symlinks"
|
||||
for m in ${DB_MODULES} ${BUSINESS_MODULES}; do
|
||||
if [ -d "pkgs/${m}/wwwroot" ]; then
|
||||
ln -sfn "../pkgs/${m}/wwwroot" "wwwroot/${m}"
|
||||
fi
|
||||
echo "==> [2/9] pip install all modules"
|
||||
for m in ${FOUNDATION_PKGS} ${BUSINESS_MODULES}; do
|
||||
if [ -f "pkgs/${m}/pyproject.toml" ] || [ -f "pkgs/${m}/setup.py" ] || [ -f "pkgs/${m}/setup.cfg" ]; then
|
||||
"${VENV}/bin/pip" install -q -e "pkgs/${m}" || { echo "ERROR: pip install ${m} failed" >&2; exit 1; }
|
||||
echo " installed ${m}"
|
||||
else
|
||||
echo "WARN: ${m} has no packaging metadata, skipped pip install"
|
||||
fi
|
||||
done
|
||||
if [ -d "pkgs/bricks/dist" ]; then
|
||||
ln -sfn "../pkgs/bricks/dist" "wwwroot/bricks"
|
||||
|
||||
echo "==> [3/9] bricks frontend build + symlink"
|
||||
if [ ! -f "pkgs/bricks/dist/bricks.js" ]; then
|
||||
(cd pkgs/bricks/bricks && bash build.sh) || { echo "ERROR: bricks build failed" >&2; exit 1; }
|
||||
fi
|
||||
mkdir -p wwwroot
|
||||
ln -sfn "../pkgs/bricks/dist" "wwwroot/bricks"
|
||||
|
||||
echo "==> [4/8] i18n merge"
|
||||
echo "==> [4/9] database + foundation/initial tables"
|
||||
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" \
|
||||
-e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" \
|
||||
|| { echo "ERROR: create database failed" >&2; exit 1; }
|
||||
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" "${DB_NAME}" \
|
||||
< "${APP_SRC_DIR}/scripts/ddl.sql" || { echo "ERROR: ddl.sql failed" >&2; exit 1; }
|
||||
|
||||
echo "==> [5/9] i18n merge"
|
||||
mkdir -p wwwroot/i18n/zh wwwroot/i18n/en
|
||||
python - <<'PY' || true
|
||||
"${VENV}/bin/python" - <<'PY'
|
||||
import json, os
|
||||
ok = 0
|
||||
for lang in ("zh", "en"):
|
||||
merged = {}
|
||||
for m in ("apppublic","sqlor","ahserver","appbase","rbac","world","scene","entity","script_engine","world_snapshot","world_sync"):
|
||||
@ -79,36 +94,58 @@ for lang in ("zh", "en"):
|
||||
k, v = line.split("=", 1)
|
||||
merged[k.strip()] = v.strip()
|
||||
out = f"wwwroot/i18n/{lang}/i18n.json"
|
||||
os.makedirs(os.path.dirname(out), exist_ok=True)
|
||||
json.dump(merged, open(out, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
|
||||
print("i18n merged")
|
||||
ok += len(merged)
|
||||
print(f"i18n merged: {ok} keys")
|
||||
PY
|
||||
|
||||
echo "==> [5/8] init db (ddl)"
|
||||
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" \
|
||||
< "${APP_DIR}/scripts/ddl.sql"
|
||||
|
||||
echo "==> [6/8] CRUD generate"
|
||||
echo "==> [6/9] per-module install: ① json2ddl建表 ② json/build.sh ③ wwwroot软链 ④ 数据导入"
|
||||
for m in ${BUSINESS_MODULES}; do
|
||||
if [ -d "pkgs/${m}/json" ] && [ -d "pkgs/${m}/models" ]; then
|
||||
(cd "pkgs/${m}" && xls2ui -m ../models -o "${DEPLOY_DIR}/wwwroot" "${m}" json/*.json || true)
|
||||
fi
|
||||
echo " -- ${m}"
|
||||
# ① 建表:模块 models 是唯一事实源;去掉 DROP 行,重跑不丢数据
|
||||
(cd "pkgs/${m}/models" && "${VENV}/bin/json2ddl" mysql .) > "/tmp/${m}_ddl.sql" \
|
||||
|| { echo "ERROR: ${m} json2ddl failed" >&2; exit 1; }
|
||||
[ -s "/tmp/${m}_ddl.sql" ] || { echo "ERROR: ${m} DDL empty" >&2; exit 1; }
|
||||
grep -vi "^drop table" "/tmp/${m}_ddl.sql" > "/tmp/${m}_ddl_nodrop.sql"
|
||||
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" "${DB_NAME}" \
|
||||
< "/tmp/${m}_ddl_nodrop.sql" || { echo "ERROR: ${m} create tables failed" >&2; exit 1; }
|
||||
# ② CRUD 页面(模块仓库自带 json/build.sh)
|
||||
(cd "pkgs/${m}/json" && bash build.sh) || { echo "ERROR: ${m} json/build.sh failed" >&2; exit 1; }
|
||||
# ③ wwwroot 软链(非 cp)
|
||||
ln -sfn "../pkgs/${m}/wwwroot" "wwwroot/${m}"
|
||||
# ④ 初始化数据(有 data/*.xlsx 才导)
|
||||
if ls "pkgs/${m}/data/"*.xlsx >/dev/null 2>&1; then
|
||||
(cd "pkgs/${m}/data" && for f in *.xlsx; do "${VENV}/bin/dbloader" "${DEPLOY_DIR}" "${DB_NAME}" "$f"; done) \
|
||||
|| { echo "ERROR: ${m} dbloader failed" >&2; exit 1; }
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> [7/8] init data"
|
||||
for m in ${BUSINESS_MODULES}; do
|
||||
if [ -d "pkgs/${m}/data" ]; then
|
||||
(cd "pkgs/${m}/data" && for f in *.xlsx; do
|
||||
[ -e "$f" ] && dbloader "${DEPLOY_DIR}" "${DB_NAME}" "$f" || true
|
||||
done)
|
||||
fi
|
||||
echo "==> [7/9] sync app code + runtime dirs"
|
||||
for d in app conf scripts wwwroot; do
|
||||
if [ -d "${APP_SRC_DIR}/${d}" ] && [ "$(realpath "${APP_SRC_DIR}/${d}")" != "$(realpath "${DEPLOY_DIR}/${d}")" ]; then
|
||||
mkdir -p "${DEPLOY_DIR}/${d}"
|
||||
cp -a "${APP_SRC_DIR}/${d}/." "${DEPLOY_DIR}/${d}/"
|
||||
fi
|
||||
done
|
||||
mkdir -p logs files
|
||||
|
||||
echo "==> [8/8] restart"
|
||||
if [ -f "${DEPLOY_DIR}/run.sh" ]; then
|
||||
bash "${DEPLOY_DIR}/run.sh" restart
|
||||
else
|
||||
echo "warning: run.sh not found, start via: nohup python app/scense.py > logs/scense.log 2>&1 &"
|
||||
echo "==> [8/9] restart service"
|
||||
bash "${APP_SRC_DIR}/stop.sh" || true
|
||||
sleep 1
|
||||
bash "${APP_SRC_DIR}/start.sh"
|
||||
|
||||
echo "==> [9/9] health check: GET /healthz"
|
||||
ok=""
|
||||
code=""
|
||||
for i in $(seq 1 15); do
|
||||
code=$(curl -s -o /tmp/scense_healthz.json -w "%{http_code}" "http://127.0.0.1:${APP_PORT}/healthz" || true)
|
||||
if [ "${code}" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
if [ -z "${ok}" ]; then
|
||||
echo "ERROR: /healthz not 200 after 30s (last=${code:-000}); logs/scense.log tail:" >&2
|
||||
tail -30 logs/scense.log 2>/dev/null >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> done, app port ${APP_PORT}"
|
||||
echo "healthz: $(cat /tmp/scense_healthz.json)"
|
||||
echo "==> deploy OK: app=scense port=${APP_PORT} healthz=200"
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
{
|
||||
"app": {"name": "scense", "port": 9380, "title": "唤景平台世界模式"},
|
||||
"app": {
|
||||
"name": "scense",
|
||||
"port": 9380,
|
||||
"title": "唤景平台世界模式"
|
||||
},
|
||||
"password_key": "scense_test_env_key",
|
||||
"logger": {
|
||||
"name": "scense",
|
||||
@ -14,7 +18,7 @@
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "test",
|
||||
"password": "test123",
|
||||
"password": "Kj2wTl+LYpPtDSk3B01U7w==",
|
||||
"database": "scense",
|
||||
"charset": "utf8mb4"
|
||||
}
|
||||
@ -24,18 +28,48 @@
|
||||
"port": 9380,
|
||||
"root": "$[workdir]$/wwwroot",
|
||||
"processors": [
|
||||
[".tmpl", "tmpl"],
|
||||
[".ui", "bui"],
|
||||
[".dspy", "dspy"],
|
||||
[".wss", "ws"]
|
||||
[
|
||||
".tmpl",
|
||||
"tmpl"
|
||||
],
|
||||
[
|
||||
".ui",
|
||||
"bui"
|
||||
],
|
||||
[
|
||||
".dspy",
|
||||
"dspy"
|
||||
],
|
||||
[
|
||||
".wss",
|
||||
"ws"
|
||||
]
|
||||
],
|
||||
"indexes": [
|
||||
"index.ui",
|
||||
"index.html"
|
||||
],
|
||||
"indexes": ["index.ui", "index.html"],
|
||||
"session_max_time": 28800,
|
||||
"session_issue_time": 7200
|
||||
"session_issue_time": 7200,
|
||||
"paths": [
|
||||
[
|
||||
"$[workdir]$/wwwroot",
|
||||
""
|
||||
]
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
"apppublic", "sqlor", "ahserver", "appbase", "rbac",
|
||||
"world", "scene", "entity", "script_engine", "world_snapshot", "world_sync"
|
||||
"apppublic",
|
||||
"sqlor",
|
||||
"ahserver",
|
||||
"appbase",
|
||||
"rbac",
|
||||
"world",
|
||||
"scene",
|
||||
"entity",
|
||||
"script_engine",
|
||||
"world_snapshot",
|
||||
"world_sync"
|
||||
],
|
||||
"wwwroot": "wwwroot"
|
||||
}
|
||||
}
|
||||
155
scripts/ddl.sql
155
scripts/ddl.sql
@ -6,3 +6,158 @@ CREATE TABLE IF NOT EXISTS entity (id BIGINT NOT NULL AUTO_INCREMENT, scene_id B
|
||||
CREATE TABLE IF NOT EXISTS script_engine (id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(128) NOT NULL, script_type VARCHAR(32) NOT NULL DEFAULT 'lua', content MEDIUMTEXT, status VARCHAR(16) NOT NULL DEFAULT 'active', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_script_name (name)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='脚本引擎';
|
||||
CREATE TABLE IF NOT EXISTS world_snapshot (id BIGINT NOT NULL AUTO_INCREMENT, world_id BIGINT NOT NULL, version INT NOT NULL DEFAULT 1, snapshot_json LONGTEXT, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_snapshot_world (world_id, version)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='世界快照';
|
||||
CREATE TABLE IF NOT EXISTS world_sync (id BIGINT NOT NULL AUTO_INCREMENT, world_id BIGINT NOT NULL, sync_type VARCHAR(32) NOT NULL, status VARCHAR(16) NOT NULL DEFAULT 'pending', payload_json TEXT, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_sync_world (world_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='世界同步';
|
||||
|
||||
-- ========== 基础框架表(rbac/appbase 单库模式,全新库需先建)==========
|
||||
/*M!999999\- enable the sandbox mode */
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` varchar(32) NOT NULL COMMENT '用户id',
|
||||
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
|
||||
`password` varchar(255) DEFAULT NULL COMMENT '密码',
|
||||
`email` varchar(255) DEFAULT NULL COMMENT '邮件地址',
|
||||
`orgid` varchar(32) DEFAULT NULL COMMENT '所属机构',
|
||||
`nick_name` varchar(255) DEFAULT NULL COMMENT '显示名',
|
||||
`address` varchar(255) DEFAULT NULL COMMENT '地址',
|
||||
`mobile` varchar(255) DEFAULT NULL COMMENT '手机',
|
||||
`user_status` varchar(1) DEFAULT '0' COMMENT '用户状态',
|
||||
`created_at` date DEFAULT NULL COMMENT '注册日期',
|
||||
`last_login` timestamp NULL DEFAULT NULL COMMENT '最后登录时间',
|
||||
`login_fail_count` smallint(6) NOT NULL DEFAULT 0 COMMENT '连续登录失败次数',
|
||||
`last_login_fail` timestamp NULL DEFAULT NULL COMMENT '最后登录失败时间',
|
||||
`sync_from` varchar(32) DEFAULT NULL COMMENT '同步应用id',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `users_idx2` (`username`),
|
||||
KEY `users_idx1` (`orgid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `organization` (
|
||||
`id` varchar(32) NOT NULL COMMENT '机构编码',
|
||||
`orgname` varchar(100) DEFAULT NULL COMMENT '机构名称',
|
||||
`alias_name` varchar(100) DEFAULT NULL COMMENT '机构别名',
|
||||
`contactor` varchar(32) DEFAULT NULL COMMENT '联系人',
|
||||
`contactor_phone` varchar(100) DEFAULT NULL COMMENT '联系人电话',
|
||||
`province_id` varchar(32) DEFAULT NULL COMMENT '所在省id',
|
||||
`city_id` varchar(32) DEFAULT NULL COMMENT '所在城市id',
|
||||
`distinct_id` varchar(32) DEFAULT NULL COMMENT '所在地区id',
|
||||
`emailaddress` varchar(256) DEFAULT NULL COMMENT '邮箱',
|
||||
`address` varchar(400) DEFAULT NULL COMMENT '地址',
|
||||
`main_business` varchar(1000) DEFAULT NULL COMMENT '主营业务描述',
|
||||
`orgcode` varchar(100) DEFAULT NULL COMMENT '组织结构代码',
|
||||
`license_img` varchar(400) DEFAULT NULL COMMENT '营业执照',
|
||||
`id_img` varchar(400) DEFAULT NULL COMMENT '身份证',
|
||||
`parentid` varchar(32) DEFAULT NULL COMMENT '父机构id',
|
||||
`org_type` varchar(32) DEFAULT NULL COMMENT '机构类型',
|
||||
`accountid` varchar(32) DEFAULT NULL COMMENT '账号',
|
||||
`del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机构';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `orgtypes` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`orgid` varchar(32) DEFAULT NULL COMMENT '机构id',
|
||||
`orgtypeid` varchar(32) DEFAULT NULL COMMENT '机构类型',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机构拥有角色';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `org_roles` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`orgid` varchar(32) DEFAULT NULL COMMENT '机构编码',
|
||||
`roleid` varchar(32) DEFAULT NULL COMMENT '角色编码',
|
||||
`del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机构角色';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `role` (
|
||||
`id` varchar(32) NOT NULL COMMENT '角色id',
|
||||
`orgtypeid` varchar(32) DEFAULT '0' COMMENT '机构类型',
|
||||
`role` varchar(100) DEFAULT NULL COMMENT '角色',
|
||||
`rolelabel` varchar(100) DEFAULT NULL COMMENT '角色名称',
|
||||
`name` varchar(100) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `role_idx1` (`orgtypeid`,`role`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT=' 角色';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `rolepermission` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`roleid` varchar(32) DEFAULT NULL COMMENT '角色id',
|
||||
`permid` varchar(32) DEFAULT NULL COMMENT '权限id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色权限表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `userrole` (
|
||||
`id` varchar(32) NOT NULL COMMENT '用户id',
|
||||
`userid` varchar(32) DEFAULT NULL COMMENT '用户id',
|
||||
`roleid` varchar(32) DEFAULT NULL COMMENT '角色id',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `permission` (
|
||||
`id` varchar(32) NOT NULL COMMENT '权限id',
|
||||
`name` varchar(255) DEFAULT NULL COMMENT '名称',
|
||||
`description` varchar(255) DEFAULT NULL COMMENT '描述',
|
||||
`ptype` varchar(20) DEFAULT NULL COMMENT '类型',
|
||||
`parentid` varchar(32) DEFAULT NULL COMMENT '父权限id',
|
||||
`path` varchar(255) DEFAULT NULL COMMENT '路径',
|
||||
`title` varchar(255) DEFAULT NULL COMMENT '标题',
|
||||
`icon` varchar(255) DEFAULT NULL COMMENT '图标',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `permission_idx1` (`ptype`),
|
||||
KEY `permission_idx2` (`parentid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='权限';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE IF NOT EXISTS `params` (
|
||||
`id` varchar(32) NOT NULL,
|
||||
`params_name` varchar(255) NOT NULL,
|
||||
`params_value` varchar(4000) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
|
||||
23
start.sh
Executable file
23
start.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# scense 启动脚本(部署目录 ~/scense_app,端口 9380)
|
||||
set -euo pipefail
|
||||
DEPLOY_DIR="${DEPLOY_DIR:-$HOME/scense_app}"
|
||||
APP_PORT="${APP_PORT:-9380}"
|
||||
cd "${DEPLOY_DIR}"
|
||||
mkdir -p logs
|
||||
|
||||
if pgrep -f "python.*app/scense.py" >/dev/null 2>&1; then
|
||||
echo "scense already running: $(pgrep -f 'python.*app/scense.py' | tr '\n' ' ')"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
nohup "${DEPLOY_DIR}/venv/bin/python" app/scense.py -w "${DEPLOY_DIR}" -p "${APP_PORT}" \
|
||||
>> logs/scense.log 2>&1 </dev/null &
|
||||
sleep 2
|
||||
pid=$(pgrep -f "python.*app/scense.py" | head -1 || true)
|
||||
if [ -z "${pid}" ]; then
|
||||
echo "ERROR: scense failed to start; logs/scense.log tail:" >&2
|
||||
tail -30 logs/scense.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
echo "scense started: pid=${pid} port=${APP_PORT}"
|
||||
18
stop.sh
Executable file
18
stop.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# scense 停止脚本(优雅停止,保留日志)
|
||||
pids=$(pgrep -f "python.*app/scense.py" || true)
|
||||
if [ -z "${pids}" ]; then
|
||||
echo "scense not running"
|
||||
exit 0
|
||||
fi
|
||||
pkill -TERM -f "python.*app/scense.py" || true
|
||||
sleep 2
|
||||
pids=$(pgrep -f "python.*app/scense.py" || true)
|
||||
if [ -n "${pids}" ]; then
|
||||
sleep 2
|
||||
pids=$(pgrep -f "python.*app/scense.py" || true)
|
||||
if [ -n "${pids}" ]; then
|
||||
echo "WARN: still alive: ${pids}"
|
||||
fi
|
||||
fi
|
||||
echo "scense stopped"
|
||||
Loading…
x
Reference in New Issue
Block a user