diff --git a/docs/2026-01-23_summary.md b/docs/2026-01-23_summary.md index 7663e6b..28997d7 100644 --- a/docs/2026-01-23_summary.md +++ b/docs/2026-01-23_summary.md @@ -3,7 +3,9 @@ #### 1) 新增:企业微信机器人 Webhook(text 消息)util 与测试命令 - settings: - - `flower/settings.py` 新增 `WECOM_WEBHOOK_BASE_URL` / `WECOM_WEBHOOK_KEY`(按当前需求直接写入 settings,未接入 .env) + - `flower/settings.py` 新增 `WECOM_WEBHOOK_BASE_URL` / `WECOM_WEBHOOK_KEY` + - `WECOM_WEBHOOK_KEY` 已改为从 `.env` 读取(默认空);若为空,发送时会报错(不会静默吞掉) + - 仓库内提供 `env.example`(等价于常见的 `.env.example`),可用 `cp env.example .env` 生成本地 `.env` - util: - `api_v1/utils/wecom_webhook.py` - 提供 `send_wecom_webhook_message(content=..., msgtype=..., key=..., timeout_seconds=...)` @@ -36,7 +38,11 @@ - `PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE` - 开关:`PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED`(默认测试环境关闭,非测试环境开启) - 模板已增加字段:`{sender}`(发送者) - - 模板已增加字段:`{followup_url}`(跟进地址,来自 `PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE`) + - 跟进地址: + - `.env`:`PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE`(默认空) + - 若为空则**消息中省略“跟进地址”字段**,但消息仍然发送 + - 模板占位符: + - `{followup_line}`(由 service 渲染:有 url 才会输出“跟进地址”行) - 模板已增加字段:`{process_params_markdown}`(工序参数,来自 `state_log.get_all_parameters_summary()`) #### 3) 重构:提取“发送最新状态到企业微信”逻辑为可复用 service(便于后续 API 化) diff --git a/env.example b/env.example new file mode 100644 index 0000000..4a4ea08 --- /dev/null +++ b/env.example @@ -0,0 +1,105 @@ +# Copy this file to ".env" (same directory as manage.py), then fill values. +# 注意:这里是示例文件,请勿提交真实密钥到仓库。 + +############################ +# Django / 基础 +############################ +SECRET_KEY=replace_me_with_a_strong_secret +DEBUG=False + +# 逗号分隔(django-environ Env.list) +ALLOWED_HOSTS=yuwenerp.yuwen.cloud,localhost,127.0.0.1 +CSRF_TRUSTED_ORIGINS=https://yuwenerp.yuwen.cloud,http://localhost:8000 + +DATA_UPLOAD_MAX_NUMBER_FIELDS=20000 + +############################ +# 数据库(必填) +############################ +DB_NAME=flower +DB_USER=flower +DB_PASSWORD=replace_me +DB_HOST=localhost +DB_PORT=6432 +CONN_MAX_AGE=0 + +############################ +# 缓存(可选) +############################ +# 二选一:优先使用 CACHE_URL;否则使用 CACHE_HOST/CACHE_PORT/CACHE_DB 组合 +#CACHE_URL=redis://localhost:6379/0 +CACHE_HOST=localhost +CACHE_PORT=6379 +CACHE_DB=0 +CACHE_KEY_PREFIX=flower +CACHE_DEFAULT_TIMEOUT=300 + +############################ +# 日志(可选) +############################ +LOG_LEVEL=INFO +DJANGO_LOG_LEVEL=INFO +UVICORN_LOG_LEVEL=INFO +UVICORN_ACCESS_LOG_LEVEL=INFO + +############################ +# 明道云同步(可选) +############################ +MDY_MERCHANT_ID=1 +MDY_PRODUCT_CATEGORY_ID=1 +MDY_SYNC_PAGE_SIZE=100 +MDY_SYNC_MAX_PAGES=2 +MDY_SYNC_MAX_RECORDS=200 + +############################ +# 腾讯云 TIIA(建议必填:生产环境请务必使用真实值) +############################ +TENCENTCLOUD_SECRET_ID=replace_me +TENCENTCLOUD_SECRET_KEY=replace_me +TENCENTCLOUD_TOKEN= +TENCENTCLOUD_TIIA_GROUP_ID=168 +TENCENTCLOUD_TIIA_REGION=ap-guangzhou +TENCENTCLOUD_TIIA_ENDPOINT=tiia.tencentcloudapi.com +TENCENTCLOUD_TIIA_PIC_NAME_PREFIX=plate_order +TENCENTCLOUD_TIIA_QPS=10 + +############################ +# 企业微信机器人(WeCom Webhook) +############################ +# 为空时发送会报错:WeCom webhook key 未配置 +WECOM_WEBHOOK_KEY= + +# PrintingJob 状态推进通知的“跟进地址”模板;为空则消息里省略“跟进地址”字段 +PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE=https://app.yuwen.cloud/workstation/production/batch-advance?orderId={order_id} + +############################ +# Printing 自动创建销售品(可选) +############################ +AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER=False + +# 必填(settings 中无默认值),用于从指定 State 读取参数创建 SalesItem +PRINTING_SALES_ITEM_SOURCE_STATE_ID=0 + +############################ +# Celery(可选) +############################ +# 二选一:优先使用 CELERY_BROKER_URL;否则使用 host/port/user/password/vhost 组合 +#CELERY_BROKER_URL=amqp://guest:guest@localhost:5672// +CELERY_BROKER_HOST=localhost +CELERY_BROKER_PORT=5672 +CELERY_BROKER_USER=guest +CELERY_BROKER_PASSWORD=guest +CELERY_BROKER_VHOST=/ + +# 二选一:优先使用 CELERY_RESULT_BACKEND;否则使用 host/port/db 组合 +#CELERY_RESULT_BACKEND=redis://localhost:6379/1 +CELERY_RESULT_HOST=localhost +CELERY_RESULT_PORT=6379 +CELERY_RESULT_DB=1 + +############################ +# CORS(可选) +############################ +# 逗号分隔 +CORS_ALLOWED_ORIGINS=http://localhost:8000,http://127.0.0.1:5173,http://127.0.0.1:5174,http://127.0.0.1:5179,https://yuwenerp.yuwen.cloud + diff --git a/flower/settings.py b/flower/settings.py index a617b06..ecbdda9 100644 --- a/flower/settings.py +++ b/flower/settings.py @@ -79,7 +79,7 @@ TENCENTCLOUD_TIIA_QPS = env.int('TENCENTCLOUD_TIIA_QPS', default=10) # Tencent # 企业微信机器人 Webhook(目前按需求直接写入 settings,不走 .env) # 使用:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx WECOM_WEBHOOK_BASE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send' -WECOM_WEBHOOK_KEY = 'cc88bdef-a13f-4d7e-bdb6-ee51b68b8205' +WECOM_WEBHOOK_KEY = env('WECOM_WEBHOOK_KEY', default='') # CORS 配置 @@ -272,9 +272,7 @@ else: PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED = (not TESTING) # PrintingJob 跟进地址(用于企业微信通知里展示/点击) # orderId 使用 PrintingOrder.id -PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE = ( - "https://app.yuwen.cloud/workstation/production/batch-advance?orderId={order_id}" -) +PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE = env('PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE', default='') PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = ( "### 印染任务状态推进\n" "\n" @@ -283,7 +281,7 @@ PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = ( "- **推进状态**:**{state_name}**\n" "- **推进时间**:`{advanced_at}`\n" "- **发送者**:{sender}\n" - "- **跟进地址**:[{followup_url}]({followup_url})\n" + "{followup_line}" "\n" "**工序参数**:\n" "{process_params_markdown}\n" diff --git a/printing/services.py b/printing/services.py index 06ad9b4..9729d9e 100644 --- a/printing/services.py +++ b/printing/services.py @@ -28,8 +28,11 @@ def build_printing_job_followup_url(*, printing_order_id: int | None) -> str: tmpl = getattr( settings, "PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE", - "https://app.yuwen.cloud/workstation/production/batch-advance?orderId={order_id}", + "", ) + tmpl = (str(tmpl or "")).strip() + if not tmpl: + return "" oid = printing_order_id if printing_order_id is not None else "" try: return str(tmpl).format(order_id=str(oid)) @@ -128,19 +131,21 @@ def render_printing_job_state_markdown( "- **推进状态**:**{state_name}**\n" "- **推进时间**:`{advanced_at}`\n" "- **发送者**:{sender}\n" - "- **跟进地址**:[{followup_url}]({followup_url})\n" + "{followup_line}" "\n" "**工序参数**:\n" "{process_params_markdown}\n" ), ) + followup_url = (followup_url or "").strip() + followup_line = f"- **跟进地址**:[{followup_url}]({followup_url})\n" if followup_url else "" return template.format( printing_order_id=str(printing_order_id), printing_job_id=str(printing_job_id), state_name=str(state_name), advanced_at=str(advanced_at), sender=str(sender_label or "系统自动发送"), - followup_url=str(followup_url), + followup_line=str(followup_line), process_params_markdown=str(process_params_markdown), )