Compare commits
43 Commits
v0.0.1-2
...
test/weixi
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a8e11414f | |||
| 46135002f9 | |||
| 72f6b341a1 | |||
| 0cb2dfa647 | |||
| 0443cc46ec | |||
| 85cf52b0e4 | |||
| c7aaa1bd16 | |||
| 0519879ebb | |||
| f461fe93f0 | |||
| 2eb98efe61 | |||
| 866ca8d938 | |||
| 267cfa12a2 | |||
| d7df9293bb | |||
| 604917b56c | |||
| 840ce860ea | |||
| 04e1735028 | |||
| ba829c4f53 | |||
| b266023afc | |||
| 23abd0496b | |||
| dffb2563be | |||
| 80998fba70 | |||
| 1f65bb61dd | |||
| 9e044672ee | |||
| 989494af6d | |||
| 5d8c3ba4ce | |||
| a973ce720e | |||
| 218d405f56 | |||
| 2d07082b81 | |||
| 15720c6a62 | |||
| 224c2a3117 | |||
| e2d6a02860 | |||
| 1f8504f002 | |||
| 9ff2492962 | |||
| 88355a3f48 | |||
| 3effc03a19 | |||
| be65996398 | |||
| c58bf929b1 | |||
| ec1b93e473 | |||
| 8a78cea36d | |||
| 96f0d9b602 | |||
| ee884a3737 | |||
| 326dbb1c3c | |||
| f03dbbfc60 |
3
.env
@@ -7,8 +7,6 @@ APP_ENV=development
|
|||||||
# PHP/PHP-FPM 配置
|
# PHP/PHP-FPM 配置
|
||||||
PHP_VERSION=7.4
|
PHP_VERSION=7.4
|
||||||
PHP_FPM_VERSION=7.4-fpm
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
PHP_FPM_PORT=9100
|
|
||||||
XDEBUG_POST=9103
|
|
||||||
|
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
MYSQL_ROOT_HOST=%
|
MYSQL_ROOT_HOST=%
|
||||||
@@ -23,5 +21,4 @@ REDIS_PORT=6399
|
|||||||
|
|
||||||
# Nginx 配置
|
# Nginx 配置
|
||||||
NGINX_PORT=8010
|
NGINX_PORT=8010
|
||||||
NGINX_SSL_PORT=8012
|
|
||||||
|
|
||||||
|
|||||||
24
.env.development
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 项目配置, 请根据实际情况修改
|
||||||
|
PROJECT_NAME=newshop
|
||||||
|
|
||||||
|
# ThinkPHP 6.x 配置, 请根据实际情况修改
|
||||||
|
APP_ENV=development
|
||||||
|
|
||||||
|
# PHP/PHP-FPM 配置
|
||||||
|
PHP_VERSION=7.4
|
||||||
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
MYSQL_ROOT_HOST=%
|
||||||
|
MYSQL_DATABASE=shop_mallnew
|
||||||
|
MYSQL_USER=shop_mallnew
|
||||||
|
MYSQL_PASSWORD=shop_mallnew
|
||||||
|
MYSQL_PORT=3326
|
||||||
|
|
||||||
|
# Redis 绑定端口及密码
|
||||||
|
REDIS_PASSWORD=luckyshop123!@#
|
||||||
|
REDIS_PORT=6499
|
||||||
|
|
||||||
|
# Nginx 暴漏端口
|
||||||
|
NGINX_PORT=8050
|
||||||
|
|
||||||
13
.env.example
@@ -1,24 +1,23 @@
|
|||||||
# 项目配置, 请根据实际情况修改
|
# 项目配置, 请根据实际情况修改
|
||||||
PROJECT_NAME=newshop
|
PROJECT_NAME=newshop
|
||||||
|
|
||||||
|
# ThinkPHP 6.x 配置, 请根据实际情况修改
|
||||||
|
APP_ENV=development
|
||||||
|
|
||||||
# PHP/PHP-FPM 配置
|
# PHP/PHP-FPM 配置
|
||||||
PHP_VERSION=7.4
|
PHP_VERSION=7.4
|
||||||
PHP_FPM_VERSION=7.4-fpm
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
PHP_FPM_PORT=9000
|
|
||||||
XDEBUG_POST=9003
|
|
||||||
|
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
MYSQL_ROOT_HOST=%
|
MYSQL_ROOT_HOST=%
|
||||||
MYSQL_DATABASE=shop_mallnew
|
MYSQL_DATABASE=shop_mallnew
|
||||||
MYSQL_USER=shop_mallnew
|
MYSQL_USER=shop_mallnew
|
||||||
MYSQL_PASSWORD=shop_mallnew
|
MYSQL_PASSWORD=shop_mallnew
|
||||||
MYSQL_PORT=3306
|
MYSQL_PORT=3316
|
||||||
|
|
||||||
# Redis 配置
|
# Redis 配置
|
||||||
REDIS_PASSWORD=luckyshop123!@#
|
REDIS_PASSWORD=luckyshop123!@#
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6399
|
||||||
|
|
||||||
# Nginx 配置
|
# Nginx 配置
|
||||||
NGINX_PORT=80
|
NGINX_PORT=8010
|
||||||
NGINX_SSL_PORT=443
|
|
||||||
|
|
||||||
|
|||||||
24
.env.production
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 项目配置, 请根据实际情况修改
|
||||||
|
PROJECT_NAME=newshop
|
||||||
|
|
||||||
|
# ThinkPHP 6.x 配置, 请根据实际情况修改
|
||||||
|
APP_ENV=production
|
||||||
|
|
||||||
|
# PHP/PHP-FPM 配置
|
||||||
|
PHP_VERSION=7.4
|
||||||
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
MYSQL_ROOT_HOST=%
|
||||||
|
MYSQL_DATABASE=shop_mallnew
|
||||||
|
MYSQL_USER=shop_mallnew
|
||||||
|
MYSQL_PASSWORD=shop_mallnew
|
||||||
|
MYSQL_PORT=3926
|
||||||
|
|
||||||
|
# Redis 绑定端口及密码
|
||||||
|
REDIS_PASSWORD=luckyshop123!@#
|
||||||
|
REDIS_PORT=6829
|
||||||
|
|
||||||
|
# Nginx 暴漏端口
|
||||||
|
NGINX_PORT=8858
|
||||||
|
|
||||||
24
.env.staging
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 项目配置, 请根据实际情况修改
|
||||||
|
PROJECT_NAME=newshop
|
||||||
|
|
||||||
|
# ThinkPHP 6.x 配置, 请根据实际情况修改
|
||||||
|
APP_ENV=staging
|
||||||
|
|
||||||
|
# PHP/PHP-FPM 配置
|
||||||
|
PHP_VERSION=7.4
|
||||||
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
MYSQL_ROOT_HOST=%
|
||||||
|
MYSQL_DATABASE=shop_mallnew
|
||||||
|
MYSQL_USER=shop_mallnew
|
||||||
|
MYSQL_PASSWORD=shop_mallnew
|
||||||
|
MYSQL_PORT=3826
|
||||||
|
|
||||||
|
# Redis 绑定端口及密码
|
||||||
|
REDIS_PASSWORD=luckyshop123!@#
|
||||||
|
REDIS_PORT=6809
|
||||||
|
|
||||||
|
# Nginx 暴漏端口
|
||||||
|
NGINX_PORT=8854
|
||||||
|
|
||||||
24
.env.test
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 项目配置, 请根据实际情况修改
|
||||||
|
PROJECT_NAME=newshop
|
||||||
|
|
||||||
|
# ThinkPHP 6.x 配置, 请根据实际情况修改
|
||||||
|
APP_ENV=test
|
||||||
|
|
||||||
|
# PHP/PHP-FPM 配置
|
||||||
|
PHP_VERSION=7.4
|
||||||
|
PHP_FPM_VERSION=7.4-fpm
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
MYSQL_ROOT_HOST=%
|
||||||
|
MYSQL_DATABASE=shop_mallnew
|
||||||
|
MYSQL_USER=shop_mallnew
|
||||||
|
MYSQL_PASSWORD=shop_mallnew
|
||||||
|
MYSQL_PORT=3346
|
||||||
|
|
||||||
|
# Redis 绑定端口及密码
|
||||||
|
REDIS_PASSWORD=luckyshop123!@#
|
||||||
|
REDIS_PORT=6799
|
||||||
|
|
||||||
|
# Nginx 暴漏端口
|
||||||
|
NGINX_PORT=8360
|
||||||
|
|
||||||
3
.gitignore
vendored
@@ -18,6 +18,9 @@ __pycache__
|
|||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# 环境变量
|
||||||
|
.env
|
||||||
|
|
||||||
# 源码结构
|
# 源码结构
|
||||||
debug.txt
|
debug.txt
|
||||||
.travis.yml
|
.travis.yml
|
||||||
|
|||||||
138
README.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# 在线商城PHP项目
|
||||||
|
|
||||||
|
## Git 分支策略
|
||||||
|
|
||||||
|
| 环境 | 推荐分支 | 备选分支 | 说明 |
|
||||||
|
|------|----------|----------|------|
|
||||||
|
| local | `dev` | `develop` | 本地开发环境 |
|
||||||
|
| development | `dev` | `development` | 开发测试环境 |
|
||||||
|
| test | `test` | `staging` | 测试环境 |
|
||||||
|
| staging | `staging` | `pre-release` | 预发布环境 |
|
||||||
|
| production | `master` | `main` | 生产环境 |
|
||||||
|
|
||||||
|
**部署建议**:
|
||||||
|
- 每个环境部署前请先切换到对应的Git分支
|
||||||
|
- 确保代码版本与目标环境匹配
|
||||||
|
- 生产环境部署前建议先在staging环境验证
|
||||||
|
|
||||||
|
## Docker 部署
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env.development
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**
|
||||||
|
|
||||||
|
- 在同一目录下面,执行 `docker-compose` 命令时,需要指定项目名称。用来区分不同的环境。如 `shop_local`、`shop_dev` 等。
|
||||||
|
- 本地部署时,需要将 `APP_ENV` 设置为 `local`。
|
||||||
|
- 开发环境部署时,需要将 `APP_ENV` 设置为 `development`。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
- `APP_ENV`: 应用环境,默认值为 `development`。
|
||||||
|
|
||||||
|
## 开发环境-local 部署
|
||||||
|
|
||||||
|
**对应Git分支**: `main` 或 `develop`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到本地开发分支
|
||||||
|
git checkout main # 或 develop
|
||||||
|
|
||||||
|
# 本地部署时,需要将 APP_ENV 设置为 local, 并指定 docker-compose.local.yml 文件
|
||||||
|
docker-compose --env-file .env.local -f docker-compose.local.yml up -d
|
||||||
|
# docker-compose --project-name shop_local --env-file .env.local -f docker-compose.local.yml up -d
|
||||||
|
|
||||||
|
# docker-compose down 命令,用来停止并删除容器
|
||||||
|
docker-compose -f docker-compose.local.yml down -v
|
||||||
|
# docker-compose --project-name shop_local down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 开发环境-development 部署
|
||||||
|
|
||||||
|
**对应Git分支**: `dev` 或 `development`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到开发分支
|
||||||
|
git checkout dev # 或 development
|
||||||
|
|
||||||
|
# 默认使用 docker-compose.yml 文件
|
||||||
|
docker-compose --project-name shop_development --env-file .env.development up -d
|
||||||
|
|
||||||
|
# docker-compose down 命令,用来停止并删除容器
|
||||||
|
docker-compose --project-name shop_development down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发环境-test 部署 (测试环境)
|
||||||
|
|
||||||
|
**对应Git分支**: `test` 或 `staging`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到测试分支
|
||||||
|
git checkout test # 或 staging
|
||||||
|
|
||||||
|
# 默认使用 docker-compose.yml 文件
|
||||||
|
docker-compose --project-name shop_test --env-file .env.test up -d
|
||||||
|
|
||||||
|
# docker-compose down 命令,用来停止并删除容器
|
||||||
|
docker-compose --project-name shop_test down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发环境-staging 部署(预发布环境)
|
||||||
|
|
||||||
|
**对应Git分支**: `staging` 或 `pre-release`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到预发布分支
|
||||||
|
git checkout staging # 或 pre-release
|
||||||
|
|
||||||
|
# 默认使用 docker-compose.yml 文件
|
||||||
|
docker-compose --project-name shop_staging --env-file .env.staging up -d
|
||||||
|
|
||||||
|
# docker-compose down 命令,用来停止并删除容器
|
||||||
|
docker-compose --project-name shop_staging down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生产环境-production 部署
|
||||||
|
|
||||||
|
**对应Git分支**: `master` 或 `main` 或 `production`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 切换到生产分支
|
||||||
|
git checkout main
|
||||||
|
|
||||||
|
# 确保代码是最新的生产版本
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# 默认使用 docker-compose.yml 文件
|
||||||
|
docker-compose --project-name shop_production --env-file .env.production up -d
|
||||||
|
|
||||||
|
# docker-compose down 命令,用来停止并删除容器
|
||||||
|
docker-compose --project-name shop_production down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## 便捷部署脚本
|
||||||
|
|
||||||
|
### 环境切换与部署脚本
|
||||||
|
|
||||||
|
- `deploy.sh` 脚本:
|
||||||
|
|
||||||
|
|
||||||
|
### 使用方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 赋予执行权限
|
||||||
|
chmod +x deploy.sh
|
||||||
|
|
||||||
|
# 部署到开发环境
|
||||||
|
./deploy.sh development
|
||||||
|
|
||||||
|
# 部署到测试环境
|
||||||
|
./deploy.sh test
|
||||||
|
|
||||||
|
# 部署到生产环境
|
||||||
|
./deploy.sh production
|
||||||
|
```
|
||||||
100
deploy.sh
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# deploy.sh - 环境切换与部署脚本
|
||||||
|
# 使用方法: ./deploy.sh <environment>
|
||||||
|
# 示例: ./deploy.sh development
|
||||||
|
|
||||||
|
ENVIRONMENT=$1
|
||||||
|
PROJECT_NAME="shop_${ENVIRONMENT}"
|
||||||
|
BRANCH=""
|
||||||
|
COMPOSE_FILE="docker-compose.yml"
|
||||||
|
ENV_FILE=".env.${ENVIRONMENT}"
|
||||||
|
|
||||||
|
# 现实运行中的服务器网站,数据库备份目录
|
||||||
|
RUN_SERVER_WEB_ROOT="/data/wwwroot/shop-projects"
|
||||||
|
RUN_SERVER_DB_BACKUP_DIR="/data/backup/shop-projects"
|
||||||
|
|
||||||
|
case $ENVIRONMENT in
|
||||||
|
"local")
|
||||||
|
BRANCH="dev"
|
||||||
|
COMPOSE_FILE="docker-compose.local.yml"
|
||||||
|
ENV_FILE=".env.local"
|
||||||
|
;;
|
||||||
|
"development")
|
||||||
|
BRANCH="dev"
|
||||||
|
;;
|
||||||
|
"test")
|
||||||
|
BRANCH="test"
|
||||||
|
;;
|
||||||
|
"staging")
|
||||||
|
BRANCH="staging"
|
||||||
|
;;
|
||||||
|
"production")
|
||||||
|
BRANCH="main"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "错误: 不支持的环境 '$ENVIRONMENT'"
|
||||||
|
echo "支持的环境: local, development, test, staging, production"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "部署环境: $ENVIRONMENT"
|
||||||
|
echo "项目名称: $PROJECT_NAME"
|
||||||
|
echo "Git分支: $BRANCH"
|
||||||
|
echo "配置文件: $COMPOSE_FILE"
|
||||||
|
echo "环境文件: $ENV_FILE"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# 切换分支
|
||||||
|
echo "切换到Git分支: $BRANCH"
|
||||||
|
git checkout $BRANCH
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "错误: 无法切换到分支 $BRANCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 拉取最新代码
|
||||||
|
echo "拉取最新代码..."
|
||||||
|
git pull origin $BRANCH
|
||||||
|
|
||||||
|
# 根据不同的环境,执行不同的操作
|
||||||
|
# 预发布环境、生产环境都需要使用运行服务上的用户文件,将用户文件复制到指定目录
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 根据不同的环境,执行不同的操作
|
||||||
|
# 预发布环境、生产环境都需要还原数据库,使用数据库备份文件,并尝试使用数据库升级
|
||||||
|
if [ "$ENVIRONMENT" = "local" ]; then
|
||||||
|
echo "本地环境,跳过数据库还原"
|
||||||
|
else
|
||||||
|
echo "还原数据库..."
|
||||||
|
# 还原数据库
|
||||||
|
docker-compose --project-name $PROJECT_NAME exec -T db bash -c "mysql -uroot -p$DB_ROOT_PASSWORD shop < $DB_BACKUP_DIR/shop.sql"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "错误: 数据库还原失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 尝试使用数据库升级脚本
|
||||||
|
echo "尝试使用数据库升级..."
|
||||||
|
docker-compose --project-name $PROJECT_NAME exec -T db bash -c "php artisan migrate --force"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "数据库升级失败"
|
||||||
|
else
|
||||||
|
echo "数据库升级成功"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 构建并启动容器
|
||||||
|
echo "构建并启动Docker容器..."
|
||||||
|
if [ "$ENVIRONMENT" = "local" ]; then
|
||||||
|
docker-compose --env-file $ENV_FILE -f $COMPOSE_FILE up -d
|
||||||
|
else
|
||||||
|
docker-compose --project-name $PROJECT_NAME --env-file $ENV_FILE up -d
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "部署完成!"
|
||||||
|
echo "查看容器状态: docker-compose --project-name $PROJECT_NAME ps"
|
||||||
|
echo "查看日志: docker-compose --project-name $PROJECT_NAME logs -f"
|
||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./docker/php
|
context: ./docker/php
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: ${PROJECT_NAME}_php
|
container_name: ${PROJECT_NAME}_${APP_ENV}_php
|
||||||
restart: always
|
restart: always
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:host-gateway" # 支持主机名解析
|
- "host.docker.internal:host-gateway" # 支持主机名解析
|
||||||
@@ -25,23 +25,20 @@ services:
|
|||||||
# 不然,ThinkPHP 6.x 系列,会只加载 .env 文件,而不会加载 .env.local 文件,导致 .env.local 文件中的配置不会生效
|
# 不然,ThinkPHP 6.x 系列,会只加载 .env 文件,而不会加载 .env.local 文件,导致 .env.local 文件中的配置不会生效
|
||||||
APP_ENV: ${APP_ENV:-development}
|
APP_ENV: ${APP_ENV:-development}
|
||||||
APP_DEBUG: ${APP_DEBUG:-true}
|
APP_DEBUG: ${APP_DEBUG:-true}
|
||||||
XDEBUG_CONFIG: ${XDEBUG_CONFIG:-client_host=host.docker.internal client_port=9003}
|
# PHP应用根目录(可选,默认 /var/www/html)
|
||||||
PHP_IDE_CONFIG: serverName=docker-php
|
PHP_APP_ROOT: ${PHP_APP_ROOT:-/var/www/html}
|
||||||
ports:
|
# 用户ID映射(可选,用于解决挂载权限问题)
|
||||||
- "${PHP_FPM_PORT:-9000}:9000" # PHP-FPM
|
USER_ID: ${USER_ID:-33}
|
||||||
- "${XDEBUG_POST:-9003}:9003" # Xdebug
|
GROUP_ID: ${GROUP_ID:-33}
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/var/www/all_source
|
- ./src:/var/www/html:rw
|
||||||
- ./src:/var/www/html
|
|
||||||
# 更新下载源列表以加速apt-get
|
# 更新下载源列表以加速apt-get
|
||||||
- ./docker/debian/sources.list:/etc/apt/sources.list:ro
|
- ./docker/debian/sources.list:/etc/apt/sources.list:ro
|
||||||
- ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro
|
- ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro
|
||||||
- ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
|
|
||||||
- xdebug_logs:/tmp # Xdebug 日志目录
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "bash", "-c", "curl -f http://localhost:9000/status && ps aux | grep '[p]hp think cron:schedule'"]
|
test: ["CMD", "bash", "-c", "curl -f http://localhost:9000/status"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
@@ -49,19 +46,19 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- sass-platform-net
|
- sass-platform-net
|
||||||
labels:
|
labels:
|
||||||
- "com.docker.compose.project.working_dir=${PROJECT_NAME}"
|
- "com.docker.compose.project.working_dir=${PROJECT_NAME}_${APP_ENV}"
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
build:
|
build:
|
||||||
context: ./docker/nginx
|
context: ./docker/nginx
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: ${PROJECT_NAME}_nginx
|
container_name: ${PROJECT_NAME}_${APP_ENV}_nginx
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${NGINX_PORT:-80}:80"
|
- "${NGINX_PORT:-80}:80"
|
||||||
- "${NGINX_SSL_PORT:-443}:443"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./src:/var/www/html:ro
|
# 挂载项目代码到 Nginx 容器中
|
||||||
|
- ./src:/var/www/html:rw
|
||||||
# 更新下载源列表以加速apt-get
|
# 更新下载源列表以加速apt-get
|
||||||
- ./docker/debian/sources.list:/etc/apt/sources.list:ro
|
- ./docker/debian/sources.list:/etc/apt/sources.list:ro
|
||||||
# 创建临时目录
|
# 创建临时目录
|
||||||
@@ -72,11 +69,11 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- sass-platform-net
|
- sass-platform-net
|
||||||
labels:
|
labels:
|
||||||
- "com.docker.compose.project.working_dir=${PROJECT_NAME}"
|
- "com.docker.compose.project.working_dir=${PROJECT_NAME}_${APP_ENV}"
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: mysql:5.7.44
|
image: mysql:5.7.44
|
||||||
container_name: ${PROJECT_NAME}_mysql
|
container_name: ${PROJECT_NAME}_${APP_ENV}_mysql
|
||||||
environment:
|
environment:
|
||||||
<<: *shared-api-env
|
<<: *shared-api-env
|
||||||
volumes:
|
volumes:
|
||||||
@@ -93,12 +90,12 @@ services:
|
|||||||
- --collation-server=utf8mb4_unicode_ci
|
- --collation-server=utf8mb4_unicode_ci
|
||||||
- --innodb_buffer_pool_size=256M
|
- --innodb_buffer_pool_size=256M
|
||||||
labels:
|
labels:
|
||||||
- "com.docker.compose.project.working_dir=${PROJECT_NAME}"
|
- "com.docker.compose.project.working_dir=${PROJECT_NAME}_${APP_ENV}"
|
||||||
|
|
||||||
# Redis 服务(可选)
|
# Redis 服务(可选)
|
||||||
redis:
|
redis:
|
||||||
image: redis:8.2
|
image: redis:8.2
|
||||||
container_name: ${PROJECT_NAME}_redis
|
container_name: ${PROJECT_NAME}_${APP_ENV}_redis
|
||||||
environment:
|
environment:
|
||||||
REDIS_PASSWORD: ${REDIS_PASSWORD:-luckyshop123!@#}
|
REDIS_PASSWORD: ${REDIS_PASSWORD:-luckyshop123!@#}
|
||||||
REDISCLI_AUTH: ${REDIS_PASSWORD:-luckyshop123!@#}
|
REDISCLI_AUTH: ${REDIS_PASSWORD:-luckyshop123!@#}
|
||||||
@@ -111,13 +108,26 @@ services:
|
|||||||
- sass-platform-net
|
- sass-platform-net
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
labels:
|
labels:
|
||||||
- "com.docker.compose.project.working_dir=${PROJECT_NAME}"
|
- "com.docker.compose.project.working_dir=${PROJECT_NAME}_${APP_ENV}"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql_db_data:
|
mysql_db_data:
|
||||||
|
name: ${PROJECT_NAME}_${APP_ENV}_mysql_db_data
|
||||||
|
driver: local
|
||||||
|
driver_opts:
|
||||||
|
type: none
|
||||||
|
o: bind
|
||||||
|
device: ./docker/mysql_db_data/${APP_ENV}
|
||||||
redis_data:
|
redis_data:
|
||||||
xdebug_logs:
|
name: ${PROJECT_NAME}_${APP_ENV}_redis_data
|
||||||
|
driver: local
|
||||||
|
driver_opts:
|
||||||
|
type: none
|
||||||
|
o: bind
|
||||||
|
device: ./docker/redis_data/${APP_ENV}
|
||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
sass-platform-net:
|
sass-platform-net:
|
||||||
|
name: ${PROJECT_NAME}_${APP_ENV}_net
|
||||||
driver: bridge
|
driver: bridge
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
# 字符集设置
|
# 字符集设置
|
||||||
character-set-server=utf8mb4
|
character-set-server=utf8mb4
|
||||||
collation-server=utf8mb4_unicode_ci
|
collation-server=utf8mb4_unicode_ci
|
||||||
|
init_connect='SET NAMES utf8mb4'
|
||||||
|
|
||||||
|
|
||||||
# 连接设置
|
# 连接设置
|
||||||
max_connections=100
|
max_connections=100
|
||||||
@@ -22,6 +24,3 @@ sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
|||||||
|
|
||||||
[client]
|
[client]
|
||||||
default-character-set=utf8mb4
|
default-character-set=utf8mb4
|
||||||
|
|
||||||
[mysql]
|
|
||||||
default-character-set=utf8mb4
|
|
||||||
9
docker/mysql_db_data/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 忽略所有文件
|
||||||
|
*
|
||||||
|
|
||||||
|
# 只保留指定的 .gitkeep 文件
|
||||||
|
!.gitignore
|
||||||
|
!development/.gitkeep
|
||||||
|
!test/.gitkeep
|
||||||
|
!production/.gitkeep
|
||||||
|
!staging/.gitkeep
|
||||||
0
docker/mysql_db_data/.gitkeep
Normal file
@@ -3,27 +3,19 @@ FROM nginx:alpine
|
|||||||
# 删除默认配置
|
# 删除默认配置
|
||||||
RUN rm /etc/nginx/conf.d/default.conf
|
RUN rm /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
#
|
|
||||||
# - ./.docker/nginx/conf.c:/etc/nginx/conf.c:ro
|
# 将本地 nginx 配置复制到镜像中
|
||||||
# - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
COPY ./conf.c/ /etc/nginx/conf.c/
|
||||||
# - ./.docker/nginx/sites-enabled:/etc/nginx/sites-enabled:ro
|
|
||||||
# 将本地 nginx 配置复制到镜像中并设置为只读
|
|
||||||
COPY ./conf.c /etc/nginx/conf.c
|
|
||||||
COPY ./default.conf /etc/nginx/conf.d/default.conf
|
COPY ./default.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY ./sites-enabled /etc/nginx/sites-enabled
|
COPY ./sites-enabled/ /etc/nginx/sites-enabled/
|
||||||
|
|
||||||
# 设置只读权限(文件 0444,目录及其内容 0555)
|
|
||||||
RUN chmod 0444 /etc/nginx/conf.c \
|
|
||||||
&& chmod 0444 /etc/nginx/conf.d/default.conf \
|
|
||||||
&& chmod -R 0555 /etc/nginx/sites-enabled
|
|
||||||
|
|
||||||
# 设置工作目录
|
|
||||||
WORKDIR /var/www/html
|
|
||||||
|
|
||||||
# 创建日志目录
|
|
||||||
RUN mkdir -p /var/log/nginx
|
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 80 443
|
EXPOSE 80 443
|
||||||
|
|
||||||
|
# 添加在Dockerfile末尾,CMD命令之前
|
||||||
|
COPY ./entrypoint.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
|
|
||||||
|
# 启动nginx
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
14
docker/nginx/conf.c/enable-websocket.conf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
location /ws {
|
||||||
|
proxy_pass http://php-fpm:8080; # 注意:这里用的是 Docker 服务名或容器名
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# 可选:设置超时(WebSocket 是长连接)
|
||||||
|
proxy_read_timeout 86400s;
|
||||||
|
proxy_send_timeout 86400s;
|
||||||
|
}
|
||||||
18
docker/nginx/entrypoint.sh
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=== NGINX Docker 权限初始化 ==="
|
||||||
|
|
||||||
|
# 设置权限
|
||||||
|
chmod -R 0444 /etc/nginx/conf.c
|
||||||
|
chmod 0444 /etc/nginx/conf.d/default.conf
|
||||||
|
chmod -R 0755 /etc/nginx/sites-enabled
|
||||||
|
|
||||||
|
|
||||||
|
# 创建日志目录
|
||||||
|
mkdir -p /var/log/nginx
|
||||||
|
|
||||||
|
echo "=== NGINX Docker 权限初始化完成 ==="
|
||||||
|
|
||||||
|
# 执行原有的启动命令
|
||||||
|
exec "$@"
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
# --- SSL configuration end ---
|
# --- SSL configuration end ---
|
||||||
|
|
||||||
|
# 启用 WebSocket 支持
|
||||||
|
include conf.c/enable-websocket.conf;
|
||||||
|
|
||||||
#PHP-INFO-START PHP引用配置,可以注释或修改
|
#PHP-INFO-START PHP引用配置,可以注释或修改
|
||||||
include conf.c/enable-php-74.conf;
|
include conf.c/enable-php-74.conf;
|
||||||
#PHP-INFO-END
|
#PHP-INFO-END
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# 使用官方PHP镜像
|
|
||||||
FROM php:7.4.33-fpm-dev-newshop
|
|
||||||
|
|
||||||
# 设置工作目录
|
|
||||||
WORKDIR /var/www/html
|
|
||||||
|
|
||||||
# 暴露端口
|
|
||||||
EXPOSE 9000 9003
|
|
||||||
|
|
||||||
CMD ["php-fpm"]
|
|
||||||
@@ -27,8 +27,14 @@ RUN apt-get update && apt-get install -y \
|
|||||||
libfreetype6-dev \
|
libfreetype6-dev \
|
||||||
libjpeg62-turbo-dev \
|
libjpeg62-turbo-dev \
|
||||||
libpng-dev \
|
libpng-dev \
|
||||||
|
iputils-ping \
|
||||||
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 安装 WebSocat 完成后,清理缓存
|
||||||
|
COPY ./websocat /usr/local/bin/websocat
|
||||||
|
RUN chmod +x /usr/local/bin/websocat
|
||||||
|
|
||||||
# 安装 PHP 扩展
|
# 安装 PHP 扩展
|
||||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||||
&& docker-php-ext-install \
|
&& docker-php-ext-install \
|
||||||
@@ -45,9 +51,6 @@ RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
|||||||
# 安装 Redis 扩展
|
# 安装 Redis 扩展
|
||||||
RUN pecl install redis-5.3.7 && docker-php-ext-enable redis
|
RUN pecl install redis-5.3.7 && docker-php-ext-enable redis
|
||||||
|
|
||||||
# 安装 Xdebug(兼容 PHP 7.4 的版本)
|
|
||||||
RUN pecl install xdebug-3.1.6 && docker-php-ext-enable xdebug
|
|
||||||
|
|
||||||
# 安装Composer
|
# 安装Composer
|
||||||
COPY --from=composer:2.2.25 /usr/bin/composer /usr/bin/composer
|
COPY --from=composer:2.2.25 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
@@ -56,30 +59,15 @@ RUN composer --version
|
|||||||
|
|
||||||
# 修改 PHP 配置
|
# 修改 PHP 配置
|
||||||
RUN echo "memory_limit=256M" > /usr/local/etc/php/conf.d/memory-limit.ini \
|
RUN echo "memory_limit=256M" > /usr/local/etc/php/conf.d/memory-limit.ini \
|
||||||
&& echo "upload_max_filesize=50M" >> /usr/local/etc/php/conf.d/uploads.ini \
|
&& echo "upload_max_filesize=150M" >> /usr/local/etc/php/conf.d/uploads.ini \
|
||||||
&& echo "post_max_size=50M" >> /usr/local/etc/php/conf.d/uploads.ini
|
&& echo "post_max_size=150M" >> /usr/local/etc/php/conf.d/uploads.ini
|
||||||
|
|
||||||
# 创建 Xdebug 配置
|
|
||||||
RUN echo "zend_extension=xdebug.so" > /usr/local/etc/php/conf.d/xdebug.ini
|
|
||||||
|
|
||||||
# # 使用Composer安装项目依赖(可选,根据需要启用, 更多的时候,会出错,要在容器中执行操作)
|
# # 使用Composer安装项目依赖(可选,根据需要启用, 更多的时候,会出错,要在容器中执行操作)
|
||||||
# RUN composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
# RUN composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
||||||
# RUN composer install --no-dev --optimize-autoloader --working-dir=/var/www/html
|
# RUN composer install --no-dev --optimize-autoloader --working-dir=/var/www/html
|
||||||
|
|
||||||
# # 创建非 root 用户
|
# 暴露端口,9000 为 PHP-FPM 端口,8080 为 WebSocket 端口
|
||||||
# RUN useradd -m -u 1000 phpuser && chown -R phpuser:phpuser /var/www/html
|
EXPOSE 9000 8080
|
||||||
|
|
||||||
# 设置权限, 防止以下目录无法写入的问题
|
|
||||||
RUN chmod -R a+rw /var/www/html/runtime
|
|
||||||
RUN chmod -R a+rw /var/www/html/uploads
|
|
||||||
RUN chmod -R a+rw /var/www/html/tmp
|
|
||||||
RUN chmod -R a+rw /var/www/html/temp
|
|
||||||
|
|
||||||
# USER phpuser
|
|
||||||
|
|
||||||
# 暴露端口
|
|
||||||
EXPOSE 9000 9003
|
|
||||||
|
|
||||||
|
|
||||||
############ 查看 cron 进程
|
############ 查看 cron 进程
|
||||||
## 查看 cron 进程
|
## 查看 cron 进程
|
||||||
@@ -95,4 +83,10 @@ EXPOSE 9000 9003
|
|||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
# 启动Supervisor
|
# 启动Supervisor
|
||||||
|
# 添加在Dockerfile末尾,CMD命令之前
|
||||||
|
COPY ./entrypoint.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
|
|
||||||
|
# 修改CMD命令
|
||||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||||
344
docker/php/entrypoint.sh
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 移除 set -e 以便更好的错误控制
|
||||||
|
|
||||||
|
echo "=== Web应用权限初始化 ==="
|
||||||
|
|
||||||
|
# 定义应用根目录,优先使用环境变量,否则使用默认值
|
||||||
|
APP_ROOT="${PHP_APP_ROOT:-/var/www/html}"
|
||||||
|
|
||||||
|
echo "使用应用根目录: $APP_ROOT"
|
||||||
|
|
||||||
|
# 如果应用根目录不存在,则跳过权限设置
|
||||||
|
if [ ! -d "$APP_ROOT" ]; then
|
||||||
|
echo "❌ 应用根目录:'$APP_ROOT'不存在,跳过权限设置"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建统一的Web组并配置所有用户(最高效的权限管理)
|
||||||
|
configure_web_users() {
|
||||||
|
# 常见Web服务器用户列表
|
||||||
|
WEB_USERS=("www-data" "www" "apache" "nginx")
|
||||||
|
|
||||||
|
# 获取环境变量中的用户ID
|
||||||
|
TARGET_UID=${USER_ID:-33}
|
||||||
|
TARGET_GID=${GROUP_ID:-33}
|
||||||
|
|
||||||
|
echo "配置统一Web组权限,目标UID:GID = $TARGET_UID:$TARGET_GID"
|
||||||
|
|
||||||
|
# 创建统一的Web组(增强错误处理)
|
||||||
|
WEB_GROUP="webaccess"
|
||||||
|
if ! getent group "$WEB_GROUP" &>/dev/null; then
|
||||||
|
echo "创建统一Web组: $WEB_GROUP"
|
||||||
|
|
||||||
|
# 尝试使用指定GID创建组
|
||||||
|
if groupadd -g $TARGET_GID "$WEB_GROUP" 2>/dev/null; then
|
||||||
|
echo "✅ 统一Web组创建成功,GID: $TARGET_GID"
|
||||||
|
else
|
||||||
|
echo "⚠️ GID $TARGET_GID 已被占用,尝试自动分配GID"
|
||||||
|
|
||||||
|
# 尝试不指定GID创建组
|
||||||
|
if groupadd "$WEB_GROUP" 2>/dev/null; then
|
||||||
|
ACTUAL_GID=$(getent group "$WEB_GROUP" | cut -d: -f3)
|
||||||
|
echo "✅ 统一Web组创建成功,自动分配GID: $ACTUAL_GID"
|
||||||
|
else
|
||||||
|
echo "❌ 创建 $WEB_GROUP 组失败,尝试使用备用方案"
|
||||||
|
|
||||||
|
# 备用方案:使用现有的www-data组
|
||||||
|
if getent group "www-data" &>/dev/null; then
|
||||||
|
WEB_GROUP="www-data"
|
||||||
|
echo "🔄 使用现有的www-data组作为统一组"
|
||||||
|
else
|
||||||
|
echo "❌ 备用方案也失败,权限配置可能不完整"
|
||||||
|
WEB_GROUP=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ACTUAL_GID=$(getent group "$WEB_GROUP" | cut -d: -f3)
|
||||||
|
echo "✅ 统一Web组 $WEB_GROUP 已存在,GID: $ACTUAL_GID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 最终验证组是否存在
|
||||||
|
if [ -z "$WEB_GROUP" ] || ! getent group "$WEB_GROUP" &>/dev/null; then
|
||||||
|
echo "❌ 无法创建或找到可用的Web组,权限配置将受限"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 只将已存在的Web用户加入统一组(增强错误处理)
|
||||||
|
success_count=0
|
||||||
|
total_users=0
|
||||||
|
|
||||||
|
for web_user in "${WEB_USERS[@]}"; do
|
||||||
|
total_users=$((total_users + 1))
|
||||||
|
|
||||||
|
if id "$web_user" &>/dev/null; then
|
||||||
|
echo "📝 处理Web用户: $web_user"
|
||||||
|
|
||||||
|
# 获取用户当前组信息(安全的变量处理)
|
||||||
|
current_groups=$(id -Gn "$web_user" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//')
|
||||||
|
echo " 当前所属组: ${current_groups:-无}"
|
||||||
|
|
||||||
|
# 尝试将用户加入统一组(使用-a参数保留现有组,只添加新组)
|
||||||
|
if usermod -a -G "$WEB_GROUP" "$web_user" 2>/dev/null; then
|
||||||
|
echo " ✅ 成功将 $web_user 添加到统一组 $WEB_GROUP"
|
||||||
|
success_count=$((success_count + 1))
|
||||||
|
else
|
||||||
|
echo " ⚠️ 无法将 $web_user 添加到统一组,尝试设置主组"
|
||||||
|
|
||||||
|
# 备用方案:设置主组
|
||||||
|
if usermod -g "$WEB_GROUP" "$web_user" 2>/dev/null; then
|
||||||
|
echo " ✅ 成功将 $web_user 主组设置为 $WEB_GROUP"
|
||||||
|
success_count=$((success_count + 1))
|
||||||
|
else
|
||||||
|
echo " ❌ 无法配置 $web_user 的组权限"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚭ Web用户 $web_user 不存在,跳过"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "📊 用户配置汇总: $success_count/$total_users 个Web用户配置成功"
|
||||||
|
|
||||||
|
# 至少要有一个用户配置成功
|
||||||
|
if [ $success_count -eq 0 ]; then
|
||||||
|
echo "⚠️ 没有Web用户被成功配置,但继续执行"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "统一Web组配置完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 错误处理:如果配置失败,不要终止整个脚本
|
||||||
|
configure_web_users || echo "⚠️ Web用户配置出现问题,但继续执行权限设置"
|
||||||
|
|
||||||
|
echo "当前用户: $(whoami)"
|
||||||
|
echo "UID: $(id -u), GID: $(id -g)"
|
||||||
|
|
||||||
|
# 修复所有目录权限(使用统一Web组,最高效的权限管理)
|
||||||
|
if [ -d "$APP_ROOT" ]; then
|
||||||
|
# 重新获取最终的WEB_GROUP(可能已被修改)
|
||||||
|
FINAL_WEB_GROUP=""
|
||||||
|
|
||||||
|
# 首选:使用创建的webaccess组
|
||||||
|
if getent group "webaccess" &>/dev/null; then
|
||||||
|
FINAL_WEB_GROUP="webaccess"
|
||||||
|
echo "🎯 使用创建的统一Web组: $FINAL_WEB_GROUP"
|
||||||
|
# 备选:使用www-data组
|
||||||
|
elif getent group "www-data" &>/dev/null; then
|
||||||
|
FINAL_WEB_GROUP="www-data"
|
||||||
|
echo "🔄 回退到www-data组: $FINAL_WEB_GROUP"
|
||||||
|
# 最后:使用当前用户的组
|
||||||
|
else
|
||||||
|
CURRENT_USER=$(whoami)
|
||||||
|
CURRENT_GROUP=$(id -gn "$CURRENT_USER")
|
||||||
|
FINAL_WEB_GROUP="$CURRENT_GROUP"
|
||||||
|
echo "🔧 使用当前用户组: $FINAL_WEB_GROUP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 最终验证
|
||||||
|
if [ -z "$FINAL_WEB_GROUP" ]; then
|
||||||
|
echo "❌ 无法确定有效的Web组,跳过权限设置"
|
||||||
|
echo "=== 启动应用 ==="
|
||||||
|
exec "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
WEB_GROUP="$FINAL_WEB_GROUP"
|
||||||
|
WEB_GROUP_GID=$(getent group "$WEB_GROUP" | cut -d: -f3)
|
||||||
|
echo "✅ 最终使用Web组: $WEB_GROUP (GID: $WEB_GROUP_GID)"
|
||||||
|
echo "🔒 统一组权限模式:所有Web用户通过组继承权限"
|
||||||
|
|
||||||
|
# 设置所有权为统一Web组(增强错误处理)
|
||||||
|
echo "📁 设置应用目录所有权为统一Web组"
|
||||||
|
CURRENT_USER=$(whoami)
|
||||||
|
|
||||||
|
if chown -R $CURRENT_USER:$WEB_GROUP "$APP_ROOT" 2>/dev/null; then
|
||||||
|
echo "✅ 所有权设置成功: $CURRENT_USER:$WEB_GROUP"
|
||||||
|
else
|
||||||
|
echo "⚠️ 所有权设置失败,尝试只设置组权限"
|
||||||
|
chgrp -R "$WEB_GROUP" "$APP_ROOT" 2>/dev/null || echo "❌ 组权限设置也失败"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 设置目录权限为775(组权限为rwx,所有组内用户都有完整权限)
|
||||||
|
echo "🔐 设置目录权限775,文件权限664"
|
||||||
|
|
||||||
|
# 使用更安全的权限设置方式,避免权限被拒绝
|
||||||
|
dir_count=0
|
||||||
|
file_count=0
|
||||||
|
|
||||||
|
# 设置目录权限(兼容性更好的方式)
|
||||||
|
if command -v find >/dev/null 2>&1; then
|
||||||
|
dir_count=$(find "$APP_ROOT" -type d -exec chmod 775 {} \; 2>/dev/null | wc -l)
|
||||||
|
file_count=$(find "$APP_ROOT" -type f -exec chmod 664 {} \; 2>/dev/null | wc -l)
|
||||||
|
find "$APP_ROOT" -type d -exec chmod g+s {} \; 2>/dev/null
|
||||||
|
else
|
||||||
|
# 备用方案:使用简单的循环
|
||||||
|
echo "find命令不可用,跳过批量权限设置"
|
||||||
|
dir_count=0
|
||||||
|
file_count=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📊 权限设置完成: $dir_count个目录, $file_count个文件"
|
||||||
|
|
||||||
|
echo "✅ 统一组权限设置完成,所有Web用户通过组获得权限"
|
||||||
|
|
||||||
|
# 设置ACL(如果支持,只需设置统一组)
|
||||||
|
if command -v setfacl >/dev/null 2>&1; then
|
||||||
|
echo "🔒 设置ACL权限(只需设置统一Web组)"
|
||||||
|
|
||||||
|
acl_success=0
|
||||||
|
|
||||||
|
# 只为统一Web组设置ACL权限(限制处理深度)
|
||||||
|
if setfacl -R -m g:$WEB_GROUP:rwx "$APP_ROOT" 2>/dev/null; then
|
||||||
|
echo " ✅ 设置组ACL权限成功"
|
||||||
|
acl_success=$((acl_success + 1))
|
||||||
|
else
|
||||||
|
echo " ❌ 设置组ACL权限失败"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 设置默认ACL权限(新创建的文件自动继承权限)
|
||||||
|
if setfacl -dR -m g:$WEB_GROUP:rwx "$APP_ROOT" 2>/dev/null; then
|
||||||
|
echo " ✅ 设置默认ACL权限成功"
|
||||||
|
acl_success=$((acl_success + 1))
|
||||||
|
else
|
||||||
|
echo " ❌ 设置默认ACL权限失败"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $acl_success -eq 2 ]; then
|
||||||
|
echo "🎉 统一组ACL设置完成,所有组内用户自动获得权限"
|
||||||
|
elif [ $acl_success -eq 1 ]; then
|
||||||
|
echo "⚠️ ACL部分设置成功,建议检查文件系统ACL支持"
|
||||||
|
else
|
||||||
|
echo "❌ ACL设置完全失败,文件系统可能不支持ACL"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ℹ️ ACL不支持,依赖传统权限模式"
|
||||||
|
echo "✅ 775权限已足够,所有组内用户都有rwx权限"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 设置umask
|
||||||
|
umask 0002
|
||||||
|
|
||||||
|
echo "✅ 应用目录权限修复完成"
|
||||||
|
|
||||||
|
# 验证文件权限是否足够(测试统一组权限效果)
|
||||||
|
echo "=== 验证统一组权限效果 ==="
|
||||||
|
|
||||||
|
# 查找测试文件的更可靠方法
|
||||||
|
test_file=""
|
||||||
|
|
||||||
|
# 方法1: 查找index.html
|
||||||
|
if [ -f "$APP_ROOT/index.html" ]; then
|
||||||
|
test_file="$APP_ROOT/index.html"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 方法2: 查找任意HTML文件(更安全的方式)
|
||||||
|
if [ -z "$test_file" ]; then
|
||||||
|
first_html=$(find "$APP_ROOT" -maxdepth 2 -name "*.html" -type f 2>/dev/null | head -1)
|
||||||
|
if [ -n "$first_html" ] && [ -f "$first_html" ]; then
|
||||||
|
test_file="$first_html"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 方法3: 查找index.php
|
||||||
|
if [ -z "$test_file" ] && [ -f "$APP_ROOT/index.php" ]; then
|
||||||
|
test_file="$APP_ROOT/index.php"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 方法4: 创建专用测试文件(最安全的选择)
|
||||||
|
if [ -z "$test_file" ]; then
|
||||||
|
test_file="$APP_ROOT/.permission_test.html"
|
||||||
|
echo "创建专用权限测试文件"
|
||||||
|
cat > "$test_file" << 'EOF'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>Permission Test</title></head>
|
||||||
|
<body><h1>Web Server Permission Test File</h1></body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
# 设置正确的权限
|
||||||
|
chown $(whoami):"$WEB_GROUP" "$test_file" 2>/dev/null || true
|
||||||
|
chmod 664 "$test_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 执行权限测试
|
||||||
|
if [ -f "$test_file" ]; then
|
||||||
|
echo "使用测试文件: $test_file"
|
||||||
|
echo "文件权限: $(stat -c '%a %n' "$test_file")"
|
||||||
|
echo "文件所有者: $(stat -c '%U:%G' "$test_file")"
|
||||||
|
|
||||||
|
# 测试所有Web用户的权限(通过组权限)
|
||||||
|
for test_user in "www-data" "www" "apache" "nginx"; do
|
||||||
|
if id "$test_user" &>/dev/null; then
|
||||||
|
echo "🔍 测试 $test_user 用户权限(通过组权限):"
|
||||||
|
|
||||||
|
# 显示用户组信息(安全的变量处理)
|
||||||
|
user_groups=$(id -Gn "$test_user" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//')
|
||||||
|
echo " 📋 所属组: ${user_groups:-无}"
|
||||||
|
|
||||||
|
# 测试读权限(安全:只读不修改)
|
||||||
|
if su -s /bin/sh -c "cat '$test_file' >/dev/null 2>&1" "$test_user" 2>/dev/null; then
|
||||||
|
echo " ✅ 读权限: 通过组权限可读"
|
||||||
|
else
|
||||||
|
echo " ❌ 读权限: 不可读"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 测试写权限(使用临时文件,避免污染原文件)
|
||||||
|
temp_test_file="${test_file}.write_test_${test_user}"
|
||||||
|
if su -s /bin/sh -c "echo 'permission_test' > '$temp_test_file' 2>/dev/null" "$test_user" 2>/dev/null; then
|
||||||
|
echo " ✅ 写权限: 通过组权限可写"
|
||||||
|
rm -f "$temp_test_file" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo " ❌ 写权限: 不可写"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 测试目录创建权限(使用临时目录)
|
||||||
|
temp_test_dir="${APP_ROOT}/.perm_test_${test_user}"
|
||||||
|
if su -s /bin/sh -c "mkdir -p '$temp_test_dir' 2>/dev/null" "$test_user" 2>/dev/null; then
|
||||||
|
echo " ✅ 创建目录: 通过组权限可创建"
|
||||||
|
rm -rf "$temp_test_dir" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo " ❌ 创建目录: 不可创建"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " 🔗 权限来源: 统一Web组 ($WEB_GROUP) 775权限"
|
||||||
|
break # 只测试第一个可用的用户即可验证效果
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 清理专用测试文件(如果是创建的)
|
||||||
|
if echo "$test_file" | grep -q "\.permission_test\.html$"; then
|
||||||
|
rm -f "$test_file" 2>/dev/null
|
||||||
|
echo "🧹 已清理临时测试文件"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ 无法找到或创建测试文件,跳过权限验证"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 显示统一组和用户状态
|
||||||
|
echo "=== 统一Web组状态检查 ==="
|
||||||
|
if getent group "$WEB_GROUP" &>/dev/null; then
|
||||||
|
echo "✅ 统一Web组 '$WEB_GROUP' 存在"
|
||||||
|
echo "组信息: $(getent group "$WEB_GROUP" 2>/dev/null || echo '获取失败')"
|
||||||
|
|
||||||
|
# 检查哪些用户在统一组中
|
||||||
|
echo "统一组成员检查:"
|
||||||
|
for web_user in "www-data" "www" "apache" "nginx"; do
|
||||||
|
if id "$web_user" &>/dev/null; then
|
||||||
|
if id -Gn "$web_user" | grep -q "$WEB_GROUP"; then
|
||||||
|
echo "✅ $web_user 在统一组 '$WEB_GROUP' 中"
|
||||||
|
else
|
||||||
|
echo "❌ $web_user 不在统一组 '$WEB_GROUP' 中"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ $web_user 用户不存在"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "❌ 统一Web组 '$WEB_GROUP' 不存在"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== 启动应用 ==="
|
||||||
|
|
||||||
|
# 执行原有的启动命令
|
||||||
|
exec "$@"
|
||||||
@@ -12,19 +12,42 @@ autostart=true
|
|||||||
autorestart=true
|
autorestart=true
|
||||||
startretries=3
|
startretries=3
|
||||||
startsecs=1
|
startsecs=1
|
||||||
stdout_logfile=/dev/stdout
|
stopasgroup=true
|
||||||
stdout_logfile_maxbytes=0
|
killasgroup=true
|
||||||
stderr_logfile=/dev/stderr
|
stdout_logfile=/var/log/supervisor/php-fpm.log
|
||||||
stderr_logfile_maxbytes=0
|
stdout_logfile_maxbytes=10MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
stderr_logfile=/var/log/supervisor/php-fpm-error.log
|
||||||
|
stderr_logfile_maxbytes=10MB
|
||||||
|
stderr_logfile_backups=10
|
||||||
|
|
||||||
[program:think-cron]
|
[program:think-cron]
|
||||||
command=php /var/www/html/think cron:schedule
|
command=php /var/www/html/think cron:schedule
|
||||||
environment=APP_ENV=local
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
numprocs=1
|
||||||
autostart=true
|
autostart=true
|
||||||
autorestart=true
|
autorestart=true
|
||||||
startretries=5
|
startretries=3
|
||||||
startsecs=2
|
stdout_logfile=/var/log/supervisor/think-cron.log
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile_maxbytes=10MB
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_backups=10
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/var/log/supervisor/think-cron-error.log
|
||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=10MB
|
||||||
|
stderr_logfile_backups=10
|
||||||
|
startsecs=3
|
||||||
|
stopwaitsecs=10
|
||||||
|
|
||||||
|
[program:websocket-server]
|
||||||
|
command=/bin/bash -c "if [ -f /var/www/html/ws_server.php ]; then php ./ws_server.php; else echo 'ws_server.php not found, skipping websocket server'; fi"
|
||||||
|
workdir=/var/www/html
|
||||||
|
autostart=true
|
||||||
|
autorestart=false
|
||||||
|
startretries=0
|
||||||
|
stdout_logfile=/var/log/supervisor/websocket-server.log
|
||||||
|
stdout_logfile_maxbytes=10MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
stderr_logfile=/var/log/supervisor/websocket-server-error.log
|
||||||
|
stderr_logfile_maxbytes=10MB
|
||||||
|
stderr_logfile_backups=10
|
||||||
|
startsecs=3
|
||||||
|
stopwaitsecs=10
|
||||||
|
|||||||
BIN
docker/php/websocat
Normal file
9
docker/redis_data/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 忽略所有文件
|
||||||
|
*
|
||||||
|
|
||||||
|
# 只保留指定的 .gitkeep 文件
|
||||||
|
!.gitignore
|
||||||
|
!development/.gitkeep
|
||||||
|
!test/.gitkeep
|
||||||
|
!production/.gitkeep
|
||||||
|
!staging/.gitkeep
|
||||||
0
docker/redis_data/.gitkeep
Normal file
10
docker/xdebug_logs/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# 忽略目录下所有文件和子目录
|
||||||
|
*
|
||||||
|
# 忽略所有子目录
|
||||||
|
*/
|
||||||
|
# 但不忽略 .gitkeep 文件
|
||||||
|
!.gitkeep
|
||||||
|
# 不忽略 .gitignore 文件自身
|
||||||
|
!.gitignore
|
||||||
|
# 不忽略 development/.gitkeep 文件
|
||||||
|
!development/.gitkeep
|
||||||
0
docker/xdebug_logs/.gitkeep
Normal file
670
docs/common/CLodop.md
Normal file
@@ -0,0 +1,670 @@
|
|||||||
|
好的!我来详细介绍一下**Web打印服务CLodop**,这是一个非常强大的浏览器打印解决方案。
|
||||||
|
|
||||||
|
## 🖨️ **CLodop - 专业Web打印服务详解**
|
||||||
|
|
||||||
|
### **1. CLodop 是什么?**
|
||||||
|
|
||||||
|
**CLodop**(Cloud Lodop)是**C-Lodop 云打印服务**的简称,是 Lodop 技术的一个轻量级版本,专门为 Web 应用提供强大的打印功能。
|
||||||
|
|
||||||
|
#### **核心特点**
|
||||||
|
- ✅ **跨浏览器兼容** - 支持所有主流浏览器
|
||||||
|
- ✅ **无需安装插件** - 基于云服务架构
|
||||||
|
- ✅ **精确打印控制** - 像素级打印精度
|
||||||
|
- ✅ **批量打印支持** - 高效处理大量打印任务
|
||||||
|
- ✅ **多种打印方式** - 直接打印、预览打印、设计打印
|
||||||
|
|
||||||
|
### **2. CLodop 与 Lodop 的区别**
|
||||||
|
|
||||||
|
| 特性 | CLodop(云打印) | Lodop(传统打印) |
|
||||||
|
|------|-----------------|------------------|
|
||||||
|
| **架构** | 云服务模式,无需安装 | 需要安装本地插件 |
|
||||||
|
| **部署** | 服务端部署,客户端零配置 | 每台客户端都需要安装 |
|
||||||
|
| **更新** | 服务端统一更新 | 每台客户端单独更新 |
|
||||||
|
| **兼容性** | 支持所有现代浏览器 | 对高版本浏览器支持有限 |
|
||||||
|
| **适用场景** | Web应用、移动端 | 企业内部系统、局域网 |
|
||||||
|
|
||||||
|
### **3. CLodop 核心架构**
|
||||||
|
|
||||||
|
#### **系统架构图**
|
||||||
|
```
|
||||||
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||||
|
│ Web应用 │ -> │ CLodop服务 │ -> │ 打印机 │
|
||||||
|
│ (浏览器) │ │ (服务端) │ │ (本地/网络) │
|
||||||
|
└─────────────┘ └─────────────┘ └─────────────┘
|
||||||
|
│ │ │
|
||||||
|
JavaScript 打印服务 打印输出
|
||||||
|
API 任务队列
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4. 完整安装和配置**
|
||||||
|
|
||||||
|
#### **4.1 服务端安装(Windows)**
|
||||||
|
```bash
|
||||||
|
# 下载CLodop服务端
|
||||||
|
# 官方下载地址:http://www.c-lodop.com/download.html
|
||||||
|
|
||||||
|
# 安装步骤:
|
||||||
|
1. 下载 CLodop_Setup.exe
|
||||||
|
2. 以管理员身份运行安装
|
||||||
|
3. 默认安装目录:C:\Program Files (x86)\CLodop
|
||||||
|
4. 服务自动启动,监听端口:8000、18000
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **4.2 服务端配置文件**
|
||||||
|
```json
|
||||||
|
// CLodop 服务配置 (config.json)
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"port": 8000,
|
||||||
|
"sslPort": 8443,
|
||||||
|
"host": "0.0.0.0"
|
||||||
|
},
|
||||||
|
"print": {
|
||||||
|
"defaultPaper": "A4",
|
||||||
|
"dpi": 300,
|
||||||
|
"timeout": 30000
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"allowedOrigins": ["http://localhost:3000", "https://yourdomain.com"],
|
||||||
|
"authRequired": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **4.3 验证安装**
|
||||||
|
```bash
|
||||||
|
# 检查服务状态
|
||||||
|
netstat -ano | findstr :8000
|
||||||
|
|
||||||
|
# 访问测试页面
|
||||||
|
http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### **5. 前端集成完整代码**
|
||||||
|
|
||||||
|
#### **5.1 基础集成方案**
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CLodop 打印示例</title>
|
||||||
|
<!-- 引入CLodop JS文件 -->
|
||||||
|
<script src="http://localhost:8000/CLodopfuncs.js"></script>
|
||||||
|
<script>
|
||||||
|
// 检查CLodop服务状态
|
||||||
|
function checkCLodop() {
|
||||||
|
try {
|
||||||
|
if (getCLodop()) {
|
||||||
|
console.log('CLodop服务已就绪');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.warn('CLodop服务未启动');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('CLodop检查失败:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取CLodop对象
|
||||||
|
function getCLodop() {
|
||||||
|
if (window.getCLodop) {
|
||||||
|
return window.getLodop();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="checkCLodop()">
|
||||||
|
<!-- 打印内容 -->
|
||||||
|
<div id="printContent">
|
||||||
|
<h1>可打印内容</h1>
|
||||||
|
<table border="1" style="width:100%">
|
||||||
|
<tr><th>姓名</th><th>年龄</th><th>职位</th></tr>
|
||||||
|
<tr><td>张三</td><td>30</td><td>工程师</td></tr>
|
||||||
|
<tr><td>李四</td><td>25</td><td>设计师</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onclick="printDirect()">直接打印</button>
|
||||||
|
<button onclick="printPreview()">打印预览</button>
|
||||||
|
<button onclick="printDesign()">打印设计</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **5.2 高级打印控制器**
|
||||||
|
```javascript
|
||||||
|
// clodop-manager.js
|
||||||
|
class CLodopManager {
|
||||||
|
constructor() {
|
||||||
|
this.lodop = null;
|
||||||
|
this.isReady = false;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化CLodop
|
||||||
|
init() {
|
||||||
|
if (typeof window.getCLodop === 'undefined') {
|
||||||
|
console.error('CLodop未加载,请检查脚本引入');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lodop = window.getLodop();
|
||||||
|
if (this.lodop) {
|
||||||
|
this.isReady = true;
|
||||||
|
console.log('CLodop初始化成功');
|
||||||
|
} else {
|
||||||
|
console.error('CLodop初始化失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查服务状态
|
||||||
|
checkStatus() {
|
||||||
|
if (!this.lodop) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const status = this.lodop.PRINT_STATUS;
|
||||||
|
return status === 'READY';
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建打印任务
|
||||||
|
createPrintJob(title = '打印文档') {
|
||||||
|
if (!this.isReady) {
|
||||||
|
throw new Error('CLodop未就绪');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lodop.PRINT_INIT(title);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置打印内容
|
||||||
|
setContent(htmlContent, options = {}) {
|
||||||
|
const config = {
|
||||||
|
top: options.top || '10mm',
|
||||||
|
left: options.left || '10mm',
|
||||||
|
width: options.width || '190mm',
|
||||||
|
height: options.height || '277mm',
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
|
||||||
|
this.lodop.ADD_PRINT_HTML(
|
||||||
|
config.top, config.left, config.width, config.height,
|
||||||
|
htmlContent
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置打印机
|
||||||
|
setPrinter(printerName = '') {
|
||||||
|
if (printerName) {
|
||||||
|
this.lodop.SET_PRINTER_INDEX(printerName);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置纸张大小
|
||||||
|
setPaperSize(paperName = 'A4') {
|
||||||
|
this.lodop.SET_PRINT_PAGESIZE(1, 0, 0, paperName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置打印份数
|
||||||
|
setCopies(copies = 1) {
|
||||||
|
this.lodop.SET_PRINT_COPIES(copies);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接打印
|
||||||
|
printDirect() {
|
||||||
|
if (!this.isReady) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.lodop.PRINT();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('打印失败:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印预览
|
||||||
|
printPreview() {
|
||||||
|
if (!this.isReady) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.lodop.PREVIEW();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('预览失败:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印设计
|
||||||
|
printDesign() {
|
||||||
|
if (!this.isReady) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.lodop.PRINT_DESIGN();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('设计失败:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量打印
|
||||||
|
batchPrint(documents = []) {
|
||||||
|
if (!this.isReady) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
documents.forEach((doc, index) => {
|
||||||
|
this.lodop.PRINT_INIT(`文档${index + 1}`);
|
||||||
|
this.lodop.ADD_PRINT_HTML("10mm", "10mm", "190mm", "277mm", doc);
|
||||||
|
|
||||||
|
if (index < documents.length - 1) {
|
||||||
|
this.lodop.NEWPAGE(); // 分页
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.lodop.PREVIEW();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('批量打印失败:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局实例
|
||||||
|
window.clodopManager = new CLodopManager();
|
||||||
|
```
|
||||||
|
|
||||||
|
### **6. 实际应用示例**
|
||||||
|
|
||||||
|
#### **6.1 票据打印**
|
||||||
|
```javascript
|
||||||
|
// receipt-print.js
|
||||||
|
function printReceipt(orderData) {
|
||||||
|
const manager = window.clodopManager;
|
||||||
|
if (!manager.isReady) {
|
||||||
|
alert('打印服务未就绪');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const receiptHTML = `
|
||||||
|
<div style="width:80mm;font-family:'宋体';font-size:12px;">
|
||||||
|
<h3 style="text-align:center;">销售小票</h3>
|
||||||
|
<hr>
|
||||||
|
<p><strong>订单号:</strong>${orderData.orderNo}</p>
|
||||||
|
<p><strong>时间:</strong>${new Date().toLocaleString()}</p>
|
||||||
|
<hr>
|
||||||
|
<table style="width:100%;">
|
||||||
|
${orderData.items.map(item => `
|
||||||
|
<tr>
|
||||||
|
<td>${item.name}</td>
|
||||||
|
<td>×${item.quantity}</td>
|
||||||
|
<td>¥${item.price}</td>
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:right;"><strong>总计:¥${orderData.total}</strong></p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
manager.createPrintJob('销售小票')
|
||||||
|
.setPaperSize(1) // 1=80mm 小票
|
||||||
|
.setContent(receiptHTML, {
|
||||||
|
width: '80mm',
|
||||||
|
height: 'auto'
|
||||||
|
})
|
||||||
|
.printDirect();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **6.2 报表打印**
|
||||||
|
```javascript
|
||||||
|
// report-print.js
|
||||||
|
function printReport(reportData) {
|
||||||
|
const manager = window.clodopManager;
|
||||||
|
|
||||||
|
const reportHTML = `
|
||||||
|
<div style="font-family:'微软雅黑';padding:20px;">
|
||||||
|
<h1 style="text-align:center;">${reportData.title}</h1>
|
||||||
|
<table border="1" style="width:100%;border-collapse:collapse;">
|
||||||
|
<thead>
|
||||||
|
<tr style="background:#f5f5f5;">
|
||||||
|
${reportData.headers.map(header =>
|
||||||
|
`<th style="padding:8px;">${header}</th>`
|
||||||
|
).join('')}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${reportData.rows.map(row => `
|
||||||
|
<tr>
|
||||||
|
${row.map(cell =>
|
||||||
|
`<td style="padding:6px;">${cell}</td>`
|
||||||
|
).join('')}
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div style="margin-top:20px;">
|
||||||
|
<p>打印时间:${new Date().toLocaleString()}</p>
|
||||||
|
<p>打印人:${reportData.printUser}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
manager.createPrintJob(reportData.title)
|
||||||
|
.setPaperSize('A4')
|
||||||
|
.setContent(reportHTML)
|
||||||
|
.setPrinter(reportData.printer || '')
|
||||||
|
.printPreview();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **6.3 标签打印**
|
||||||
|
```javascript
|
||||||
|
// label-print.js
|
||||||
|
function printLabels(labelsData) {
|
||||||
|
const manager = window.clodopManager;
|
||||||
|
|
||||||
|
manager.createPrintJob('产品标签');
|
||||||
|
|
||||||
|
labelsData.forEach((label, index) => {
|
||||||
|
const labelHTML = `
|
||||||
|
<div style="width:50mm;height:30mm;border:1px dotted #ccc;padding:5mm;font-size:10px;">
|
||||||
|
<div style="text-align:center;font-weight:bold;">${label.productName}</div>
|
||||||
|
<div>规格:${label.spec}</div>
|
||||||
|
<div>批次:${label.batchNo}</div>
|
||||||
|
<div>有效期:${label.expiryDate}</div>
|
||||||
|
<div style="text-align:center;margin-top:2mm;">
|
||||||
|
<img src="${label.barcodeUrl}" style="height:15mm;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
manager.setContent(labelHTML, {
|
||||||
|
top: `${(index % 5) * 32}mm`,
|
||||||
|
left: `${Math.floor(index / 5) * 52}mm`,
|
||||||
|
width: '50mm',
|
||||||
|
height: '30mm'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (index < labelsData.length - 1) {
|
||||||
|
manager.lodop.NEWPAGE();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
manager.printPreview();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **7. 高级功能实现**
|
||||||
|
|
||||||
|
#### **7.1 打印状态监控**
|
||||||
|
```javascript
|
||||||
|
// print-monitor.js
|
||||||
|
class PrintMonitor {
|
||||||
|
constructor() {
|
||||||
|
this.printJobs = new Map();
|
||||||
|
this.initEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
initEvents() {
|
||||||
|
// 监听打印开始
|
||||||
|
window.addEventListener('beforeprint', (e) => {
|
||||||
|
console.log('打印开始');
|
||||||
|
this.onPrintStart(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听打印结束
|
||||||
|
window.addEventListener('afterprint', (e) => {
|
||||||
|
console.log('打印结束');
|
||||||
|
this.onPrintEnd(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onPrintStart(jobId) {
|
||||||
|
this.printJobs.set(jobId, {
|
||||||
|
startTime: new Date(),
|
||||||
|
status: 'printing'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onPrintEnd(jobId, success = true) {
|
||||||
|
const job = this.printJobs.get(jobId);
|
||||||
|
if (job) {
|
||||||
|
job.endTime = new Date();
|
||||||
|
job.status = success ? 'completed' : 'failed';
|
||||||
|
job.duration = job.endTime - job.startTime;
|
||||||
|
|
||||||
|
// 发送打印统计
|
||||||
|
this.sendPrintStatistics(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendPrintStatistics(job) {
|
||||||
|
// 发送到服务器记录
|
||||||
|
fetch('/api/print/log', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(job)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取打印机列表
|
||||||
|
getPrinterList() {
|
||||||
|
const lodop = getCLodop();
|
||||||
|
if (!lodop) return [];
|
||||||
|
|
||||||
|
const printers = [];
|
||||||
|
const count = lodop.GET_PRINTER_COUNT();
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
printers.push({
|
||||||
|
name: lodop.GET_PRINTER_NAME(i),
|
||||||
|
status: lodop.GET_PRINTER_STATUS(i)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return printers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **7.2 错误处理和重试机制**
|
||||||
|
```javascript
|
||||||
|
// error-handler.js
|
||||||
|
class PrintErrorHandler {
|
||||||
|
static async printWithRetry(printFunction, maxRetries = 3) {
|
||||||
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
const result = await printFunction();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`打印尝试 ${attempt} 失败:`, error);
|
||||||
|
|
||||||
|
if (attempt === maxRetries) {
|
||||||
|
throw new Error(`打印失败,已重试 ${maxRetries} 次`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待后重试
|
||||||
|
await this.delay(1000 * attempt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static delay(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
static handleCommonErrors(error) {
|
||||||
|
const errorMap = {
|
||||||
|
'PRINTER_NOT_FOUND': '打印机未找到,请检查打印机连接',
|
||||||
|
'OUT_OF_PAPER': '打印机缺纸,请添加纸张',
|
||||||
|
'SERVICE_UNAVAILABLE': '打印服务不可用,请检查CLodop服务',
|
||||||
|
'TIMEOUT': '打印超时,请重试'
|
||||||
|
};
|
||||||
|
|
||||||
|
const message = errorMap[error.code] || `打印错误: ${error.message}`;
|
||||||
|
this.showErrorDialog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showErrorDialog(message) {
|
||||||
|
// 可以替换为更友好的UI提示
|
||||||
|
alert(`打印错误: ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **8. 部署和配置最佳实践**
|
||||||
|
|
||||||
|
#### **8.1 Docker 部署**
|
||||||
|
```dockerfile
|
||||||
|
# Dockerfile
|
||||||
|
FROM windows/servercore:ltsc2019
|
||||||
|
|
||||||
|
# 安装CLodop服务
|
||||||
|
COPY CLodop_Setup.exe /setup/
|
||||||
|
RUN /setup/CLodop_Setup.exe /S
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 8000 18000
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
CMD ["C:\\Program Files (x86)\\CLodop\\CLodop.exe", "-start"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **8.2 Nginx 反向代理配置**
|
||||||
|
```nginx
|
||||||
|
# nginx.conf
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name print.yourdomain.com;
|
||||||
|
|
||||||
|
location /CLodop/ {
|
||||||
|
proxy_pass http://localhost:8000/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
}
|
||||||
|
|
||||||
|
# WebSocket 支持
|
||||||
|
location /CLodop/ws {
|
||||||
|
proxy_pass http://localhost:8000/ws;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **9. 安全配置**
|
||||||
|
|
||||||
|
#### **9.1 访问控制**
|
||||||
|
```javascript
|
||||||
|
// security-middleware.js
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
// IP白名单
|
||||||
|
const allowedIPs = ['192.168.1.0/24', '10.0.0.0/8'];
|
||||||
|
|
||||||
|
app.use('/print', (req, res, next) => {
|
||||||
|
const clientIP = req.ip || req.connection.remoteAddress;
|
||||||
|
|
||||||
|
if (!isIPAllowed(clientIP, allowedIPs)) {
|
||||||
|
return res.status(403).json({ error: '访问被拒绝' });
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
function isIPAllowed(ip, allowedRanges) {
|
||||||
|
// IP地址验证逻辑
|
||||||
|
return allowedRanges.some(range => {
|
||||||
|
// 简单的IP范围检查实现
|
||||||
|
return ip.startsWith(range.split('.')[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **10. 性能优化**
|
||||||
|
|
||||||
|
#### **10.1 打印任务队列**
|
||||||
|
```javascript
|
||||||
|
// print-queue.js
|
||||||
|
class PrintQueue {
|
||||||
|
constructor() {
|
||||||
|
this.queue = [];
|
||||||
|
this.isProcessing = false;
|
||||||
|
this.maxConcurrent = 1; // 串行打印
|
||||||
|
}
|
||||||
|
|
||||||
|
async addJob(printJob) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.queue.push({ printJob, resolve, reject });
|
||||||
|
this.processQueue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async processQueue() {
|
||||||
|
if (this.isProcessing || this.queue.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isProcessing = true;
|
||||||
|
|
||||||
|
while (this.queue.length > 0) {
|
||||||
|
const { printJob, resolve, reject } = this.queue.shift();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await printJob();
|
||||||
|
resolve(result);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 延迟一下,避免打印机过载
|
||||||
|
await this.delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isProcessing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 **总结**
|
||||||
|
|
||||||
|
### **CLodop 核心优势**
|
||||||
|
1. **零客户端安装** - 基于云服务架构
|
||||||
|
2. **完美浏览器兼容** - 支持所有现代浏览器
|
||||||
|
3. **企业级功能** - 批量打印、精确控制、多种纸张支持
|
||||||
|
4. **易于集成** - 简单的 JavaScript API
|
||||||
|
|
||||||
|
### **适用场景**
|
||||||
|
- ✅ **企业ERP系统** - 报表、单据打印
|
||||||
|
- ✅ **电商平台** - 订单、发货单打印
|
||||||
|
- ✅ **医疗系统** - 处方、报告打印
|
||||||
|
- ✅ **政府办公** - 公文、证件打印
|
||||||
|
- ✅ **教育系统** - 成绩单、证书打印
|
||||||
|
|
||||||
|
### **部署建议**
|
||||||
|
1. **开发环境**:本地安装CLodop服务
|
||||||
|
2. **测试环境**:内网服务器部署
|
||||||
|
3. **生产环境**:高可用集群部署,配合负载均衡
|
||||||
|
|
||||||
|
CLodop 是解决Web打印难题的优秀方案,特别适合需要精确控制打印格式的企业级应用!
|
||||||
605
docs/db/PROCEDURE_DEV_v2.0.md
Normal file
@@ -0,0 +1,605 @@
|
|||||||
|
# 开发中使用的存储过程
|
||||||
|
|
||||||
|
|
||||||
|
## 统计一下,数据库中哪些表中有site_id字段或者store_id字段,而且表中是有数据的
|
||||||
|
|
||||||
|
```sql
|
||||||
|
|
||||||
|
-- 检查符合条件的表
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE PROCEDURE CheckTablesWithHasData()
|
||||||
|
BEGIN
|
||||||
|
DECLARE done INT DEFAULT FALSE;
|
||||||
|
DECLARE tbl_name VARCHAR(255);
|
||||||
|
DECLARE cur CURSOR FOR
|
||||||
|
SELECT DISTINCT TABLE_NAME
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE COLUMN_NAME IN ('site_id', 'store_id')
|
||||||
|
AND TABLE_SCHEMA = DATABASE(); -- 使用当前数据库
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE tmp_results (table_name VARCHAR(255));
|
||||||
|
|
||||||
|
OPEN cur;
|
||||||
|
|
||||||
|
read_loop: LOOP
|
||||||
|
FETCH cur INTO tbl_name;
|
||||||
|
IF done THEN
|
||||||
|
LEAVE read_loop;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET @sql = CONCAT('INSERT INTO tmp_results SELECT ''', tbl_name, ''' FROM ', tbl_name, ' HAVING COUNT(*) > 0');
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE cur;
|
||||||
|
|
||||||
|
SELECT table_name FROM tmp_results;
|
||||||
|
DROP TEMPORARY TABLE tmp_results;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- 执行
|
||||||
|
CALL CheckTablesWithHasData();
|
||||||
|
|
||||||
|
--- 结果
|
||||||
|
+-----------------+
|
||||||
|
| table_name |
|
||||||
|
+-----------------+
|
||||||
|
| t_order_info |
|
||||||
|
| t_order_item |
|
||||||
|
| t_order_payment |
|
||||||
|
| t_order_refund |
|
||||||
|
+-----------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## 统计一下,数据库中哪些表中是有数据的
|
||||||
|
|
||||||
|
```sql
|
||||||
|
|
||||||
|
-- 检查符合条件的表
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE PROCEDURE CheckTablesIsNotEmpty()
|
||||||
|
BEGIN
|
||||||
|
DECLARE done INT DEFAULT FALSE;
|
||||||
|
DECLARE tbl_name VARCHAR(255);
|
||||||
|
DECLARE cur CURSOR FOR
|
||||||
|
SELECT DISTINCT TABLE_NAME
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE(); -- 使用当前数据库
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE tmp_results (table_name VARCHAR(255));
|
||||||
|
|
||||||
|
OPEN cur;
|
||||||
|
|
||||||
|
read_loop: LOOP
|
||||||
|
FETCH cur INTO tbl_name;
|
||||||
|
IF done THEN
|
||||||
|
LEAVE read_loop;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET @sql = CONCAT('INSERT INTO tmp_results SELECT ''', tbl_name, ''' FROM ', tbl_name, ' HAVING COUNT(*) > 0');
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE cur;
|
||||||
|
|
||||||
|
SELECT table_name FROM tmp_results;
|
||||||
|
DROP TEMPORARY TABLE tmp_results;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- 执行
|
||||||
|
CALL CheckTablesIsNotEmpty();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 对于空表或者无数据表,重置 AUTO_INCREMENT
|
||||||
|
|
||||||
|
```sql
|
||||||
|
|
||||||
|
-- 定义存储过程
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE PROCEDURE ResetAutoIncrementForEmptyTables()
|
||||||
|
BEGIN
|
||||||
|
DECLARE done INT DEFAULT FALSE;
|
||||||
|
DECLARE tbl_name VARCHAR(255);
|
||||||
|
DECLARE cnt BIGINT;
|
||||||
|
|
||||||
|
-- 声明游标:获取所有表名
|
||||||
|
DECLARE cur CURSOR FOR
|
||||||
|
SELECT DISTINCT c.TABLE_NAME
|
||||||
|
FROM information_schema.COLUMNS c
|
||||||
|
INNER JOIN information_schema.TABLES t
|
||||||
|
ON c.TABLE_SCHEMA = t.TABLE_SCHEMA
|
||||||
|
AND c.TABLE_NAME = t.TABLE_NAME
|
||||||
|
WHERE
|
||||||
|
c.TABLE_SCHEMA = DATABASE()
|
||||||
|
AND t.TABLE_TYPE = 'BASE TABLE'; -- 排除视图
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||||
|
|
||||||
|
OPEN cur;
|
||||||
|
|
||||||
|
read_loop: LOOP
|
||||||
|
FETCH cur INTO tbl_name;
|
||||||
|
IF done THEN
|
||||||
|
LEAVE read_loop;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 动态获取行数
|
||||||
|
SET @sql = CONCAT('SELECT COUNT(*) INTO @cnt FROM `', tbl_name, '`');
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 如果为空,重置 AUTO_INCREMENT
|
||||||
|
IF @cnt = 0 THEN
|
||||||
|
SET @reset_sql = CONCAT('ALTER TABLE `', tbl_name, '` AUTO_INCREMENT = 1');
|
||||||
|
PREPARE reset_stmt FROM @reset_sql;
|
||||||
|
EXECUTE reset_stmt;
|
||||||
|
DEALLOCATE PREPARE reset_stmt;
|
||||||
|
SELECT CONCAT('Reset AUTO_INCREMENT for table: ', tbl_name) AS message;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE cur;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- 执行
|
||||||
|
|
||||||
|
CALL ResetAutoIncrementForEmptyTables();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 数据重置到初始化状态
|
||||||
|
|
||||||
|
|
||||||
|
### 1. 删除数据,保留表结构,当表中有site_id字段时,只删除site_id不为0的数据
|
||||||
|
|
||||||
|
```sql
|
||||||
|
|
||||||
|
-- 定义存储过程
|
||||||
|
-- 增强版数据库重置脚本
|
||||||
|
-- 支持 MySQL/PostgreSQL/SQL Server
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
DROP PROCEDURE IF EXISTS reset_tables_has_site_id_where;
|
||||||
|
CREATE PROCEDURE reset_tables_has_site_id_where(
|
||||||
|
IN p_preserve_site_zero BOOLEAN, -- 是否保留 site_id = 0 的数据
|
||||||
|
IN p_dry_run BOOLEAN, -- 是否试运行(不实际执行)
|
||||||
|
IN p_exclude_tables TEXT -- 排除的表列表,逗号分隔
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
DECLARE v_done INT DEFAULT FALSE;
|
||||||
|
DECLARE v_table_name VARCHAR(255);
|
||||||
|
DECLARE v_has_site_id INT DEFAULT 0;
|
||||||
|
DECLARE v_table_count INT DEFAULT 0;
|
||||||
|
DECLARE v_processed_count INT DEFAULT 0;
|
||||||
|
DECLARE v_skipped_count INT DEFAULT 0;
|
||||||
|
DECLARE v_error_count INT DEFAULT 0;
|
||||||
|
DECLARE v_no_site_id_tables TEXT DEFAULT '';
|
||||||
|
DECLARE v_excluded_tables TEXT DEFAULT '';
|
||||||
|
|
||||||
|
-- 游标声明
|
||||||
|
DECLARE table_cursor CURSOR FOR
|
||||||
|
SELECT TABLE_NAME
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_TYPE = 'BASE TABLE'
|
||||||
|
AND TABLE_NAME NOT IN (
|
||||||
|
'sys_operation_log', 'sys_login_log', 'system_parameters' -- 系统表默认排除
|
||||||
|
)
|
||||||
|
ORDER BY TABLE_NAME;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
|
||||||
|
|
||||||
|
-- 创建详细的日志表
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS reset_operation_log;
|
||||||
|
CREATE TEMPORARY TABLE reset_operation_log (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
table_name VARCHAR(255) NOT NULL,
|
||||||
|
action_type ENUM('CLEARED', 'SKIPPED', 'ERROR', 'EXCLUDED') NOT NULL,
|
||||||
|
records_affected INT DEFAULT 0,
|
||||||
|
sql_statement TEXT,
|
||||||
|
error_message TEXT,
|
||||||
|
execution_time_ms INT DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 开始事务(确保原子性)
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
OPEN table_cursor;
|
||||||
|
|
||||||
|
process_tables: LOOP
|
||||||
|
FETCH table_cursor INTO v_table_name;
|
||||||
|
IF v_done THEN
|
||||||
|
LEAVE process_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET v_table_count = v_table_count + 1;
|
||||||
|
|
||||||
|
-- 检查是否在排除列表中
|
||||||
|
IF FIND_IN_SET(v_table_name, p_exclude_tables) > 0 OR
|
||||||
|
FIND_IN_SET(v_table_name, v_excluded_tables) > 0 THEN
|
||||||
|
INSERT INTO reset_operation_log (table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'EXCLUDED', 0, '表在排除列表中,跳过处理');
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
ITERATE process_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 检查表是否有 site_id 字段
|
||||||
|
SELECT COUNT(*) INTO v_has_site_id
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = v_table_name
|
||||||
|
AND COLUMN_NAME = 'site_id';
|
||||||
|
|
||||||
|
SET @start_time = UNIX_TIMESTAMP(NOW(3)) * 1000;
|
||||||
|
|
||||||
|
IF v_has_site_id > 0 THEN
|
||||||
|
-- 构建动态SQL
|
||||||
|
IF p_preserve_site_zero THEN
|
||||||
|
SET @sql = CONCAT('DELETE FROM `', v_table_name, '` WHERE site_id != 0');
|
||||||
|
ELSE
|
||||||
|
SET @sql = CONCAT('TRUNCATE TABLE `', v_table_name, '`');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errmsg = MESSAGE_TEXT;
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement, error_message)
|
||||||
|
VALUES (v_table_name, 'ERROR', 0, @sql, CONCAT(@sqlstate, ' - ', @errmsg));
|
||||||
|
SET v_error_count = v_error_count + 1;
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF p_dry_run THEN
|
||||||
|
-- 试运行模式,只记录不执行
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'SKIPPED', 0, CONCAT('试运行: ', @sql));
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
ELSE
|
||||||
|
-- 实际执行
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @row_count = ROW_COUNT();
|
||||||
|
SET @end_time = UNIX_TIMESTAMP(NOW(3)) * 1000;
|
||||||
|
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement, execution_time_ms)
|
||||||
|
VALUES (v_table_name, 'CLEARED', @row_count, @sql, (@end_time - @start_time));
|
||||||
|
|
||||||
|
SET v_processed_count = v_processed_count + 1;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
ELSE
|
||||||
|
-- 表没有 site_id 字段
|
||||||
|
SET v_no_site_id_tables = CONCAT_WS(', ', v_no_site_id_tables, v_table_name);
|
||||||
|
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'SKIPPED', 0, '表没有 site_id 字段,跳过处理');
|
||||||
|
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET v_has_site_id = 0;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE table_cursor;
|
||||||
|
|
||||||
|
IF p_dry_run THEN
|
||||||
|
ROLLBACK; -- 试运行模式回滚
|
||||||
|
SELECT '=== 试运行模式 - 未实际执行任何操作 ===' as notice;
|
||||||
|
ELSE
|
||||||
|
COMMIT; -- 提交事务
|
||||||
|
SELECT '=== 数据库重置完成 ===' as summary;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 生成总结报告
|
||||||
|
SELECT
|
||||||
|
CONCAT('数据库: ', DATABASE()) as database_info,
|
||||||
|
CONCAT('开始时间: ', DATE_FORMAT(MIN(log_time), '%Y-%m-%d %H:%i:%s')) as start_time,
|
||||||
|
CONCAT('结束时间: ', DATE_FORMAT(MAX(log_time), '%Y-%m-%d %H:%i:%s')) as end_time,
|
||||||
|
CONCAT('总表数: ', v_table_count) as total_tables,
|
||||||
|
CONCAT('已处理表: ', v_processed_count) as processed_tables,
|
||||||
|
CONCAT('跳过表: ', v_skipped_count) as skipped_tables,
|
||||||
|
CONCAT('错误数: ', v_error_count) as error_count,
|
||||||
|
CONCAT('总耗时: ', SUM(execution_time_ms), 'ms') as total_duration
|
||||||
|
FROM reset_operation_log;
|
||||||
|
|
||||||
|
-- 显示没有 site_id 字段的表
|
||||||
|
IF v_no_site_id_tables != '' THEN
|
||||||
|
SELECT
|
||||||
|
'以下表没有 site_id 字段,已被跳过:' as warning_title,
|
||||||
|
v_no_site_id_tables as skipped_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 显示错误详情
|
||||||
|
IF v_error_count > 0 THEN
|
||||||
|
SELECT '=== 错误详情 ===' as error_title;
|
||||||
|
SELECT table_name, error_message, sql_statement
|
||||||
|
FROM reset_operation_log
|
||||||
|
WHERE action_type = 'ERROR'
|
||||||
|
ORDER BY log_time;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 显示处理详情
|
||||||
|
SELECT '=== 处理详情 ===' as details_title;
|
||||||
|
SELECT
|
||||||
|
table_name as '表名',
|
||||||
|
CASE action_type
|
||||||
|
WHEN 'CLEARED' THEN '已清空'
|
||||||
|
WHEN 'SKIPPED' THEN '已跳过'
|
||||||
|
WHEN 'ERROR' THEN '错误'
|
||||||
|
WHEN 'EXCLUDED' THEN '已排除'
|
||||||
|
END as '操作状态',
|
||||||
|
records_affected as '影响行数',
|
||||||
|
execution_time_ms as '耗时(ms)',
|
||||||
|
CASE
|
||||||
|
WHEN error_message IS NOT NULL THEN error_message
|
||||||
|
ELSE LEFT(sql_statement, 100)
|
||||||
|
END as '详情'
|
||||||
|
FROM reset_operation_log
|
||||||
|
ORDER BY action_type, table_name;
|
||||||
|
|
||||||
|
-- 性能统计
|
||||||
|
SELECT '=== 性能统计 ===' as performance_title;
|
||||||
|
SELECT
|
||||||
|
action_type as '操作类型',
|
||||||
|
COUNT(*) as '表数量',
|
||||||
|
SUM(records_affected) as '总影响行数',
|
||||||
|
AVG(execution_time_ms) as '平均耗时(ms)',
|
||||||
|
SUM(execution_time_ms) as '总耗时(ms)'
|
||||||
|
FROM reset_operation_log
|
||||||
|
GROUP BY action_type;
|
||||||
|
|
||||||
|
-- 清理
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS reset_operation_log;
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- 使用示例
|
||||||
|
-- 试运行(不实际执行)
|
||||||
|
CALL reset_tables_has_site_id_where(TRUE, TRUE, 'user,config');
|
||||||
|
|
||||||
|
-- 实际执行(保留site_id=0的数据,排除user和config表)
|
||||||
|
CALL reset_tables_has_site_id_where(TRUE, FALSE, '');
|
||||||
|
|
||||||
|
-- 完全清空所有表(不保留任何数据)
|
||||||
|
CALL reset_tables_has_site_id_where(FALSE, FALSE, '');
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 删除数据,保留表结构,当表中有store_id字段时,只删除store_id不为0的数据
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
DROP PROCEDURE IF EXISTS reset_tables_has_store_id_where;
|
||||||
|
CREATE PROCEDURE reset_tables_has_store_id_where(
|
||||||
|
IN p_preserve_site_zero BOOLEAN, -- 是否保留 store_id = 0 的数据
|
||||||
|
IN p_dry_run BOOLEAN, -- 是否试运行(不实际执行)
|
||||||
|
IN p_exclude_tables TEXT -- 排除的表列表,逗号分隔
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
DECLARE v_done INT DEFAULT FALSE;
|
||||||
|
DECLARE v_table_name VARCHAR(255);
|
||||||
|
DECLARE v_has_store_id INT DEFAULT 0;
|
||||||
|
DECLARE v_table_count INT DEFAULT 0;
|
||||||
|
DECLARE v_processed_count INT DEFAULT 0;
|
||||||
|
DECLARE v_skipped_count INT DEFAULT 0;
|
||||||
|
DECLARE v_error_count INT DEFAULT 0;
|
||||||
|
DECLARE v_no_store_id_tables TEXT DEFAULT '';
|
||||||
|
DECLARE v_excluded_tables TEXT DEFAULT '';
|
||||||
|
|
||||||
|
-- 游标声明
|
||||||
|
DECLARE table_cursor CURSOR FOR
|
||||||
|
SELECT TABLE_NAME
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_TYPE = 'BASE TABLE'
|
||||||
|
AND TABLE_NAME NOT IN (
|
||||||
|
'sys_operation_log', 'sys_login_log', 'system_parameters' -- 系统表默认排除
|
||||||
|
)
|
||||||
|
ORDER BY TABLE_NAME;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
|
||||||
|
|
||||||
|
-- 创建详细的日志表
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS reset_operation_log;
|
||||||
|
CREATE TEMPORARY TABLE reset_operation_log (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
table_name VARCHAR(255) NOT NULL,
|
||||||
|
action_type ENUM('CLEARED', 'SKIPPED', 'ERROR', 'EXCLUDED') NOT NULL,
|
||||||
|
records_affected INT DEFAULT 0,
|
||||||
|
sql_statement TEXT,
|
||||||
|
error_message TEXT,
|
||||||
|
execution_time_ms INT DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 开始事务(确保原子性)
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
OPEN table_cursor;
|
||||||
|
|
||||||
|
process_tables: LOOP
|
||||||
|
FETCH table_cursor INTO v_table_name;
|
||||||
|
IF v_done THEN
|
||||||
|
LEAVE process_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET v_table_count = v_table_count + 1;
|
||||||
|
|
||||||
|
-- 检查是否在排除列表中
|
||||||
|
IF FIND_IN_SET(v_table_name, p_exclude_tables) > 0 OR
|
||||||
|
FIND_IN_SET(v_table_name, v_excluded_tables) > 0 THEN
|
||||||
|
INSERT INTO reset_operation_log (table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'EXCLUDED', 0, '表在排除列表中,跳过处理');
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
ITERATE process_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 检查表是否有 store_id 字段
|
||||||
|
SELECT COUNT(*) INTO v_has_store_id
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = v_table_name
|
||||||
|
AND COLUMN_NAME = 'store_id';
|
||||||
|
|
||||||
|
SET @start_time = UNIX_TIMESTAMP(NOW(3)) * 1000;
|
||||||
|
|
||||||
|
IF v_has_store_id > 0 THEN
|
||||||
|
-- 构建动态SQL
|
||||||
|
IF p_preserve_site_zero THEN
|
||||||
|
SET @sql = CONCAT('DELETE FROM `', v_table_name, '` WHERE store_id != 0');
|
||||||
|
ELSE
|
||||||
|
SET @sql = CONCAT('TRUNCATE TABLE `', v_table_name, '`');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errmsg = MESSAGE_TEXT;
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement, error_message)
|
||||||
|
VALUES (v_table_name, 'ERROR', 0, @sql, CONCAT(@sqlstate, ' - ', @errmsg));
|
||||||
|
SET v_error_count = v_error_count + 1;
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF p_dry_run THEN
|
||||||
|
-- 试运行模式,只记录不执行
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'SKIPPED', 0, CONCAT('试运行: ', @sql));
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
ELSE
|
||||||
|
-- 实际执行
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @row_count = ROW_COUNT();
|
||||||
|
SET @end_time = UNIX_TIMESTAMP(NOW(3)) * 1000;
|
||||||
|
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement, execution_time_ms)
|
||||||
|
VALUES (v_table_name, 'CLEARED', @row_count, @sql, (@end_time - @start_time));
|
||||||
|
|
||||||
|
SET v_processed_count = v_processed_count + 1;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
ELSE
|
||||||
|
-- 表没有 store_id 字段
|
||||||
|
SET v_no_store_id_tables = CONCAT_WS(', ', v_no_store_id_tables, v_table_name);
|
||||||
|
|
||||||
|
INSERT INTO reset_operation_log
|
||||||
|
(table_name, action_type, records_affected, sql_statement)
|
||||||
|
VALUES (v_table_name, 'SKIPPED', 0, '表没有 store_id 字段,跳过处理');
|
||||||
|
|
||||||
|
SET v_skipped_count = v_skipped_count + 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET v_has_store_id = 0;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE table_cursor;
|
||||||
|
|
||||||
|
IF p_dry_run THEN
|
||||||
|
ROLLBACK; -- 试运行模式回滚
|
||||||
|
SELECT '=== 试运行模式 - 未实际执行任何操作 ===' as notice;
|
||||||
|
ELSE
|
||||||
|
COMMIT; -- 提交事务
|
||||||
|
SELECT '=== 数据库重置完成 ===' as summary;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 生成总结报告
|
||||||
|
SELECT
|
||||||
|
CONCAT('数据库: ', DATABASE()) as database_info,
|
||||||
|
CONCAT('开始时间: ', DATE_FORMAT(MIN(log_time), '%Y-%m-%d %H:%i:%s')) as start_time,
|
||||||
|
CONCAT('结束时间: ', DATE_FORMAT(MAX(log_time), '%Y-%m-%d %H:%i:%s')) as end_time,
|
||||||
|
CONCAT('总表数: ', v_table_count) as total_tables,
|
||||||
|
CONCAT('已处理表: ', v_processed_count) as processed_tables,
|
||||||
|
CONCAT('跳过表: ', v_skipped_count) as skipped_tables,
|
||||||
|
CONCAT('错误数: ', v_error_count) as error_count,
|
||||||
|
CONCAT('总耗时: ', SUM(execution_time_ms), 'ms') as total_duration
|
||||||
|
FROM reset_operation_log;
|
||||||
|
|
||||||
|
-- 显示没有 store_id 字段的表
|
||||||
|
IF v_no_store_id_tables != '' THEN
|
||||||
|
SELECT
|
||||||
|
'以下表没有 store_id 字段,已被跳过:' as warning_title,
|
||||||
|
v_no_store_id_tables as skipped_tables;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 显示错误详情
|
||||||
|
IF v_error_count > 0 THEN
|
||||||
|
SELECT '=== 错误详情 ===' as error_title;
|
||||||
|
SELECT table_name, error_message, sql_statement
|
||||||
|
FROM reset_operation_log
|
||||||
|
WHERE action_type = 'ERROR'
|
||||||
|
ORDER BY log_time;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 显示处理详情
|
||||||
|
SELECT '=== 处理详情 ===' as details_title;
|
||||||
|
SELECT
|
||||||
|
table_name as '表名',
|
||||||
|
CASE action_type
|
||||||
|
WHEN 'CLEARED' THEN '已清空'
|
||||||
|
WHEN 'SKIPPED' THEN '已跳过'
|
||||||
|
WHEN 'ERROR' THEN '错误'
|
||||||
|
WHEN 'EXCLUDED' THEN '已排除'
|
||||||
|
END as '操作状态',
|
||||||
|
records_affected as '影响行数',
|
||||||
|
execution_time_ms as '耗时(ms)',
|
||||||
|
CASE
|
||||||
|
WHEN error_message IS NOT NULL THEN error_message
|
||||||
|
ELSE LEFT(sql_statement, 100)
|
||||||
|
END as '详情'
|
||||||
|
FROM reset_operation_log
|
||||||
|
ORDER BY action_type, table_name;
|
||||||
|
|
||||||
|
-- 性能统计
|
||||||
|
SELECT '=== 性能统计 ===' as performance_title;
|
||||||
|
SELECT
|
||||||
|
action_type as '操作类型',
|
||||||
|
COUNT(*) as '表数量',
|
||||||
|
SUM(records_affected) as '总影响行数',
|
||||||
|
AVG(execution_time_ms) as '平均耗时(ms)',
|
||||||
|
SUM(execution_time_ms) as '总耗时(ms)'
|
||||||
|
FROM reset_operation_log
|
||||||
|
GROUP BY action_type;
|
||||||
|
|
||||||
|
-- 清理
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS reset_operation_log;
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- 实际执行(保留site_id=0的数据,排除user和config表)
|
||||||
|
CALL reset_tables_has_store_id_where(TRUE, FALSE, '');
|
||||||
|
```
|
||||||
27
docs/diy/RADEME.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# 自定义页面
|
||||||
|
|
||||||
|
|
||||||
|
## 对应的组件存放到数据表中
|
||||||
|
|
||||||
|
表: lucky_diy_view_util
|
||||||
|
|
||||||
|
```sql
|
||||||
|
create table if not exists lucky_diy_view_util
|
||||||
|
(
|
||||||
|
id int auto_increment
|
||||||
|
primary key,
|
||||||
|
name varchar(50) default '' not null comment '标识',
|
||||||
|
title varchar(50) default '' not null comment '组件名称',
|
||||||
|
type varchar(50) default 'SYSTEM' not null comment '组件类型',
|
||||||
|
value text null comment '配置:json格式',
|
||||||
|
addon_name varchar(50) default '' not null comment '插件标识',
|
||||||
|
sort int default 0 not null comment '排序号',
|
||||||
|
support_diy_view varchar(500) default '' not null comment '支持的自定义页面(为空表示公共组件都支持)',
|
||||||
|
max_count int default 0 not null comment '限制添加次数',
|
||||||
|
is_delete int default 0 not null comment '是否可以删除,0 允许,1 禁用',
|
||||||
|
icon varchar(255) default '' not null comment '组件图标',
|
||||||
|
icon_type int default 0 not null comment '0图片1图标',
|
||||||
|
constraint name
|
||||||
|
unique (name)
|
||||||
|
)
|
||||||
|
```
|
||||||
@@ -3,23 +3,22 @@ APP_TRACE = true
|
|||||||
|
|
||||||
[APP]
|
[APP]
|
||||||
DEFAULT_TIMEZONE = Asia/Shanghai
|
DEFAULT_TIMEZONE = Asia/Shanghai
|
||||||
ENV_MODE = development
|
|
||||||
|
|
||||||
[LANG]
|
[LANG]
|
||||||
default_lang = zh-cn
|
default_lang = zh-cn
|
||||||
|
|
||||||
[DATABASE]
|
[DATABASE]
|
||||||
TYPE = mysql
|
TYPE = mysql
|
||||||
HOSTNAME = 127.0.0.1
|
HOSTNAME = db
|
||||||
DATABASE = shop_mallnew_dev
|
DATABASE = shop_mallnew
|
||||||
USERNAME = root
|
USERNAME = shop_mallnew
|
||||||
PASSWORD = root
|
PASSWORD = shop_mallnew
|
||||||
HOSTPORT = 3306
|
HOSTPORT = 3306
|
||||||
CHARSET = utf8
|
CHARSET = utf8mb4
|
||||||
DEBUG = true
|
DEBUG = true
|
||||||
|
|
||||||
[redis]
|
[REDIS]
|
||||||
HOST = 127.0.0.1
|
HOST = redis
|
||||||
PORT = 6379
|
PORT = 6379
|
||||||
PASSWORD = ''
|
PASSWORD = 'luckyshop123!@#'
|
||||||
EXPIRY = 604800
|
EXPIRY = 604800
|
||||||
@@ -10,16 +10,16 @@ default_lang = zh-cn
|
|||||||
|
|
||||||
[DATABASE]
|
[DATABASE]
|
||||||
TYPE = mysql
|
TYPE = mysql
|
||||||
HOSTNAME = production_mysql_host
|
HOSTNAME = db
|
||||||
DATABASE = shop_mallnew_prod
|
DATABASE = shop_mallnew
|
||||||
USERNAME = prod_user
|
USERNAME = shop_mallnew
|
||||||
PASSWORD = prod_password
|
PASSWORD = shop_mallnew
|
||||||
HOSTPORT = 3306
|
HOSTPORT = 3306
|
||||||
CHARSET = utf8
|
CHARSET = utf8mb4
|
||||||
DEBUG = false
|
DEBUG = false
|
||||||
|
|
||||||
[redis]
|
[REDIS]
|
||||||
HOST = production_redis_host
|
HOST = redis
|
||||||
PORT = 6379
|
PORT = 6379
|
||||||
PASSWORD = production_redis_password
|
PASSWORD = 'luckyshop123!@#'
|
||||||
EXPIRY = 86400
|
EXPIRY = 604800
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
APP_DEBUG = true
|
APP_DEBUG = true
|
||||||
APP_TRACE = true
|
APP_TRACE = true
|
||||||
|
|
||||||
[APP]
|
[APP]
|
||||||
DEFAULT_TIMEZONE = Asia/Shanghai
|
DEFAULT_TIMEZONE = Asia/Shanghai
|
||||||
|
|
||||||
[LANG]
|
[LANG]
|
||||||
default_lang = zh-cn
|
default_lang = zh-cn
|
||||||
|
|
||||||
[DATABASE]
|
[DATABASE]
|
||||||
TYPE = mysql
|
TYPE = mysql
|
||||||
HOSTNAME = newshop_mysql
|
HOSTNAME = db
|
||||||
DATABASE = shop_dev
|
DATABASE = shop_mallnew
|
||||||
USERNAME = shop_mallnew
|
USERNAME = shop_mallnew
|
||||||
PASSWORD = shop_mallnew
|
PASSWORD = shop_mallnew
|
||||||
HOSTPORT = 3306
|
HOSTPORT = 3306
|
||||||
CHARSET = utf8
|
CHARSET = utf8mb4
|
||||||
DEBUG = true
|
DEBUG = true
|
||||||
[RRDATABASE]
|
|
||||||
HOSTNAME = 192.168.2.64
|
[REDIS]
|
||||||
[redis]
|
HOST = redis
|
||||||
HOST = newshop_redis
|
|
||||||
PORT = 6379
|
PORT = 6379
|
||||||
PASSWORD = 'luckyshop123!@#'
|
PASSWORD = 'luckyshop123!@#'
|
||||||
EXPIRY = 604800
|
EXPIRY = 604800
|
||||||
24
src/.env.test
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
APP_DEBUG = true
|
||||||
|
APP_TRACE = true
|
||||||
|
|
||||||
|
[APP]
|
||||||
|
DEFAULT_TIMEZONE = Asia/Shanghai
|
||||||
|
|
||||||
|
[LANG]
|
||||||
|
default_lang = zh-cn
|
||||||
|
|
||||||
|
[DATABASE]
|
||||||
|
TYPE = mysql
|
||||||
|
HOSTNAME = db
|
||||||
|
DATABASE = shop_mallnew
|
||||||
|
USERNAME = shop_mallnew
|
||||||
|
PASSWORD = shop_mallnew
|
||||||
|
HOSTPORT = 3306
|
||||||
|
CHARSET = utf8mb4
|
||||||
|
DEBUG = true
|
||||||
|
|
||||||
|
[REDIS]
|
||||||
|
HOST = redis
|
||||||
|
PORT = 6379
|
||||||
|
PASSWORD = 'luckyshop123!@#'
|
||||||
|
EXPIRY = 604800
|
||||||
@@ -1 +0,0 @@
|
|||||||
HUIqMBxOaiPqppGTd9WxmjJwFwX3x-hpbnI1xujpUW4.m7oE98dVL-9XQE2gAJ9VpnsbTfOJ2csnVDIzFqe9osw
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
39aLknx0mLrzjinZRvjc5pYAXUkRq0eo
|
|
||||||
201
src/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2020 上海牛之云网络科技有限公司
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
144
src/README.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|

|
||||||
|
|
||||||
|
### 产品介绍
|
||||||
|
|
||||||
|
### Niushop开源商城单商户V4
|
||||||
|
**快速搭建专属店铺,迅速展开线上业务** <br/>
|
||||||
|
NIUSHOP开源商城B2C单商户V4,功能强大,安全便捷,框架成熟稳定便于扩展,源码100%开源,支持二次开发定制,让企业用更低的成本、更少的人力,更快的速度构建自己的商城,开启网上商城销售业务。
|
||||||
|
|
||||||
|
### 公司介绍
|
||||||
|
|
||||||
|
上海牛之云网络科技有限公司成立于2016年,是一家从事移动互联网,电商软件为主导的技术研发型企业。公司总部位于上海,研发中心设立于锦绣龙城太原市,目前有团队成员50多人,产品研发实力雄厚。拥有NIUSHOP开源商城,NIUCLOUD开源小程序应用市场,牛客云商企业级SAAS电商服务平台等产品。业务遍及全国26个省市,在北京、广州、上海、深圳等地区拥有多家合作企业。我们始终保持专业、专注、专一的原则,旨在为用户提供最好用的全功能型电商软件产品,是您转型新零售,新媒体,掘金千亿电商市场的首选。
|
||||||
|
|
||||||
|
### 操作指南
|
||||||
|
|
||||||
|
[Niushop开源商城单商户V4使用手册](https://www.kancloud.cn/niucloud/niushop_b2c_v4/1842076)
|
||||||
|
| [api文档地址](https://www.kancloud.cn/niucloud/niushop_b2c_v4_api/1830441)
|
||||||
|
| [二开手册](https://www.kancloud.cn/niucloud/niushop_b2c_v4_develop/1830902)
|
||||||
|
| [论坛地址](https://bbs.niushop.com.cn/forum.php)
|
||||||
|
| [官网地址](https://www.niushop.com)
|
||||||
|
- - -
|
||||||
|
|
||||||
|
|
||||||
|
### 推荐阿里云服务器配置
|
||||||
|
|
||||||
|
阿里云2000元代金劵:<a href="https://www.aliyun.com/minisite/goods?userCode=hvxtm3ee">马上领取</a>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 商城特色:
|
||||||
|
强大的营销功能模块,丰富的行业模板和装修组件,快速搭建最适合自己的电商平台,轻松获客、裂变。开启电商运营之路。
|
||||||
|
|
||||||
|
1. <img src="https://images.gitee.com/uploads/images/2020/0724/121556_a96bd648_6569472.png"/> ThinkPhp6 + LayUi + ElementUi,学习维护成本低<br/>
|
||||||
|
2. <img src="https://images.gitee.com/uploads/images/2020/0724/121615_f801f981_6569472.png"/> 前端由UNI-APP框架编写,支持多端,易于维护<br/>
|
||||||
|
3. <img src="https://images.gitee.com/uploads/images/2020/0724/121635_e51987c4_6569472.png"/> 钩子 + 插件,组件化开发,可复用,开发便捷<br/>
|
||||||
|
4. <img src="https://images.gitee.com/uploads/images/2020/0724/121645_df103f55_6569472.png"/> 标准API接口,前后端分离,二次开发更方便<br/>
|
||||||
|
5. <img src="https://images.gitee.com/uploads/images/2020/0724/121708_74c55984_6569472.png"/> 代码全部开源,方便企业扩展自身业务需求
|
||||||
|
|
||||||
|
### Niushop官方群
|
||||||
|
Niushop商城qq开发群1:<a href="https://jq.qq.com/?_wv=1027&k=VrVzi1FI" target="_blank"></a>| qq开发群2:<a href="https://jq.qq.com/?_wv=1027&k=MCtjz6B9" target="_blank"> </a>| qq开发群3:<a href="https://jq.qq.com/?_wv=1027&k=H9FLIfTP" target="_blank"></a>
|
||||||
|
|
||||||
|
### 体验演示二维码
|
||||||
|

|
||||||
|
|
||||||
|
#### :fire: 体验演示站后台:[<a href='https://uniapp.v4.niuteam.cn/' target="_blank"> 查看 </a>]
|
||||||
|
<a href='https://uniapp.v4.niuteam.cn/' target="_blank">https://uniapp.v4.niuteam.cn/</a> 账号:test 密码:123456
|
||||||
|
|
||||||
|
### 开源版使用须知
|
||||||
|
|
||||||
|
1.仅允许用于个人学习研究使用;
|
||||||
|
|
||||||
|
2.开源版不建议商用,如果商用必须保留版权信息,望自觉遵守;
|
||||||
|
|
||||||
|
3.禁止将本开源的代码和资源进行任何形式任何名义的出售,否则产生的一切任何后果责任由侵权者自负。
|
||||||
|
|
||||||
|
4.推荐3名会员关注公众号,将免费获得单商户V4基础版授权。
|
||||||
|
|
||||||
|
5.绑定码云评论并点赞支持可获得单商户V4基础版授权
|
||||||
|
|
||||||
|
6.本基础版本后台源码全部开源,小程序为uniapp编译版,如需小程序源码,请点击下方图片马上获取。
|
||||||
|
|
||||||
|
<a href='https://www.niushop.com/web/index/promotion' target="_blank"><img src="https://images.gitee.com/uploads/images/2020/0805/103536_c7d1b001_6569472.png"/></a>
|
||||||
|
|
||||||
|
### 技术亮点
|
||||||
|
|
||||||
|
1.框架采用全新thinkphp6+事件开发设计+layui+uniapp进行设计,代码完全重构,采用支持百万级!
|
||||||
|
|
||||||
|
2.前端以layui + uniapp模块化开发;
|
||||||
|
|
||||||
|
3.数据导出采用phpExcel,使数据更加直观,更方便于管理统计;
|
||||||
|
|
||||||
|
4.插件钩子机制,功能模块独立,更有助于二次开发;
|
||||||
|
|
||||||
|
5.后台采用ECharts,直观体现关系数据可视化的图,支持图与图之间的混搭。实现完善的数据统计和分析;
|
||||||
|
|
||||||
|
6.EasyWeChat部署微信开发,微信接入更加快捷,简单;
|
||||||
|
|
||||||
|
7.内置强大灵活的权限管理体系,有利于专人专项运营;
|
||||||
|
|
||||||
|
8.内置组合数据统计,系统配置,管理碎片化数据统计;
|
||||||
|
|
||||||
|
9.客户端完善的交互效果和动画,提升用户端视觉体验;
|
||||||
|
|
||||||
|
10.可以完美对接公众号和小程序,并且数据同步,实现真正意义上的一端开发,多端使用;
|
||||||
|
|
||||||
|
11.内置客服系统,可以对接微信客服,客服在线实时聊天;
|
||||||
|
|
||||||
|
12.高频数据缓存,数据库读写分离,很大程度减轻服务器压力,提升访问速度;
|
||||||
|
|
||||||
|
13.后台设置菜单中可以一键数据备份和恢复,完全傻瓜式操作就可以轻松升级备份;
|
||||||
|
|
||||||
|
14.在线一键升级,轻松跨越到最新版本;
|
||||||
|
|
||||||
|
15.标准Api接口、前后端分离,二次开发更方便快捷;
|
||||||
|
|
||||||
|
16.支持数据库结构、数据、模板在线缓存清除,提升用户体验;
|
||||||
|
|
||||||
|
17.可视化DIY店铺装修,方便、快捷、直观,可以随心所欲装扮自己的店铺;
|
||||||
|
|
||||||
|
18.无缝事件机制行为扩展更方便,方便二次开发;
|
||||||
|
|
||||||
|
19.支持队列降低流量高峰,解除代码耦合性,高可用性;
|
||||||
|
|
||||||
|
20.在线一键安装部署,自动检测系统环境一键安装,省时省力快捷部署;
|
||||||
|
|
||||||
|
|
||||||
|
### 系统功能
|
||||||
|

|
||||||
|
|
||||||
|
### 页面展示
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### 合作伙伴
|
||||||
|
.png")
|
||||||
|
|
||||||
|
|
||||||
|
### 版权信息
|
||||||
|
|
||||||
|
版权所有Copyright © 2015-2020 NiuShop开源商城 版权所有
|
||||||
|
|
||||||
|
All rights reserved。
|
||||||
|
|
||||||
|
上海牛之云网络科技有限公司 提供技术支持
|
||||||
@@ -253,7 +253,7 @@ class Enterprise extends BaseModel
|
|||||||
*/
|
*/
|
||||||
public function deleteVideo($condition)
|
public function deleteVideo($condition)
|
||||||
{
|
{
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
||||||
$check_condition = array_column($condition, 2, 0);
|
$check_condition = array_column($condition, 2, 0);
|
||||||
$site_id = $check_condition['site_id'] ?? '';
|
$site_id = $check_condition['site_id'] ?? '';
|
||||||
if ($site_id === '') {
|
if ($site_id === '') {
|
||||||
|
|||||||
@@ -381,33 +381,40 @@ class FenxiaoOrder extends BaseModel
|
|||||||
*/
|
*/
|
||||||
public function getFenxiaoOrderPage($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'order_id DESC')
|
public function getFenxiaoOrderPage($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'order_id DESC')
|
||||||
{
|
{
|
||||||
$field = 'order_id,order_no,site_name,member_name,create_time,is_settlement,fenxiao_order_id';
|
// 解决GROUP BY问题:只查询主键ID,避免ONLY_FULL_GROUP_BY错误
|
||||||
$list = model('fenxiao_order')->pageList($condition, $field, $order, $page, $page_size, 'fo', [], 'order_id');
|
$field = 'DISTINCT fo.order_id';
|
||||||
|
$list = model('fenxiao_order')->pageList($condition, $field, $order, $page, $page_size, 'fo', [], 'fo.order_id');
|
||||||
if (!empty($list[ 'list' ])) {
|
if (!empty($list[ 'list' ])) {
|
||||||
$order_id_arr = [];
|
$order_id_arr = [];
|
||||||
foreach ($list['list'] as $k => $v)
|
foreach ($list['list'] as $k => $v)
|
||||||
{
|
{
|
||||||
$order_id_arr[] = $v['order_id'];
|
$order_id_arr[] = $v['order_id'];
|
||||||
}
|
}
|
||||||
|
if (!empty($order_id_arr)) {
|
||||||
$order_ids = implode(',', $order_id_arr);
|
$order_ids = implode(',', $order_id_arr);
|
||||||
$order_list = model('order')->getList([ [ 'order_id', 'in', $order_ids ] ], 'order_id,name,full_address,mobile,order_status_name');
|
|
||||||
$order_goods_list = model('fenxiao_order')->getList([ [ 'order_id', 'in', $order_ids ] ]);
|
// 重新查询完整的分销订单数据
|
||||||
foreach ($list[ 'list' ] as $k => $item) {
|
$fenxiao_orders = model('fenxiao_order')->getList([ [ 'fo.order_id', 'in', $order_ids ] ],
|
||||||
foreach ($order_list as $k_order => $v_order)
|
'fo.order_id, fo.order_no, fo.site_name, fo.member_name, fo.create_time, fo.is_settlement, fo.fenxiao_order_id',
|
||||||
{
|
'', 'fo');
|
||||||
if($item['order_id'] == $v_order['order_id'])
|
|
||||||
{
|
// 重新组织数据
|
||||||
$list[ 'list' ][ $k ] = array_merge($list[ 'list' ][ $k ], $v_order);
|
$new_list = [];
|
||||||
}
|
foreach ($fenxiao_orders as $fenxiao_order) {
|
||||||
}
|
$order_list = model('order')->getInfo([ [ 'order_id', '=', $fenxiao_order['order_id'] ] ],
|
||||||
$list[ 'list' ][ $k ][ 'order_goods' ] = [];
|
'name,full_address,mobile,order_status_name');
|
||||||
foreach ($order_goods_list as $k_order_goods => $v_order_goods)
|
$order_goods_list = model('fenxiao_order')->getList([ [ 'order_id', '=', $fenxiao_order['order_id'] ] ]);
|
||||||
{
|
|
||||||
if($item['order_id'] == $v_order_goods['order_id'])
|
// 合并数据
|
||||||
{
|
$new_item = array_merge($fenxiao_order, [
|
||||||
$list[ 'list' ][ $k ][ 'order_goods' ][] = $v_order_goods;
|
'address' => $order_list['full_address'] ?? '',
|
||||||
}
|
'mobile' => $order_list['mobile'] ?? '',
|
||||||
|
'order_status_name' => $order_list['order_status_name'] ?? '',
|
||||||
|
'order_goods' => $order_goods_list
|
||||||
|
]);
|
||||||
|
$new_list[] = $new_item;
|
||||||
}
|
}
|
||||||
|
$list['list'] = $new_list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->success($list);
|
return $this->success($list);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Poster extends BaseModel
|
|||||||
[
|
[
|
||||||
'action' => 'imageCopy', // 背景图
|
'action' => 'imageCopy', // 背景图
|
||||||
'data' => [
|
'data' => [
|
||||||
'upload/poster/bg/fenxiao_3.png',
|
'upload/poster/bg/fenxiao_2.png',
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
720,
|
720,
|
||||||
@@ -125,18 +125,18 @@ class Poster extends BaseModel
|
|||||||
1
|
1
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
// [
|
[
|
||||||
// 'action' => 'imageText', // 写入分享语
|
'action' => 'imageText', // 写入分享语
|
||||||
// 'data' => [
|
'data' => [
|
||||||
// $params[ 'template_json' ][ 'share_content' ],
|
$params[ 'template_json' ][ 'share_content' ],
|
||||||
// $params[ 'template_json' ][ 'share_content_font_size' ] * $fontRate * 2,
|
$params[ 'template_json' ][ 'share_content_font_size' ] * $fontRate * 2,
|
||||||
// is_array($params[ 'template_json' ][ 'share_content_color' ]) ? $params[ 'template_json' ][ 'share_content_color' ] : hex2rgb($params[ 'template_json' ][ 'share_content_color' ]),
|
is_array($params[ 'template_json' ][ 'share_content_color' ]) ? $params[ 'template_json' ][ 'share_content_color' ] : hex2rgb($params[ 'template_json' ][ 'share_content_color' ]),
|
||||||
// $params[ 'template_json' ][ 'share_content_left' ] * 2,
|
$params[ 'template_json' ][ 'share_content_left' ] * 2,
|
||||||
// ( $params[ 'template_json' ][ 'share_content_top' ] + $params[ 'template_json' ][ 'share_content_font_size' ] ) * 2,
|
( $params[ 'template_json' ][ 'share_content_top' ] + $params[ 'template_json' ][ 'share_content_font_size' ] ) * 2,
|
||||||
// $params[ 'template_json' ][ 'share_content_width' ] * 2,
|
$params[ 'template_json' ][ 'share_content_width' ] * 2,
|
||||||
// 1
|
1
|
||||||
// ]
|
]
|
||||||
// ],
|
],
|
||||||
[
|
[
|
||||||
'action' => 'imageCopy', // 写入用户头像
|
'action' => 'imageCopy', // 写入用户头像
|
||||||
'data' => [
|
'data' => [
|
||||||
@@ -179,7 +179,7 @@ class Poster extends BaseModel
|
|||||||
$pic_name = "_" . $pic_name;
|
$pic_name = "_" . $pic_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = $option_res->jpeg('upload/poster/distribution', 'distribution_0516' . $qrcode_param[ 'source_member' ] . $pic_name . '_' . $app_type);
|
$res = $option_res->jpeg('upload/poster/distribution', 'distribution_' . $qrcode_param[ 'source_member' ] . $pic_name . '_' . $app_type);
|
||||||
if ($res[ 'code' ] == 0) {
|
if ($res[ 'code' ] == 0) {
|
||||||
$upload = new Upload($site_id);
|
$upload = new Upload($site_id);
|
||||||
$cloud_res = $upload->fileCloud($res[ 'data' ][ 'path' ]);
|
$cloud_res = $upload->fileCloud($res[ 'data' ][ 'path' ]);
|
||||||
|
|||||||
@@ -49,14 +49,14 @@ class PosterTemplate extends BaseModel
|
|||||||
'nickname_top' => 515,
|
'nickname_top' => 515,
|
||||||
'nickname_left' => 20,
|
'nickname_left' => 20,
|
||||||
//分享语
|
//分享语
|
||||||
// 'share_content' => '邀您一起分享赚佣金',
|
'share_content' => '邀您一起分享赚佣金',
|
||||||
// 'share_content_is_show' => 1,
|
'share_content_is_show' => 1,
|
||||||
// 'share_content_font_size' => 14,
|
'share_content_font_size' => 14,
|
||||||
// 'share_content_color' => '#8D8D8D',
|
'share_content_color' => '#8D8D8D',
|
||||||
// 'share_content_width' => 130,
|
'share_content_width' => 130,
|
||||||
// 'share_content_height' => 30,
|
'share_content_height' => 30,
|
||||||
// 'share_content_top' => 550,
|
'share_content_top' => 550,
|
||||||
// 'share_content_left' => 20,
|
'share_content_left' => 20,
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class Form extends BaseApi
|
|||||||
['form_type', '=', 'custom' ]
|
['form_type', '=', 'custom' ]
|
||||||
];
|
];
|
||||||
$data = (new FormModel())->getFormInfo($condition, 'json_data,form_name');
|
$data = (new FormModel())->getFormInfo($condition, 'json_data,form_name');
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($data,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($data,true));
|
||||||
if (!empty($data['data'])) {
|
if (!empty($data['data'])) {
|
||||||
$data['data']['json_data'] = json_decode($data['data']['json_data'], true);
|
$data['data']['json_data'] = json_decode($data['data']['json_data'], true);
|
||||||
// $data['data']['title'] = model('form')->getValue(['id'=>$form_id]);
|
// $data['data']['title'] = model('form')->getValue(['id'=>$form_id]);
|
||||||
|
|||||||
@@ -7,16 +7,12 @@
|
|||||||
.layui-layout-admin.admin-style-2 .table-tab .layui-tab-title{margin-bottom: 15px;}
|
.layui-layout-admin.admin-style-2 .table-tab .layui-tab-title{margin-bottom: 15px;}
|
||||||
.form-img .form-img-wrap {width: 25px;height: 25px;margin: 0 10px 10px 0;border: 1px solid #EAEAEA;display: flex;align-items: center;justify-items: center}
|
.form-img .form-img-wrap {width: 25px;height: 25px;margin: 0 10px 10px 0;border: 1px solid #EAEAEA;display: flex;align-items: center;justify-items: center}
|
||||||
.form-img-wrap img {max-width: 100%;max-height: 100%;height: auto;width: 100%}
|
.form-img-wrap img {max-width: 100%;max-height: 100%;height: auto;width: 100%}
|
||||||
.layui-layer-content .layui-form-label {width: 250px}
|
.layui-layer-content .layui-form-label {width: 100px}
|
||||||
.layui-layer-content .layui-form-label + .layui-input-block {margin-left: 100px}
|
.layui-layer-content .layui-form-label + .layui-input-block {margin-left: 100px}
|
||||||
.layui-table .form-data-wrap {max-height: 50px;overflow: hidden}
|
.layui-table .form-data-wrap {max-height: 50px;overflow: hidden}
|
||||||
.layui-table .layui-form-item {margin-bottom: 0}
|
.layui-table .layui-form-item {margin-bottom: 0}
|
||||||
.layui-table .layui-form-label {width: auto;height: 25px;line-height: 25px;}
|
.layui-table .layui-form-label {width: auto;height: 25px;line-height: 25px;}
|
||||||
.layui-table .layui-form-label + .layui-input-block {margin-left: 0; height: 25px;line-height: 25px;min-height: unset;}
|
.layui-table .layui-form-label + .layui-input-block {margin-left: 0; height: 25px;line-height: 25px;min-height: unset;}
|
||||||
.layui-layer-content .form-data-wrap{
|
|
||||||
height: 700px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
@@ -211,7 +207,7 @@ layui.use(['form', 'laydate', 'laytpl'], function() {
|
|||||||
laytpl($('#formData').html()).render(data, function(string){
|
laytpl($('#formData').html()).render(data, function(string){
|
||||||
layer.open({
|
layer.open({
|
||||||
title: '查看信息',
|
title: '查看信息',
|
||||||
area: ["600px","800px"],
|
area: "400px",
|
||||||
type: 1,
|
type: 1,
|
||||||
content: string,
|
content: string,
|
||||||
btn: ['确认']
|
btn: ['确认']
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
<!-- <script src="MEMBERRECHARGE_JS/order_list.js?v={$version}"></script> -->
|
<script src="MEMBERRECHARGE_JS/order_list.js?v={$version}"></script>
|
||||||
<script>
|
<script>
|
||||||
var form,laypage,element,laydate;
|
var form,laypage,element,laydate;
|
||||||
var is_refresh = false;
|
var is_refresh = false;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ return [
|
|||||||
'name' => 'MINGPIAN_INFO',
|
'name' => 'MINGPIAN_INFO',
|
||||||
'title' => '电子名片',
|
'title' => '电子名片',
|
||||||
'parent' => 'BASICS_LINK',
|
'parent' => 'BASICS_LINK',
|
||||||
'wap_url' => '',
|
'wap_url' => '/pages/contact/contact',
|
||||||
'web_url' => '',
|
'web_url' => '',
|
||||||
'sort' => 0
|
'sort' => 0
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class Enterprise extends BaseModel
|
|||||||
*/
|
*/
|
||||||
public function deleteVideo($condition)
|
public function deleteVideo($condition)
|
||||||
{
|
{
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
||||||
$check_condition = array_column($condition, 2, 0);
|
$check_condition = array_column($condition, 2, 0);
|
||||||
$site_id = $check_condition['site_id'] ?? '';
|
$site_id = $check_condition['site_id'] ?? '';
|
||||||
if ($site_id === '') {
|
if ($site_id === '') {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Personnel extends BaseShop
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
$config['value'] = json_decode($config['value'],true);
|
$config['value'] = json_decode($config['value'],true);
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($config,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($config,true));
|
||||||
$this->assign('config', $config);
|
$this->assign('config', $config);
|
||||||
return $this->fetch('personnel/diy');
|
return $this->fetch('personnel/diy');
|
||||||
}
|
}
|
||||||
|
|||||||
146
src/addon/personnel/shop/view/enterprise/add.html
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.upload-img-block .upload-img-box .upload-default{position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="layui-form form-wrap">
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label short-label"><span class="required">*</span>文件名称:</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="files_title" lay-verify="required" maxlength="40" autocomplete="off" placeholder="请输入标题" class="layui-input len-long">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"><span class="required">*</span>文件:</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<p class="file-upload">未上传</p>
|
||||||
|
<button type="button" class="layui-btn" id="cert_upload">
|
||||||
|
<i class="layui-icon"></i>上传文件
|
||||||
|
</button>
|
||||||
|
<input type="hidden" name="files_url" class="layui-input len-long" value="{$info.files_url ?? ''}" lay-verify="files_url">
|
||||||
|
<input type="hidden" name="size" class="layui-input len-long" value="{$info.size ?? ''}">
|
||||||
|
</div>
|
||||||
|
<div class="word-aux">请选择pdf文件</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row" id="save">
|
||||||
|
<button class="layui-btn" lay-submit lay-filter="save">提交</button>
|
||||||
|
<button class="layui-btn layui-btn-primary" onclick="back()">返回</button>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="form-row" id="save1" style="display: none;">
|
||||||
|
<div style="color:red">(文件越大解码时间越长)上传解码中,请稍等...</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var form,repeat_flag,
|
||||||
|
IMAGE_MAX = 9, //最多可以上传多少张图片
|
||||||
|
imageCollection = [], //图片集合
|
||||||
|
selectedGoodsId = [],
|
||||||
|
goods_id = [],
|
||||||
|
goods_list =[];
|
||||||
|
|
||||||
|
layui.use(['form'], function() {
|
||||||
|
form = layui.form;
|
||||||
|
repeat_flag = false;
|
||||||
|
|
||||||
|
form.render();
|
||||||
|
|
||||||
|
// 单图上传
|
||||||
|
$("body").off("click", "#img").on("click", "#img", function () {
|
||||||
|
openAlbum(function (data) {
|
||||||
|
imageCollection = [];
|
||||||
|
imageCollection.push(data[0].pic_path);
|
||||||
|
imageCollection.splice(1, imageCollection.length);
|
||||||
|
var val = '<img src="' + ns.img(imageCollection[0]) + '" alt="">';
|
||||||
|
$("#img").html(val);
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单提交(立即发布)
|
||||||
|
*/
|
||||||
|
form.on('submit(save)', function(data){
|
||||||
|
field = data.field;
|
||||||
|
field.status = 1;
|
||||||
|
formSubmit(field)
|
||||||
|
});
|
||||||
|
|
||||||
|
new Upload({
|
||||||
|
elem: '#cert_upload',
|
||||||
|
url: ns.url("personnel://shop/enterprise/uploadfile"),
|
||||||
|
accept: 'file',
|
||||||
|
callback:function (res) {
|
||||||
|
if (res.code >= 0) {
|
||||||
|
layer.msg('上传成功');
|
||||||
|
$("input[name='files_url']").val(res.data.path);
|
||||||
|
$("input[name='size']").val(res.data.size);
|
||||||
|
$("input[name='files_url']").siblings(".file-upload").text("已上传");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交
|
||||||
|
*/
|
||||||
|
function formSubmit(data){
|
||||||
|
// if (!imageCollection.length){
|
||||||
|
// layer.msg('请选择封面图!', {icon: 5, anim: 6});
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// $('#save').hide()
|
||||||
|
// $('#save1').show()
|
||||||
|
if(repeat_flag) return;
|
||||||
|
repeat_flag = true;
|
||||||
|
setTimeout(function (a) {
|
||||||
|
console.log(1236)
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
url: ns.url("personnel://shop/enterprise/add"),
|
||||||
|
data: data,
|
||||||
|
async: false,
|
||||||
|
success: function(res){
|
||||||
|
repeat_flag = false;
|
||||||
|
if (res.code == 0) {
|
||||||
|
layer.confirm('添加成功', {
|
||||||
|
title:'操作提示',
|
||||||
|
btn: ['返回列表', '继续添加'],
|
||||||
|
closeBtn: 0,
|
||||||
|
yes: function(index, layero){
|
||||||
|
if(data.status == 1){
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/lists");
|
||||||
|
}else{
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/drafts");
|
||||||
|
}
|
||||||
|
layer.close(index);
|
||||||
|
},
|
||||||
|
btn2: function(index, layero) {
|
||||||
|
listenerHash(); // 刷新页面
|
||||||
|
layer.close(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
layer.msg(res.message);
|
||||||
|
}
|
||||||
|
$('#save').show()
|
||||||
|
$('#save1').hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function back() {
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/lists");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
137
src/addon/personnel/shop/view/enterprise/edit.html
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.upload-img-block .upload-img-box .upload-default{position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="layui-form form-wrap">
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label short-label"><span class="required">*</span>文件标题:</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="files_title" value="{$info.files_title}" lay-verify="required" maxlength="40" autocomplete="off" placeholder="请输入标题" class="layui-input len-long">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"><span class="required">*</span>文件:</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
{notempty name="$info.files_url"}
|
||||||
|
<p class="file-upload">已上传</p>
|
||||||
|
{else/}
|
||||||
|
<p class="file-upload">未上传</p>
|
||||||
|
{/notempty}
|
||||||
|
<button type="button" class="layui-btn" id="cert_upload">
|
||||||
|
<i class="layui-icon"></i>上传文件
|
||||||
|
</button>
|
||||||
|
<input type="hidden" name="files_url" class="layui-input len-long" value="{$info.files_url ?? ''}" lay-verify="files_url">
|
||||||
|
<input type="hidden" name="size" class="layui-input len-long" value="{$info.size ?? ''}">
|
||||||
|
</div>
|
||||||
|
<div class="word-aux">请选择pdf文件</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<input type="hidden" name="files_id" value="{$info.files_id}" />
|
||||||
|
|
||||||
|
<div class="form-row" id="save">
|
||||||
|
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
|
||||||
|
<button class="layui-btn layui-btn-primary" onclick="back()">返回</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="form-row" id="save1" style="display: none;">
|
||||||
|
<div style="color:red">(文件越大解码时间越长)上传解码中,请稍等...</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var form,upload, repeat_flag = false;
|
||||||
|
|
||||||
|
layui.use(['form'], function() {
|
||||||
|
form = layui.form;
|
||||||
|
form.render();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单提交(立即发布)
|
||||||
|
*/
|
||||||
|
form.on('submit(save)', function(data){
|
||||||
|
field = data.field;
|
||||||
|
field.status = 1;
|
||||||
|
formSubmit(field)
|
||||||
|
});
|
||||||
|
|
||||||
|
new Upload({
|
||||||
|
elem: '#cert_upload',
|
||||||
|
url: ns.url("/personnel://shop/enterprise/uploadfile"),
|
||||||
|
accept: 'file',
|
||||||
|
callback:function (res) {
|
||||||
|
if (res.code >= 0) {
|
||||||
|
layer.msg('上传成功');
|
||||||
|
$("input[name='files_url']").val(res.data.path);
|
||||||
|
$("input[name='size']").val(res.data.size);
|
||||||
|
$("input[name='files_url']").siblings(".file-upload").text("已上传");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交
|
||||||
|
*/
|
||||||
|
function formSubmit(field)
|
||||||
|
{
|
||||||
|
// if (!imageCollection.length){
|
||||||
|
// layer.msg('请选择封面图!', {icon: 5, anim: 6});
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $('#save').hide()
|
||||||
|
// $('#save1').show()
|
||||||
|
|
||||||
|
if(repeat_flag) return;
|
||||||
|
repeat_flag = true;
|
||||||
|
setTimeout(function (a) {
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
url: ns.url("personnel://shop/enterprise/edit"),
|
||||||
|
data: field,
|
||||||
|
async: false,
|
||||||
|
success: function(res){
|
||||||
|
repeat_flag = false;
|
||||||
|
|
||||||
|
if (res.code == 0) {
|
||||||
|
layer.confirm('编辑成功', {
|
||||||
|
title:'操作提示',
|
||||||
|
btn: ['返回列表', '继续编辑'],
|
||||||
|
yes: function(index, layero){
|
||||||
|
if(field.status == 1){
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/lists");
|
||||||
|
}else{
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/drafts");
|
||||||
|
}
|
||||||
|
layer.close(index);
|
||||||
|
},
|
||||||
|
btn2: function(index, layero) {
|
||||||
|
layer.close(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
layer.msg(res.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function back() {
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/lists");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
BIN
src/addon/personnel/shop/view/enterprise/fileicon.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/addon/personnel/shop/view/enterprise/icon.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
155
src/addon/personnel/shop/view/enterprise/lists.html
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="single-filter-box top">
|
||||||
|
<button class="layui-btn" onclick="add()">添加文件</button>
|
||||||
|
|
||||||
|
<div class="layui-form">
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="search_text" placeholder="请输入标题" autocomplete="off" class="layui-input">
|
||||||
|
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
|
||||||
|
<i class="layui-icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input id="url" value="" type="hidden"></input>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<table id="files_list" lay-filter="files_list"></table>
|
||||||
|
|
||||||
|
<!-- 操作 -->
|
||||||
|
<script type="text/html" id="operation">
|
||||||
|
<div class="table-btn">
|
||||||
|
<!-- <a class="layui-btn" lay-event="copy">复制链接</a> -->
|
||||||
|
<a class="layui-btn" lay-event="edit">编辑</a>
|
||||||
|
<a class="layui-btn" lay-event="delete">删除</a>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<!-- 用户信息 -->
|
||||||
|
<script type="text/html" id="info">
|
||||||
|
<div class='table-title'>
|
||||||
|
<div class='title-pic headimg'>
|
||||||
|
<img layer-src src="{{ns.img('addon/personnel/shop/view/enterprise/fileicon.png')}}" onerror="this.src = '{:img('addon/personnel/shop/view/enterprise/fileicon.png')}' ">
|
||||||
|
</div>
|
||||||
|
<div class='title-content'>
|
||||||
|
<p class="layui-elip" style="font-weight: 600;color:#000">{{d.files_title}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var form,laytpl,table, repeat_flag = false;//防重复标识;
|
||||||
|
layui.use(['form','laytpl'], function() {
|
||||||
|
form = layui.form;
|
||||||
|
laytpl = layui.laytpl;
|
||||||
|
form.render();
|
||||||
|
|
||||||
|
table = new Table({
|
||||||
|
elem: '#files_list',
|
||||||
|
url: ns.url("personnel://shop/enterprise/lists"),
|
||||||
|
cols: [
|
||||||
|
[ {
|
||||||
|
field: 'files_title',
|
||||||
|
title: '文件名称',
|
||||||
|
width: '30%',
|
||||||
|
unresize: 'false',
|
||||||
|
templet: '#info'
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// field: 'category_name',
|
||||||
|
// title: '文件分类',
|
||||||
|
// width: '20%',
|
||||||
|
// unresize: 'false'
|
||||||
|
// },
|
||||||
|
/*{
|
||||||
|
field: 'create_time',
|
||||||
|
title: '创建时间',
|
||||||
|
width: '20%',
|
||||||
|
unresize: 'false',
|
||||||
|
templet: function (data) {
|
||||||
|
return ns.time_to_date(data.createtime);
|
||||||
|
}
|
||||||
|
}, */{
|
||||||
|
title: '操作',
|
||||||
|
toolbar: '#operation',
|
||||||
|
unresize: 'false',
|
||||||
|
align : 'right'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
form.on('submit(search)', function(data) {
|
||||||
|
table.reload({
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
},
|
||||||
|
where: data.field
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
table.on("sort",function (obj) {
|
||||||
|
table.reload({
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
order:obj.field,
|
||||||
|
sort:obj.type
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听工具栏操作
|
||||||
|
*/
|
||||||
|
table.tool(function(obj) {
|
||||||
|
var data = obj.data;
|
||||||
|
switch (obj.event) {
|
||||||
|
case 'copy': // 推广
|
||||||
|
// promote(data);
|
||||||
|
$('#url').val(data.url)
|
||||||
|
console.log(data.files_url)
|
||||||
|
ns.copy('url')
|
||||||
|
break;
|
||||||
|
case 'edit': //编辑
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/edit?files_id=" + data.files_id);
|
||||||
|
break;
|
||||||
|
case 'delete': //删除
|
||||||
|
deletefiles(data.files_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
function deletefiles(files_id) {
|
||||||
|
if (repeat_flag) return false;
|
||||||
|
repeat_flag = true;
|
||||||
|
|
||||||
|
layer.confirm('确定要删除该文件吗?', function (index) {
|
||||||
|
layer.close(index);
|
||||||
|
$.ajax({
|
||||||
|
url: ns.url("personnel://shop/enterprise/delete"),
|
||||||
|
data: {files_id},
|
||||||
|
dataType: 'JSON',
|
||||||
|
type: 'POST',
|
||||||
|
success: function (res) {
|
||||||
|
layer.msg(res.message);
|
||||||
|
repeat_flag = false;
|
||||||
|
if (res.code == 0) {
|
||||||
|
table.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
repeat_flag = false;
|
||||||
|
layer.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function add() {
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/add");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
BIN
src/addon/personnel/shop/view/enterprise/play.png
Normal file
|
After Width: | Height: | Size: 818 B |
168
src/addon/personnel/shop/view/files/lists.html
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="single-filter-box top">
|
||||||
|
<button class="layui-btn" onclick="add()">添加文件</button>
|
||||||
|
|
||||||
|
<div class="layui-form">
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="search_text" placeholder="请输入标题" autocomplete="off" class="layui-input">
|
||||||
|
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
|
||||||
|
<i class="layui-icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input id="url" value="" type="hidden"></input>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<table id="files_list" lay-filter="files_list"></table>
|
||||||
|
|
||||||
|
<!-- 操作 -->
|
||||||
|
<script type="text/html" id="operation">
|
||||||
|
<div class="table-btn">
|
||||||
|
<!-- <a class="layui-btn" lay-event="copy">复制链接</a> -->
|
||||||
|
<a class="layui-btn" lay-event="edit">编辑</a>
|
||||||
|
<a class="layui-btn" lay-event="delete">删除</a>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<!-- 用户信息 -->
|
||||||
|
<script type="text/html" id="info">
|
||||||
|
<div class='table-title'>
|
||||||
|
<div class='title-pic headimg'>
|
||||||
|
<img layer-src src="{{ns.img('/addon/personnel/view/enterprise/fileicon.png')}}" onerror="this.src = '{:img('app/shop/view/files/fileicon.png')}' ">
|
||||||
|
</div>
|
||||||
|
<div class='title-content'>
|
||||||
|
<p class="layui-elip" style="font-weight: 600;color:#000">{{d.files_title}}</p>
|
||||||
|
<!-- <p class="layui-elip" style="line-height: 1.2;color:#888;font-size: 12px;">发布时间:{{ns.time_to_date(d.createtime)}}</p> -->
|
||||||
|
<!-- <p class="layui-elip" style="color:#888;font-size: 12px;">样本大小:{{d.size}}</p> -->
|
||||||
|
<!-- <div>
|
||||||
|
<span title="{{ d.mobile }}">{{ d.mobile }}</span>
|
||||||
|
{{# if (d.status == 0 || d.member_level_type == 1){ }}
|
||||||
|
{{# if (d.status == 0){ }}
|
||||||
|
<span class="blacklist">黑名单</span>
|
||||||
|
{{# } }}
|
||||||
|
{{# if (d.member_level_type == 1){ }}
|
||||||
|
<span class="vip_style">SVIP</span>
|
||||||
|
{{# } }}
|
||||||
|
{{# } }}
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var form,laytpl,table, repeat_flag = false;//防重复标识;
|
||||||
|
layui.use(['form','laytpl'], function() {
|
||||||
|
form = layui.form;
|
||||||
|
laytpl = layui.laytpl;
|
||||||
|
form.render();
|
||||||
|
|
||||||
|
table = new Table({
|
||||||
|
elem: '#files_list',
|
||||||
|
url: ns.url("personnel://shop/enterprise/lists"),
|
||||||
|
cols: [
|
||||||
|
[ {
|
||||||
|
field: 'files_title',
|
||||||
|
title: '文件名称',
|
||||||
|
width: '30%',
|
||||||
|
unresize: 'false',
|
||||||
|
templet: '#info'
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// field: 'category_name',
|
||||||
|
// title: '文件分类',
|
||||||
|
// width: '20%',
|
||||||
|
// unresize: 'false'
|
||||||
|
// },
|
||||||
|
/*{
|
||||||
|
field: 'create_time',
|
||||||
|
title: '创建时间',
|
||||||
|
width: '20%',
|
||||||
|
unresize: 'false',
|
||||||
|
templet: function (data) {
|
||||||
|
return ns.time_to_date(data.createtime);
|
||||||
|
}
|
||||||
|
}, */{
|
||||||
|
title: '操作',
|
||||||
|
toolbar: '#operation',
|
||||||
|
unresize: 'false',
|
||||||
|
align : 'right'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
form.on('submit(search)', function(data) {
|
||||||
|
table.reload({
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
},
|
||||||
|
where: data.field
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
table.on("sort",function (obj) {
|
||||||
|
table.reload({
|
||||||
|
page: {
|
||||||
|
curr: 1
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
order:obj.field,
|
||||||
|
sort:obj.type
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听工具栏操作
|
||||||
|
*/
|
||||||
|
table.tool(function(obj) {
|
||||||
|
var data = obj.data;
|
||||||
|
switch (obj.event) {
|
||||||
|
case 'copy': // 推广
|
||||||
|
// promote(data);
|
||||||
|
$('#url').val(data.url)
|
||||||
|
console.log(data.files_url)
|
||||||
|
ns.copy('url')
|
||||||
|
break;
|
||||||
|
case 'edit': //编辑
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/edit?files_id=" + data.files_id);
|
||||||
|
break;
|
||||||
|
case 'delete': //删除
|
||||||
|
deletefiles(data.files_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
function deletefiles(files_id) {
|
||||||
|
if (repeat_flag) return false;
|
||||||
|
repeat_flag = true;
|
||||||
|
|
||||||
|
layer.confirm('确定要删除该文件吗?', function (index) {
|
||||||
|
layer.close(index);
|
||||||
|
$.ajax({
|
||||||
|
url: ns.url("personnel://shop/enterprise/delete"),
|
||||||
|
data: {files_id},
|
||||||
|
dataType: 'JSON',
|
||||||
|
type: 'POST',
|
||||||
|
success: function (res) {
|
||||||
|
layer.msg(res.message);
|
||||||
|
repeat_flag = false;
|
||||||
|
if (res.code == 0) {
|
||||||
|
table.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
repeat_flag = false;
|
||||||
|
layer.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function add() {
|
||||||
|
location.hash = ns.hash("personnel://shop/enterprise/add");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
0
src/addon/personnel/shop/view/public/diy.css
Normal file
BIN
src/addon/personnel/shop/view/public/img/file.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/addon/personnel/shop/view/public/img/kefu.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/addon/personnel/shop/view/public/img/map.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
src/addon/personnel/shop/view/public/img/mingpian.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/addon/personnel/shop/view/public/img/video.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
@@ -86,7 +86,7 @@ class Pointexchange extends BaseShop
|
|||||||
$list = $exchange_order_model->getExchangePageList($condition, $page, $page_size, $order, $field, 'eo', [
|
$list = $exchange_order_model->getExchangePageList($condition, $page, $page_size, $order, $field, 'eo', [
|
||||||
[ 'member m', 'm.member_id=eo.member_id', 'left' ]
|
[ 'member m', 'm.member_id=eo.member_id', 'left' ]
|
||||||
]);
|
]);
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
||||||
return $list;
|
return $list;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -468,12 +468,12 @@ class Weapp extends BaseModel
|
|||||||
$server = $this->app->server;
|
$server = $this->app->server;
|
||||||
$message = $server->getMessage();
|
$message = $server->getMessage();
|
||||||
Log::write('微信小程序消息推送:' . json_encode($message));
|
Log::write('微信小程序消息推送:' . json_encode($message));
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($message,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($message,true));
|
||||||
if (isset($message[ 'MsgType' ])) {
|
if (isset($message[ 'MsgType' ])) {
|
||||||
switch ( $message[ 'MsgType' ] ) {
|
switch ( $message[ 'MsgType' ] ) {
|
||||||
case 'event':
|
case 'event':
|
||||||
$this->app->server->push(function($res) {
|
$this->app->server->push(function($res) {
|
||||||
file_put_contents(__DIR__ . '/debug1.txt', var_export($res,true));
|
// file_put_contents(__DIR__ . '/debug1.txt', var_export($res,true));
|
||||||
// 商品审核结果通知
|
// 商品审核结果通知
|
||||||
if ($res[ 'Event' ] == 'open_product_spu_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
|
if ($res[ 'Event' ] == 'open_product_spu_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
|
||||||
model('shopcompoent_goods')->update([
|
model('shopcompoent_goods')->update([
|
||||||
|
|||||||
@@ -28,13 +28,11 @@ class Config extends BaseApi
|
|||||||
$document_info = $config_model->getRegisterDocument($site_id, 'shop');
|
$document_info = $config_model->getRegisterDocument($site_id, 'shop');
|
||||||
//隐私协议
|
//隐私协议
|
||||||
$rivacy_info = $config_model->getRrivacyDocument($site_id, 'shop');
|
$rivacy_info = $config_model->getRrivacyDocument($site_id, 'shop');
|
||||||
|
|
||||||
if($type == 1){//注册
|
if($type == 1){//注册
|
||||||
$config = $document_info;
|
$config = $document_info;
|
||||||
}else{//隐私
|
}else{//隐私
|
||||||
$config = $rivacy_info;
|
$config = $rivacy_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->response($config);
|
return $this->response($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,6 +127,13 @@ class Goods extends BaseApi
|
|||||||
|
|
||||||
$poster = new Poster();
|
$poster = new Poster();
|
||||||
$res = $poster->shareImg($this->params[ 'page' ] ?? '', $qrcode_param, $this->site_id, $this->store_id);
|
$res = $poster->shareImg($this->params[ 'page' ] ?? '', $qrcode_param, $this->site_id, $this->store_id);
|
||||||
|
//临时解决分享
|
||||||
|
$goods = model('goods')->getInfo(['goods_id'=>$qrcode_param['goods_id']]);
|
||||||
|
$img = explode(',',$goods['goods_image']);
|
||||||
|
$res['code'] = 0;
|
||||||
|
$res['data'] = [
|
||||||
|
'path'=>$img[0]
|
||||||
|
];
|
||||||
return $this->response($res);
|
return $this->response($res);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -333,7 +333,20 @@ class Goodssku extends BaseApi
|
|||||||
$join = [
|
$join = [
|
||||||
[ 'goods g', 'gs.sku_id = g.sku_id', 'inner' ]
|
[ 'goods g', 'gs.sku_id = g.sku_id', 'inner' ]
|
||||||
];
|
];
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
|
||||||
|
// 如果是连锁运营模式
|
||||||
|
if ($this->store_data[ 'config' ][ 'store_business' ] == 'store') {
|
||||||
|
$join[] = [ 'store_goods_sku sgs', 'sgs.status = 1 and g.sku_id = sgs.sku_id and sgs.store_id=' . $this->store_id, 'right' ];
|
||||||
|
|
||||||
|
$condition[] = [ 'g.sale_store', 'like', [ '%all%', '%,' . $this->store_id . ',%' ], 'or' ];
|
||||||
|
|
||||||
|
$field = str_replace('gs.price', 'IFNULL(IF(g.is_unify_price = 1,gs.price,sgs.price), gs.price) as price', $field);
|
||||||
|
$field = str_replace('gs.discount_price', 'IFNULL(IF(g.is_unify_price = 1,gs.price,sgs.price), gs.price) as discount_price', $field);
|
||||||
|
if ($this->store_data[ 'store_info' ][ 'stock_type' ] == 'store') {
|
||||||
|
$field = str_replace('gs.stock', 'IFNULL(sgs.stock, 0) as stock', $field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$goods = new Goods();
|
$goods = new Goods();
|
||||||
$list = $goods->getGoodsSkuPageList($condition, $page, $page_size, $order_by, $field, $alias, $join);
|
$list = $goods->getGoodsSkuPageList($condition, $page, $page_size, $order_by, $field, $alias, $join);
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,36 @@ use addon\wxoplatform\model\Config as WxOplatformConfigModel;
|
|||||||
use app\model\web\Config as WebConfig;
|
use app\model\web\Config as WebConfig;
|
||||||
use think\facade\Log;
|
use think\facade\Log;
|
||||||
|
|
||||||
|
use app\model\system\Seal as SealModel;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class Lucky extends BaseApi
|
class Lucky extends BaseApi
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function newtest(){
|
||||||
|
|
||||||
|
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$params = [
|
||||||
|
"filename" => "20250625030540175079194017513.xlsx",
|
||||||
|
"path" => "upload/2035/common/seal/sealmedium_import/20250625/20250625030540175079194017513.xlsx",
|
||||||
|
"index" => "1",
|
||||||
|
"success_num" => "0",
|
||||||
|
"error_num" => "0",
|
||||||
|
"record" => "0"
|
||||||
|
];
|
||||||
|
$res = $sealModel->importMedium($params, 2035);
|
||||||
|
|
||||||
|
}
|
||||||
|
//生成pdf
|
||||||
|
public function pdf(){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 生成 NFC 跳转 URL Scheme
|
// 生成 NFC 跳转 URL Scheme
|
||||||
function generateNFCScheme($accessToken) {
|
function generateNFCScheme($accessToken) {
|
||||||
$url = "https://api.weixin.qq.com/wxa/generatenfcscheme?access_token={$accessToken}";
|
$url = "https://api.weixin.qq.com/wxa/generatenfcscheme?access_token={$accessToken}";
|
||||||
|
|||||||
@@ -601,4 +601,12 @@ class Member extends BaseApi
|
|||||||
model('personnel_message')->add($insert);
|
model('personnel_message')->add($insert);
|
||||||
return $this->response(['code'=>0,'message'=>'留言成功~']);
|
return $this->response(['code'=>0,'message'=>'留言成功~']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getbusiness(){
|
||||||
|
|
||||||
|
$token = $this->checkToken();
|
||||||
|
if ($token[ 'code' ] < 0) return $this->response($token);
|
||||||
|
$list = model('business')->getList([]);
|
||||||
|
return $this->response(['code'=>0,'data'=>$list]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@ class Rrapi
|
|||||||
*/
|
*/
|
||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
exit;
|
|
||||||
$model = new Rrmodel();
|
$model = new Rrmodel();
|
||||||
//同步流程 首先同步所有公众号-》同步商品分类-》同步商品-》同步diy首页-》diy会员-》diy自定义页面-》单独同步vr链接
|
//同步流程 首先同步所有公众号-》同步商品分类-》同步商品-》同步diy首页-》diy会员-》diy自定义页面-》单独同步vr链接
|
||||||
$uniacid = 1083;//设置大于0同步单个
|
$uniacid = 1083;//设置大于0同步单个
|
||||||
|
|||||||
269
src/app/api/controller/Seal.php
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\api\controller;
|
||||||
|
|
||||||
|
use app\model\system\Seal as SealModel;
|
||||||
|
use Mpdf\Mpdf;
|
||||||
|
class Seal extends BaseApi
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getimg($keyword){
|
||||||
|
|
||||||
|
// 设置内容类型为PNG图片
|
||||||
|
header('Content-Type: image/png');
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$info = $sealModel->getInfo('seal_medium',['name'=>$keyword]);
|
||||||
|
$type = ['数据不详','推荐使用','有条件使用','不推荐使用','不能使用'];
|
||||||
|
$value = [];
|
||||||
|
if($info['data']){
|
||||||
|
$value = json_decode($info['data']['value'],true);
|
||||||
|
}
|
||||||
|
// dump($value);
|
||||||
|
// 图片尺寸
|
||||||
|
$width = 640;
|
||||||
|
$height = 1280;
|
||||||
|
|
||||||
|
// 创建画布
|
||||||
|
$image = imagecreatetruecolor($width, $height);
|
||||||
|
|
||||||
|
// 颜色定义
|
||||||
|
$white = imagecolorallocate($image, 255, 255, 255);
|
||||||
|
$black = imagecolorallocate($image, 0, 0, 0);
|
||||||
|
$gray = imagecolorallocate($image, 200, 200, 200);
|
||||||
|
$darkGray = imagecolorallocate($image, 100, 100, 100);
|
||||||
|
|
||||||
|
// 填充背景
|
||||||
|
imagefill($image, 0, 0, $white);
|
||||||
|
|
||||||
|
// 设置字体路径(确保服务器上有此字体文件)
|
||||||
|
$font = PUBLIC_PATH . 'static/font/Microsoft.ttf'; // 宋体字体,支持中文
|
||||||
|
// if (!file_exists($font)) {
|
||||||
|
// $font = 'arial.ttf'; // 备用字体
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 添加标题
|
||||||
|
imagettftext($image, 24, 0, 280, 50, $black, $font, "乙醛");
|
||||||
|
|
||||||
|
// 模拟你的数据
|
||||||
|
// $value = [
|
||||||
|
// ['text' => '项目1', 'value' => '值1', 'color' => '#FF0000'],
|
||||||
|
// ['text' => '项目2', 'value' => '值2', 'color' => '#00FF00'],
|
||||||
|
// ['text' => '项目3', 'value' => '', 'color' => '#0000FF'],
|
||||||
|
// ];
|
||||||
|
|
||||||
|
$type = ['值1' => '类型1', '值2' => '类型2'];
|
||||||
|
|
||||||
|
// 表格参数
|
||||||
|
$startY = 80;
|
||||||
|
$rowHeight = 40;
|
||||||
|
$col1Width = 240;
|
||||||
|
$col2Width = 500;
|
||||||
|
|
||||||
|
// 绘制表格边框
|
||||||
|
imagerectangle($image, 30, $startY, $width-30, $startY + count($value) * $rowHeight, $black);
|
||||||
|
|
||||||
|
// 绘制表格内容
|
||||||
|
foreach ($value as $index => $item) {
|
||||||
|
$y = $startY + $index * $rowHeight;
|
||||||
|
|
||||||
|
// 绘制行线
|
||||||
|
imageline($image, 30, $y, $width-30, $y, $black);
|
||||||
|
$item['color'] = $item['color']?$item['color']:'#FFFFFF';
|
||||||
|
// 解析颜色
|
||||||
|
$color = sscanf($item['color'], "#%02x%02x%02x");
|
||||||
|
|
||||||
|
$textColor = imagecolorallocate($image, $color[0], $color[1], $color[2]);
|
||||||
|
|
||||||
|
// dump($textColor);
|
||||||
|
// 第一列
|
||||||
|
$bgColor = sscanf(ltrim($item['color'], '#'), "%02x%02x%02x");
|
||||||
|
$cellBgColor = imagecolorallocate($image, $bgColor[0], $bgColor[1], $bgColor[2]);
|
||||||
|
imagefilledrectangle($image, 30, $y, 30 + $col1Width, $y + $rowHeight, $cellBgColor);
|
||||||
|
imagettftext($image, 14, 0, 50, $y + 25, $black, $font, $item['text']);
|
||||||
|
|
||||||
|
// 第二列
|
||||||
|
$displayValue = '数据不详';
|
||||||
|
imagettftext($image, 14, 0, 30 + $col1Width + 20, $y + 25, $textColor, $font, $displayValue);
|
||||||
|
// dump($color);
|
||||||
|
// echo $index.'<br/>';
|
||||||
|
// break;
|
||||||
|
// 列分隔线
|
||||||
|
imageline($image, 30 + $col1Width, $y, 30 + $col1Width, $y + $rowHeight, $black);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出PNG图片
|
||||||
|
$time = time();
|
||||||
|
imagepng($image,'upload/1/pdfs/'.$time.'.png');
|
||||||
|
imagedestroy($image);
|
||||||
|
// echo '<img src="/upload/1/pdfs/a.png">';
|
||||||
|
return 'upload/1/pdfs/'.$time.'.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getpdf($id){
|
||||||
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$info = $sealModel->getInfo('seal_medium',['id'=>$id]);
|
||||||
|
try {
|
||||||
|
// 创建 mPDF 实例并配置
|
||||||
|
$mpdf = new \Mpdf\Mpdf([
|
||||||
|
'autoScriptToLang' => true,
|
||||||
|
'autoLangToFont' => true,
|
||||||
|
'mode' => 'utf-8', // 设置编码模式
|
||||||
|
'format' => 'A4', // 设置页面格式
|
||||||
|
'orientation' => 'P', // 页面方向 P-纵向/L-横向
|
||||||
|
'default_font_size' => 12, // 默认字体大小
|
||||||
|
'default_font' => 'sans-serif', // 默认字体
|
||||||
|
'margin_left' => 15, // 左边距(毫米)
|
||||||
|
'margin_right' => 15, // 右边距
|
||||||
|
'margin_top' => 16, // 上边距
|
||||||
|
'margin_bottom' => 16, // 下边距
|
||||||
|
'margin_header' => 9, // 页眉边距
|
||||||
|
'margin_footer' => 9 // 页脚边距
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 设置文档信息(可选)
|
||||||
|
// $mpdf->SetTitle('乙醛');
|
||||||
|
// $mpdf->SetAuthor('你的名字');
|
||||||
|
// $mpdf->SetCreator('PHP mPDF');
|
||||||
|
// $mpdf->SetSubject('mPDF 示例');
|
||||||
|
// $mpdf->SetKeywords('mPDF, PHP, PDF, 示例');
|
||||||
|
|
||||||
|
// 添加页眉(可选)
|
||||||
|
// $mpdf->SetHTMLHeader('
|
||||||
|
// <div style="text-align: right; font-weight: bold;">
|
||||||
|
// 乙醛
|
||||||
|
// </div>
|
||||||
|
// ');
|
||||||
|
|
||||||
|
// 添加页脚(可选)
|
||||||
|
// $mpdf->SetHTMLFooter('
|
||||||
|
// <table width="100%">
|
||||||
|
// <tr>
|
||||||
|
// <td width="33%">{DATE j-m-Y}</td>
|
||||||
|
// <td width="33%" align="center">{PAGENO}/{nbpg}</td>
|
||||||
|
// <td width="33%" style="text-align: right;">乙醛</td>
|
||||||
|
// </tr>
|
||||||
|
// </table>
|
||||||
|
// ');
|
||||||
|
|
||||||
|
$type = ['数据不详','推荐使用','有条件使用','不推荐使用','不能使用'];
|
||||||
|
$value = [];
|
||||||
|
if($info['data']){
|
||||||
|
$value = json_decode($info['data']['value'],true);
|
||||||
|
// foreach($value as &$item){
|
||||||
|
// $item['value'] = $item['value']?$type[$item['value']]:'数据不详';
|
||||||
|
// }
|
||||||
|
// $info['data']['value'] = $value;
|
||||||
|
}
|
||||||
|
// dump($value);
|
||||||
|
// 准备 HTML 内容
|
||||||
|
$html = '
|
||||||
|
<h1 style="text-align: center; color: #333;">乙醛</h1>
|
||||||
|
<table border="1" cellspacing="0" cellpadding="5" width="100%">
|
||||||
|
<!--<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="30%">项目</th>
|
||||||
|
<th width="40%">描述</th>
|
||||||
|
</tr>
|
||||||
|
</thead>-->
|
||||||
|
<tbody>';
|
||||||
|
foreach($value as &$item){
|
||||||
|
// $item['value'] = $item['value']?$type[$item['value']]:'数据不详';
|
||||||
|
$html .= '<tr>
|
||||||
|
<td style="background: '.$item['color'].';">'.$item['text'].'</td>
|
||||||
|
<td style="color: '.$item['color'].';">'.($item['value']?$type[$item['value']]:'数据不详').'</td>
|
||||||
|
</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '</tbody>
|
||||||
|
</table>
|
||||||
|
';
|
||||||
|
// echo $html;exit;
|
||||||
|
// 写入 HTML 内容
|
||||||
|
$mpdf->WriteHTML($html);
|
||||||
|
|
||||||
|
// 输出 PDF
|
||||||
|
// 方式1:直接在浏览器中打开
|
||||||
|
// $mpdf->Output('example.pdf', \Mpdf\Output\Destination::INLINE);
|
||||||
|
|
||||||
|
// 方式2:强制下载
|
||||||
|
// $mpdf->Output('example.pdf', \Mpdf\Output\Destination::DOWNLOAD);
|
||||||
|
$directory = 'upload/1/pdfs/';
|
||||||
|
$time = time();
|
||||||
|
if (!file_exists($directory)) {
|
||||||
|
// 尝试创建目录(递归创建多级目录)
|
||||||
|
if (!mkdir($directory, 0755, true)) {
|
||||||
|
// 创建失败处理
|
||||||
|
die("无法创建目录: $directory");
|
||||||
|
}
|
||||||
|
// echo "目录创建成功: $directory";
|
||||||
|
}
|
||||||
|
// 方式3:保存到服务器
|
||||||
|
$pdf = $directory.'/'.$time.'.pdf';
|
||||||
|
$mpdf->Output($pdf, \Mpdf\Output\Destination::FILE);
|
||||||
|
return $pdf;
|
||||||
|
} catch (\Mpdf\MpdfException $e) {
|
||||||
|
// 处理异常
|
||||||
|
// echo '生成PDF时出错: ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础信息
|
||||||
|
*/
|
||||||
|
public function info()
|
||||||
|
{
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$keyword = $this->params['keyword'] ?? '';
|
||||||
|
$info = $sealModel->getInfo('seal_medium',['name'=>$keyword]);
|
||||||
|
//1推荐使用,2有条件使用,3不推荐使用,4不能使用,空格,数据不详
|
||||||
|
$type = ['数据不详','推荐使用','有条件使用','不推荐使用','不能使用'];
|
||||||
|
if($info['data']){
|
||||||
|
$value = json_decode($info['data']['value'],true);
|
||||||
|
foreach($value as &$item){
|
||||||
|
$item['value'] = $item['value']?$type[$item['value']]:'数据不详';
|
||||||
|
}
|
||||||
|
$info['data']['value'] = $value;
|
||||||
|
//生成pdf和img
|
||||||
|
if(!$info['data']['files_url']){
|
||||||
|
$pdf = $this->getpdf($info['data']['id']);
|
||||||
|
if($pdf){
|
||||||
|
model('seal_medium')->update(['files_url'=>$pdf],['id'=>$info['data']['id']]);
|
||||||
|
$info['data']['files_url'] = $pdf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$info['data']['img_url'] = $this->getimg($keyword);
|
||||||
|
}
|
||||||
|
return $this->response($info['data']);
|
||||||
|
// $help_id = $this->params['id'] ?? 0;
|
||||||
|
// if (empty($help_id)) {
|
||||||
|
// return $this->response($this->error('', 'REQUEST_ID'));
|
||||||
|
// }
|
||||||
|
// $help = new HelpModel();
|
||||||
|
// $info = $help->getHelpInfo($help_id);
|
||||||
|
// return $this->response($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function search(){
|
||||||
|
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$keyword = $this->params['keyword'] ?? '';
|
||||||
|
$list = $sealModel->getList('seal_medium',[['name','like','%'.$keyword.'%']]);
|
||||||
|
return $this->response(['code'=>0,'list'=>$list]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础信息
|
||||||
|
*/
|
||||||
|
public function getstructure()
|
||||||
|
{
|
||||||
|
$sealModel = new SealModel();
|
||||||
|
$condition[] = [ 'site_id', '=', $this->site_id ];
|
||||||
|
$field = '*';
|
||||||
|
$list = $sealModel->getTree1($condition, $field);
|
||||||
|
if (request()->isJson()) return $list;
|
||||||
|
return $this->response($list);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
@CHARSET "UTF-8";
|
@CHARSET "UTF-8";
|
||||||
|
|
||||||
|
|
||||||
|
.digit-navigation .preview-draggable {padding: 0;}
|
||||||
|
.digit-navigation .audio-wrap audio{width: 100%;position: relative;}
|
||||||
|
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .audio-add-box .img-block {width: 200px !important;height: 125px !important;margin-bottom: 30px;margin-right: 0;position: relative;}
|
||||||
|
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .audio-add-box .img-block > div {line-height: 125px;height: 125px !important;width: 100%;text-align: center;}
|
||||||
|
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .audio-add-box .img-block audio {width: 100% !important;height: 125px !important;}
|
||||||
|
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .audio-add-box .img-block span{position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}
|
||||||
|
.digit-navigation .audio-zhezhao {position: absolute;background: #fff;width: 61%;height: 125px;top: 1px;right: 32px;text-align: center;line-height: 105px;display: none;}
|
||||||
|
.digit-navigation .audio-zhezhao span {position: absolute;top: 35px;left: 80px;color: #909399;}
|
||||||
|
|
||||||
/*图文导航组件*/
|
/*图文导航组件*/
|
||||||
.digit-navigation .preview-draggable .preview-box {
|
.digit-navigation .preview-draggable .preview-box {
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
<template v-if="nc.lazyLoad">
|
<template v-if="nc.lazyLoad">
|
||||||
|
|
||||||
<div :class="['digit-nav',nc.showStyle] " :style="{
|
<div :class="['digit-nav',nc.showStyle] " :style="{
|
||||||
backgroundColor: nc.componentBgColor,
|
backgroundImage: 'url('+nc.imageUrl+')',
|
||||||
|
backgroundSize:'100% 100%',
|
||||||
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
|
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
|
||||||
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
|
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
|
||||||
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
|
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
|
||||||
@@ -48,8 +49,7 @@
|
|||||||
<!-- 内容编辑 -->
|
<!-- 内容编辑 -->
|
||||||
<template slot="edit-content">
|
<template slot="edit-content">
|
||||||
<template v-if="nc.lazyLoad">
|
<template v-if="nc.lazyLoad">
|
||||||
|
<!-- <digit-nav-list></digit-nav-list> -->
|
||||||
<digit-nav-list></digit-nav-list>
|
|
||||||
<div class="template-edit-title">
|
<div class="template-edit-title">
|
||||||
<h3>数字项设置</h3>
|
<h3>数字项设置</h3>
|
||||||
<div class="layui-form-item icon-radio">
|
<div class="layui-form-item icon-radio">
|
||||||
@@ -109,10 +109,11 @@
|
|||||||
<template slot="edit-style">
|
<template slot="edit-style">
|
||||||
<template v-if="nc.lazyLoad">
|
<template v-if="nc.lazyLoad">
|
||||||
<div class="template-edit-title">
|
<div class="template-edit-title">
|
||||||
<!--
|
|
||||||
<h3>图文导航</h3>
|
|
||||||
|
|
||||||
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
|
<h3>背景设置</h3>
|
||||||
|
|
||||||
|
<digit-images></digit-images>
|
||||||
|
<!-- <color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
|
||||||
|
|
||||||
|
|
||||||
<div class="template-edit-title" v-show="['listmenu','img'].includes(nc.mode) && nc.type == 'img'">
|
<div class="template-edit-title" v-show="['listmenu','img'].includes(nc.mode) && nc.type == 'img'">
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
/**
|
/**
|
||||||
* [图片导航的图片]·组件
|
* [图片导航的图片]·组件
|
||||||
*/
|
*/
|
||||||
var digitNavListHtml = '<div style="display: none;"></div>';
|
// var digitNavListHtml = '<div style="display: none;"></div>';
|
||||||
Vue.component("digit-nav-list", {
|
var igitNavHtml = '<div class="digit-images">';
|
||||||
template: digitNavListHtml,
|
|
||||||
|
igitNavHtml += '<div class="template-edit-title">';
|
||||||
|
|
||||||
|
igitNavHtml += '<div class="layui-form-item">';
|
||||||
|
igitNavHtml += '<label class="layui-form-label sm">背景图</label>';
|
||||||
|
igitNavHtml += '<img-upload :data="{data : data}"></img-upload>';
|
||||||
|
igitNavHtml += '</div>';
|
||||||
|
|
||||||
|
igitNavHtml += '</div>';
|
||||||
|
|
||||||
|
igitNavHtml += '</div>';
|
||||||
|
Vue.component("digit-images", {
|
||||||
|
template: igitNavHtml,
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
data: this.$parent.data,
|
data: this.$parent.data,
|
||||||
@@ -89,7 +101,7 @@
|
|||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
setnum(num){
|
setnum(num){
|
||||||
console.log(num)
|
console.log(this.data)
|
||||||
this.data.rowCount = num
|
this.data.rowCount = num
|
||||||
if(num == 3){
|
if(num == 3){
|
||||||
this.data.list = [
|
this.data.list = [
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Task extends Controller
|
|||||||
log_write('Task checkCron ...', 'debug');
|
log_write('Task checkCron ...', 'debug');
|
||||||
$cron_model = new Cron();
|
$cron_model = new Cron();
|
||||||
$result = $cron_model->checkSchedule();
|
$result = $cron_model->checkSchedule();
|
||||||
log_write('Task checkCron result: ' . json_encode($result), 'debug');
|
log_write('Task checkCron result: ' . formatForLog($result), 'debug');
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class DiyViewEdit extends Controller
|
|||||||
}
|
}
|
||||||
$diy_view_utils = array_values($diy_view_utils);
|
$diy_view_utils = array_values($diy_view_utils);
|
||||||
|
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($diy_view_utils,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($diy_view_utils,true));
|
||||||
$this->assign('diy_view_utils', $diy_view_utils);
|
$this->assign('diy_view_utils', $diy_view_utils);
|
||||||
|
|
||||||
$this->assign("time", time());
|
$this->assign("time", time());
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class InitConfig
|
|||||||
$this->initConst();
|
$this->initConst();
|
||||||
//初始化配置信息
|
//初始化配置信息
|
||||||
$this->initConfig();
|
$this->initConfig();
|
||||||
log_write('系统配置信息已初始化', 'debug');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ class Goods extends BaseMerchant
|
|||||||
$condition[] = [ 'ischeck', '=', 1 ];
|
$condition[] = [ 'ischeck', '=', 1 ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
|
||||||
if (!empty($start_sale)) $condition[] = [ 'sale_num', '>=', $start_sale ];
|
if (!empty($start_sale)) $condition[] = [ 'sale_num', '>=', $start_sale ];
|
||||||
if (!empty($end_sale)) $condition[] = [ 'sale_num', '<=', $end_sale ];
|
if (!empty($end_sale)) $condition[] = [ 'sale_num', '<=', $end_sale ];
|
||||||
if (!empty($start_price)) $condition[] = [ 'price', '>=', $start_price ];
|
if (!empty($start_price)) $condition[] = [ 'price', '>=', $start_price ];
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class Order extends BaseMerchant
|
|||||||
$order_status = input('order_status', '');//订单状态
|
$order_status = input('order_status', '');//订单状态
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($order_status,true));
|
|
||||||
$order_name = input('order_name', '');
|
$order_name = input('order_name', '');
|
||||||
$pay_type = input('pay_type', '');
|
$pay_type = input('pay_type', '');
|
||||||
$order_from = input('order_from', '');
|
$order_from = input('order_from', '');
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class Model
|
|||||||
/**
|
/**
|
||||||
* 获取分页列表数据
|
* 获取分页列表数据
|
||||||
* @param array $condition
|
* @param array $condition
|
||||||
* @param bool $field
|
* @param bool | string $field
|
||||||
* @param string $order
|
* @param string $order
|
||||||
* @param int $page
|
* @param int $page
|
||||||
* @param int $list_rows
|
* @param int $list_rows
|
||||||
|
|||||||
@@ -1077,7 +1077,7 @@ class Goods extends BaseModel
|
|||||||
public function getGoodsPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'a.create_time desc', $field = 'a.goods_id,a.goods_name,a.site_id,a.site_name,a.goods_image,a.goods_state,a.price,a.goods_stock,a.goods_stock_alarm,a.create_time,a.sale_num,a.is_virtual,a.goods_class,a.goods_class_name,a.is_fenxiao,a.fenxiao_type,a.promotion_addon,a.sku_id,a.is_consume_discount,a.discount_config,a.discount_method,a.sort,a.label_id,a.is_delete', $alias = 'a', $join = [])
|
public function getGoodsPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'a.create_time desc', $field = 'a.goods_id,a.goods_name,a.site_id,a.site_name,a.goods_image,a.goods_state,a.price,a.goods_stock,a.goods_stock_alarm,a.create_time,a.sale_num,a.is_virtual,a.goods_class,a.goods_class_name,a.is_fenxiao,a.fenxiao_type,a.promotion_addon,a.sku_id,a.is_consume_discount,a.discount_config,a.discount_method,a.sort,a.label_id,a.is_delete', $alias = 'a', $join = [])
|
||||||
{
|
{
|
||||||
$res = model('goods')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
|
$res = model('goods')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export(Db::getLastSql(),true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export(Db::getLastSql(),true));
|
||||||
foreach ($res[ 'list' ] as $k => $v) {
|
foreach ($res[ 'list' ] as $k => $v) {
|
||||||
if (isset($v[ 'goods_stock' ])) {
|
if (isset($v[ 'goods_stock' ])) {
|
||||||
$res[ 'list' ][ $k ][ 'goods_stock' ] = numberFormat($res[ 'list' ][ $k ][ 'goods_stock' ]);
|
$res[ 'list' ][ $k ][ 'goods_stock' ] = numberFormat($res[ 'list' ][ $k ][ 'goods_stock' ]);
|
||||||
@@ -2160,7 +2160,7 @@ class Goods extends BaseModel
|
|||||||
|
|
||||||
return $this->addGoods($data);
|
return $this->addGoods($data);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
dump($e);
|
// dump($e);
|
||||||
return $this->error('', $e->getMessage());
|
return $this->error('', $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,8 @@ class GoodsApi extends BaseModel
|
|||||||
$goods_sku_detail[ 'store_goods_status' ] = 1;
|
$goods_sku_detail[ 'store_goods_status' ] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//后端处理缺少域名问题,后续处理到前端 add lucky
|
||||||
|
if($goods_sku_detail['pdf_url']) $goods_sku_detail['pdf_url'] = 'https://'.$_SERVER['HTTP_HOST'].'/'.$goods_sku_detail['pdf_url'];
|
||||||
$goods_sku_detail[ 'purchased_num' ] = 0; // 该商品已购数量
|
$goods_sku_detail[ 'purchased_num' ] = 0; // 该商品已购数量
|
||||||
$res[ 'goods_sku_detail' ] = $goods_sku_detail;
|
$res[ 'goods_sku_detail' ] = $goods_sku_detail;
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class Login extends BaseModel
|
|||||||
$info = [];
|
$info = [];
|
||||||
$auth_tag = '';
|
$auth_tag = '';
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
if (in_array($key, [ 'wx_unionid', 'wx_openid', 'weapp_openid', 'qq_openid', 'ali_openid', 'baidu_openid', 'toutiao_openid' ])) {
|
if (in_array($key, [ 'wx_unionid', 'wx_openid', 'weapp_openid', 'qq_openid', 'ali_openid', 'baidu_openid', 'toutiao_openid', 'huawei_openid' ])) {
|
||||||
$auth_tag = $key;
|
$auth_tag = $key;
|
||||||
if (empty($value)) return $this->error('', 'PARAMETER_ERROR');
|
if (empty($value)) return $this->error('', 'PARAMETER_ERROR');
|
||||||
$info = model("member")->getInfo(
|
$info = model("member")->getInfo(
|
||||||
@@ -95,7 +95,8 @@ class Login extends BaseModel
|
|||||||
// 会员不存在 第三方自动注册开启 未开启绑定手机 则进行自动注册
|
// 会员不存在 第三方自动注册开启 未开启绑定手机 则进行自动注册
|
||||||
$config = new Config();
|
$config = new Config();
|
||||||
$config_info = $config->getRegisterConfig($data[ 'site_id' ], 'shop');
|
$config_info = $config->getRegisterConfig($data[ 'site_id' ], 'shop');
|
||||||
if ($config_info[ 'data' ][ 'value' ][ 'third_party' ] && !$config_info[ 'data' ][ 'value' ][ 'bind_mobile' ]) {
|
//华为元服务静默不用判断强制手机号
|
||||||
|
if (($config_info[ 'data' ][ 'value' ][ 'third_party' ] && !$config_info[ 'data' ][ 'value' ][ 'bind_mobile' ]) || $auth_tag == 'huawei_openid') {
|
||||||
$register = new Register();
|
$register = new Register();
|
||||||
$register_res = $register->authRegister($data);
|
$register_res = $register->authRegister($data);
|
||||||
if ($register_res[ 'code' ] == 0) {
|
if ($register_res[ 'code' ] == 0) {
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ use think\facade\Config;
|
|||||||
class Member extends BaseModel
|
class Member extends BaseModel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function getBusinessPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
|
||||||
|
{
|
||||||
|
$list = model('business')->pageList($condition, $field, $order, $page, $page_size, '', '', '');
|
||||||
|
return $this->success($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加会员(注意等级名称)
|
* 添加会员(注意等级名称)
|
||||||
* @param $data
|
* @param $data
|
||||||
@@ -256,6 +264,7 @@ class Member extends BaseModel
|
|||||||
$member_info = model('member')->setIsCache(0)->getInfo($condition, $field);
|
$member_info = model('member')->setIsCache(0)->getInfo($condition, $field);
|
||||||
|
|
||||||
if (!empty($member_info) && empty($member_info[ 'wx_openid' ]) && !empty($member_info[ 'wx_unionid' ])) {
|
if (!empty($member_info) && empty($member_info[ 'wx_openid' ]) && !empty($member_info[ 'wx_unionid' ])) {
|
||||||
|
// TODO: 注意, 华为云上的最新代码,下面都注释掉了,
|
||||||
$fans_model = new Fans();
|
$fans_model = new Fans();
|
||||||
$fans_condition[] = [ "unionid", "=", $member_info[ 'wx_unionid' ] ];
|
$fans_condition[] = [ "unionid", "=", $member_info[ 'wx_unionid' ] ];
|
||||||
$fans_info = $fans_model->getFansInfo($fans_condition);
|
$fans_info = $fans_model->getFansInfo($fans_condition);
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class Register extends BaseModel
|
|||||||
'ali_openid' => $data['ali_openid'] ?? '',
|
'ali_openid' => $data['ali_openid'] ?? '',
|
||||||
'baidu_openid' => $data['baidu_openid'] ?? '',
|
'baidu_openid' => $data['baidu_openid'] ?? '',
|
||||||
'toutiao_openid' => $data['toutiao_openid'] ?? '',
|
'toutiao_openid' => $data['toutiao_openid'] ?? '',
|
||||||
|
'huawei_openid' => $data['huawei_openid'] ?? '',
|
||||||
'headimg' => $data['avatarUrl'] ?? '',
|
'headimg' => $data['avatarUrl'] ?? '',
|
||||||
'member_level' => !empty($member_level_info) ? $member_level_info[ 'level_id' ] : 0,
|
'member_level' => !empty($member_level_info) ? $member_level_info[ 'level_id' ] : 0,
|
||||||
'member_level_name' => !empty($member_level_info) ? $member_level_info[ 'level_name' ] : '',
|
'member_level_name' => !empty($member_level_info) ? $member_level_info[ 'level_name' ] : '',
|
||||||
|
|||||||
@@ -1198,7 +1198,6 @@ class OrderCommon extends BaseModel
|
|||||||
public function getOrderPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*', $alias = 'a', $join = [])
|
public function getOrderPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*', $alias = 'a', $join = [])
|
||||||
{
|
{
|
||||||
$order_list = model('order')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
|
$order_list = model('order')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
|
|
||||||
$check_condition = array_column($condition, 2, 0);
|
$check_condition = array_column($condition, 2, 0);
|
||||||
|
|
||||||
if (!empty($order_list[ 'list' ])) {
|
if (!empty($order_list[ 'list' ])) {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class OrderCreate extends BaseModel
|
|||||||
model('order')->startTrans();
|
model('order')->startTrans();
|
||||||
$pay_model = new Pay();
|
$pay_model = new Pay();
|
||||||
$this->out_trade_no = $pay_model->createOutTradeNo($this->member_id);
|
$this->out_trade_no = $pay_model->createOutTradeNo($this->member_id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
//循环生成多个订单
|
//循环生成多个订单
|
||||||
@@ -52,15 +53,16 @@ class OrderCreate extends BaseModel
|
|||||||
$order_insert_data['order_type_name'] = $this->order_type['order_type_name'];
|
$order_insert_data['order_type_name'] = $this->order_type['order_type_name'];
|
||||||
$order_insert_data['order_status_name'] = $this->order_type['order_status']['name'];
|
$order_insert_data['order_status_name'] = $this->order_type['order_status']['name'];
|
||||||
$order_insert_data['order_status_action'] = json_encode($this->order_type['order_status'], JSON_UNESCAPED_UNICODE);
|
$order_insert_data['order_status_action'] = json_encode($this->order_type['order_status'], JSON_UNESCAPED_UNICODE);
|
||||||
|
$order_insert_data['business'] = input('business','');
|
||||||
if($i >= 1){
|
if($i >= 1){
|
||||||
//主表订单id
|
//主表订单id
|
||||||
$order_insert_data['host_order_id'] = $this->order_id;
|
$order_insert_data['host_order_id'] = $this->order_id;
|
||||||
// file_put_contents(__DIR__ . '/debug.txt', var_export($order_insert_data,true));
|
|
||||||
$order_id = model('order')->add($order_insert_data);
|
$order_id = model('order')->add($order_insert_data);
|
||||||
}else{
|
}else{
|
||||||
$order_id = model('order')->add($order_insert_data);
|
$order_id = model('order')->add($order_insert_data);
|
||||||
$this->order_id = $order_id;
|
$this->order_id = $order_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$order_goods_insert_data = [];
|
$order_goods_insert_data = [];
|
||||||
//订单项目表
|
//订单项目表
|
||||||
foreach ($v['goods_list'] as $order_goods_v) {
|
foreach ($v['goods_list'] as $order_goods_v) {
|
||||||
|
|||||||
@@ -712,7 +712,7 @@ trait PromotionTool
|
|||||||
//-------------
|
//-------------
|
||||||
/* $all_info = $manjian_model->getManjianInfo([['manjian_type', '=', 1], ['site_id', '=', $this->site_id], ['status', '=', 1]], 'manjian_name,type,goods_ids,rule_json,manjian_id')['data'];
|
/* $all_info = $manjian_model->getManjianInfo([['manjian_type', '=', 1], ['site_id', '=', $this->site_id], ['status', '=', 1]], 'manjian_name,type,goods_ids,rule_json,manjian_id')['data'];
|
||||||
$goods_list = $this->goods_list;
|
$goods_list = $this->goods_list;
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($all_info,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($all_info,true));
|
||||||
//存在全场满减(不考虑部分满减情况)
|
//存在全场满减(不考虑部分满减情况)
|
||||||
if (!empty($all_info)) {//满减默认
|
if (!empty($all_info)) {//满减默认
|
||||||
$discount_array = $this->getManjianDiscountMoney($all_info);
|
$discount_array = $this->getManjianDiscountMoney($all_info);
|
||||||
|
|||||||
@@ -66,11 +66,11 @@ class Document extends BaseModel
|
|||||||
public function getDocument($condition)
|
public function getDocument($condition)
|
||||||
{
|
{
|
||||||
|
|
||||||
// $json_condition = json_encode($condition);
|
$json_condition = json_encode($condition);
|
||||||
// $cache = Cache::get("document_" . $json_condition, "");
|
$cache = Cache::get("document_" . $json_condition, "");
|
||||||
// if (!empty($cache)) {
|
if (!empty($cache)) {
|
||||||
// return $this->success($cache);
|
return $this->success($cache);
|
||||||
// }
|
}
|
||||||
$check_condition = array_column($condition, 2, 0);
|
$check_condition = array_column($condition, 2, 0);
|
||||||
$site_id = $check_condition['site_id'] ?? '';
|
$site_id = $check_condition['site_id'] ?? '';
|
||||||
if ($site_id === '') {
|
if ($site_id === '') {
|
||||||
@@ -98,7 +98,7 @@ class Document extends BaseModel
|
|||||||
'modify_time' => 0
|
'modify_time' => 0
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// Cache::tag("document")->set("document_" . $json_condition, $info);
|
Cache::tag("document")->set("document_" . $json_condition, $info);
|
||||||
return $this->success($info);
|
return $this->success($info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Menu extends BaseModel
|
|||||||
// if (!empty($cache)) {
|
// if (!empty($cache)) {
|
||||||
// return $this->success($cache);
|
// return $this->success($cache);
|
||||||
// }
|
// }
|
||||||
$list = model('menu')->getList($condition, $field, $order, '', '', '', $limit);
|
$list = model('menu')->getList($condition, $field, $order, '', [], '', $limit);
|
||||||
// Cache::tag("menu")->set("getMenuList_" . $data, $list);
|
// Cache::tag("menu")->set("getMenuList_" . $data, $list);
|
||||||
|
|
||||||
return $this->success($list);
|
return $this->success($list);
|
||||||
|
|||||||
338
src/app/model/system/Seal.php
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\model\system;
|
||||||
|
|
||||||
|
use extend\api\HttpClient;
|
||||||
|
use think\facade\Cache;
|
||||||
|
use app\model\BaseModel;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class Seal extends BaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function getTree($condition = [], $field = '*', $order = 'sort asc,category_id desc', $limit = null)
|
||||||
|
{
|
||||||
|
$list = model('seal_structure')->getList($condition, $field, $order, '', '', '', $limit);
|
||||||
|
$categoryMap = [];
|
||||||
|
foreach ($list as $item) {
|
||||||
|
$categoryMap[$item['category_id']] = $item;
|
||||||
|
$categoryMap[$item['category_id']]['child_list'] = [];
|
||||||
|
}
|
||||||
|
$buildTree = function ($parentId = 0) use (&$buildTree, $categoryMap) {
|
||||||
|
$children = [];
|
||||||
|
foreach ($categoryMap as $id => $item) {
|
||||||
|
if ($item['pid'] == $parentId) {
|
||||||
|
$item['child_list'] = $buildTree($id);
|
||||||
|
$children[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $children;
|
||||||
|
};
|
||||||
|
|
||||||
|
$tree = $buildTree(0);
|
||||||
|
return $this->success($tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getTree1($condition = [], $field = '*', $order = 'sort asc,category_id desc', $limit = null)
|
||||||
|
{
|
||||||
|
$list = model('seal_structure')->getList($condition, $field, $order, '', '', '', $limit);
|
||||||
|
$categoryMap = [];
|
||||||
|
foreach ($list as $item) {
|
||||||
|
$categoryMap[$item['category_id']] = $item;
|
||||||
|
// 初始化子分类数组(避免子分类为null)
|
||||||
|
$categoryMap[$item['category_id']]['child_list'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归构建树形结构:仅子层级(parentId≠0)添加「请选择」
|
||||||
|
$buildTree = function ($parentId = 0) use (&$buildTree, $categoryMap) {
|
||||||
|
$children = [];
|
||||||
|
foreach ($categoryMap as $id => $item) {
|
||||||
|
if ($item['pid'] == $parentId) {
|
||||||
|
// 1. 递归获取当前分类的子分类(子分类会根据parentId判断是否加占位项)
|
||||||
|
$item['child_list'] = $buildTree($id);
|
||||||
|
$children[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 关键判断:仅当 parentId ≠ 0(子层级)时,才插入「请选择」占位项
|
||||||
|
if ($parentId != 0 && !empty($children)) { // 非顶级 + 有真实子分类时才加(可选,避免空列表加占位)
|
||||||
|
$defaultOption = [
|
||||||
|
'category_id' => 0, // 虚拟ID(与真实分类区分)
|
||||||
|
'pid' => $parentId, // 占位项父ID = 当前层级父ID(匹配真实子分类)
|
||||||
|
'name' => '请选择', // 显示文本
|
||||||
|
'child_list' => [], // 占位项无下级(避免无限嵌套)
|
||||||
|
'is_placeholder' => true // 前端识别标记
|
||||||
|
// 真实分类的其他字段(如sort)可按需添加默认值
|
||||||
|
];
|
||||||
|
|
||||||
|
// 在子层级分类列表头部插入占位项
|
||||||
|
array_unshift($children, $defaultOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成树形结构:顶级分类(parentId=0)不添加「请选择」
|
||||||
|
$tree = $buildTree(0);
|
||||||
|
|
||||||
|
return $this->success($tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取列表带分页
|
||||||
|
* @param array $condition
|
||||||
|
* @param int $page
|
||||||
|
* @param int $page_size
|
||||||
|
* @param string $order
|
||||||
|
* @param bool $field
|
||||||
|
* @param string $alias
|
||||||
|
* @param array $join
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPageList($table,array $condition = [], $page = 1, $page_size = PAGE_LIST_ROWS,$order = '',$field = true, $alias = '', $join = [], $group='')
|
||||||
|
{
|
||||||
|
$res = model($table)->pageList($condition, $field, $order, $page, $page_size, $alias, $join, $group);
|
||||||
|
return $this->success($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情
|
||||||
|
* @param array $condition
|
||||||
|
* @param bool $field
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getInfo($table,$condition = [], $field = true, $alias = 'a', $join = null)
|
||||||
|
{
|
||||||
|
$info = model($table)->getInfo($condition, $field,$alias,$join);
|
||||||
|
return $this->success($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($table,$condition = [])
|
||||||
|
{
|
||||||
|
$info = model($table)->delete($condition);
|
||||||
|
return $this->success($info);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取列表不要分页
|
||||||
|
* @param array $condition
|
||||||
|
* @return array
|
||||||
|
* @throws DataNotFoundException
|
||||||
|
* @throws DbException
|
||||||
|
* @throws ModelNotFoundException
|
||||||
|
*/
|
||||||
|
public function getList($table,$condition = [],$field="*", $order = '', $alias = 'a', $join = [], $group = '')
|
||||||
|
{
|
||||||
|
return model($table)->getList($condition,$field,$order,$alias,$join,$group);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加
|
||||||
|
* @param array $data
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function add($table,array $data)
|
||||||
|
{
|
||||||
|
if (empty($data) || empty($table)) {
|
||||||
|
return $this->error('', 'PARAMETER_ERROR');
|
||||||
|
}
|
||||||
|
$res = model($table)->add($data);
|
||||||
|
return $this->success($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑
|
||||||
|
* @param array $data
|
||||||
|
* @param array $condition
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function edit($table,array $data, array $condition, array $params = [])
|
||||||
|
{
|
||||||
|
if (empty($data)) {
|
||||||
|
return $this->error('', 'PARAMETER_ERROR');
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = model($table)->update($data, $condition);
|
||||||
|
return $this->success($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $param
|
||||||
|
* @param $site_id
|
||||||
|
* @return array
|
||||||
|
* @throws \PHPExcel_Exception
|
||||||
|
* @throws \PHPExcel_Reader_Exception
|
||||||
|
* @throws \think\exception\PDOException
|
||||||
|
*/
|
||||||
|
public function importMedium($param, $site_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$PHPReader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
|
||||||
|
|
||||||
|
//载入文件
|
||||||
|
$PHPExcel = $PHPReader->load($param[ 'path' ]);
|
||||||
|
|
||||||
|
//获取表中的第一个工作表,如果要获取第二个,把0改为1,依次类推
|
||||||
|
$currentSheet = $PHPExcel->getSheet(0);
|
||||||
|
|
||||||
|
//获取总行数
|
||||||
|
$allRow = $currentSheet->getHighestRow();
|
||||||
|
|
||||||
|
if ($allRow < 2) {
|
||||||
|
return $this->error('', '导入了一个空文件');
|
||||||
|
}
|
||||||
|
|
||||||
|
$index = $param[ 'index' ];
|
||||||
|
|
||||||
|
//每次导入100条
|
||||||
|
$length = $index * 2000;
|
||||||
|
|
||||||
|
if ($index == 1) {
|
||||||
|
$num = 27
|
||||||
|
;
|
||||||
|
$success_num = 0;
|
||||||
|
$error_num = 0;
|
||||||
|
|
||||||
|
$data_record = [
|
||||||
|
"member_num" => ( $allRow - 1 ),
|
||||||
|
"success_num" => 0,
|
||||||
|
"error_num" => 0,
|
||||||
|
"create_time" => time(),
|
||||||
|
"status_name" => "等待导入"
|
||||||
|
];
|
||||||
|
$record = model('seal_medium_import_record')->add($data_record);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$num = ( ( $index - 1 ) * 100 ) + 1;
|
||||||
|
$success_num = $param[ 'success_num' ];
|
||||||
|
$error_num = $param[ 'error_num' ];
|
||||||
|
$record = $param[ 'record' ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$type_num = 0;
|
||||||
|
model('seal_medium')->startTrans();
|
||||||
|
$field = ['C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T'];
|
||||||
|
$name = ['全氟醚FFKM','聚全氟乙丙稀FEPM','丁苯橡胶SBR','氯丁橡胶CR','聚四氟乙烯PTFE','三元乙丙橡胶EPDM','氯醇橡胶 ECO','丁基橡胶 ⅡR','丁腈橡胶 NBR','丙烯酸酯橡胶ACM','聚氨酯 PU','天然橡胶 NR','氟橡胶 FKM','乙丙烯酸酯橡胶AEM','氢化丁腈橡胶HNBR','氟硅橡胶 FVMQ','氯磺化聚乙烯CSM','硅橡胶 VMQ'];
|
||||||
|
$colors = ['#D5663F','','#E09E36','','#DDDF37','','#75C551','','#54C28D','','#409CBD','','#5B5FBB','','#A061B5','','#BC5A6A',''];//颜色表
|
||||||
|
try {
|
||||||
|
|
||||||
|
for ($i = $num; $i <= $length; $i++) {
|
||||||
|
|
||||||
|
//这一行是化学介质行直接跳过
|
||||||
|
// if($num == 26) continue;
|
||||||
|
|
||||||
|
if ($i > $allRow) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$type_num = $i;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$title = $PHPExcel->getActiveSheet()->getCell('B' . $i)->getValue();
|
||||||
|
$title = trim($title);
|
||||||
|
if($title == '') break;
|
||||||
|
//获取每一列的值
|
||||||
|
$value_data = [];
|
||||||
|
foreach($field as $k=>$item){
|
||||||
|
$value = $PHPExcel->getActiveSheet()->getCell($item . $i)->getValue();
|
||||||
|
// //1推荐使用,2有条件使用,3不推荐使用,4不能使用,空格,数据不详
|
||||||
|
$colortext = '#333';
|
||||||
|
if($value == 1){
|
||||||
|
$colortext = '#75c551';
|
||||||
|
}else if($value == 2){
|
||||||
|
$colortext = '#409cbd';
|
||||||
|
}else if($value == 3){
|
||||||
|
$colortext = '#e09e36';
|
||||||
|
}else if($value == 4){
|
||||||
|
$colortext = '#ff0000';
|
||||||
|
}
|
||||||
|
$value_data[] = [
|
||||||
|
'text'=>$name[$k],
|
||||||
|
'value'=>trim($value),
|
||||||
|
'color'=>$colortext,
|
||||||
|
'background'=>$colors[$k]
|
||||||
|
];
|
||||||
|
// echo $value.'<br/>';
|
||||||
|
}
|
||||||
|
// dump($value_data);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name'=>$title,
|
||||||
|
'value'=>json_encode($value_data)
|
||||||
|
];
|
||||||
|
$res = model('seal_medium')->add($data);
|
||||||
|
// dump($data);
|
||||||
|
// break;
|
||||||
|
// exit;
|
||||||
|
|
||||||
|
// $not_data = [
|
||||||
|
// "username" => $username,
|
||||||
|
// "number" => $number,
|
||||||
|
// "company" => $company,
|
||||||
|
// "company_realname" => $company_realname,
|
||||||
|
// "company_mobile" => $company_mobile,
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// if ($username == "" && $mobile == "") {
|
||||||
|
// $not_data[ 'content' ] = "失败,用户名或手机号必须存在一个";
|
||||||
|
// model('member_import_log')->add($not_data);
|
||||||
|
// $error_num++;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $data = [
|
||||||
|
// "username" => $username,
|
||||||
|
// "number" => $number,
|
||||||
|
// "company" => $company,
|
||||||
|
// "company_realname" => $company_realname,
|
||||||
|
// "company_mobile" => $company_mobile,
|
||||||
|
// ];
|
||||||
|
// $res = model('seal_medium_import_record')->add($data);
|
||||||
|
// $product = model('device')->getInfo([ [ 'id', '=', $res ]]);
|
||||||
|
|
||||||
|
$not_data[ 'content' ] = "成功";
|
||||||
|
// model('member_import_log')->add($not_data);
|
||||||
|
$success_num++;
|
||||||
|
}
|
||||||
|
model('seal_medium')->commit();
|
||||||
|
if ($success_num + $error_num == ( $allRow - 1 )) {
|
||||||
|
$data_record = [
|
||||||
|
"member_num" => ( $allRow - 1 ),
|
||||||
|
"success_num" => $success_num,
|
||||||
|
"error_num" => $error_num,
|
||||||
|
"create_time" => time()
|
||||||
|
];
|
||||||
|
if ($success_num == ( $allRow - 1 )) {
|
||||||
|
$data_record[ 'status_name' ] = '导入成功';
|
||||||
|
} elseif ($error_num == ( $allRow - 1 )) {
|
||||||
|
$data_record[ 'status_name' ] = '导入失败';
|
||||||
|
}
|
||||||
|
|
||||||
|
model('seal_medium_import_record')->update($data_record, [ 'id' => $record ]);
|
||||||
|
}
|
||||||
|
return $this->success([
|
||||||
|
"allRow" => $allRow,
|
||||||
|
"num" => $type_num,
|
||||||
|
"path" => $param[ 'path' ],
|
||||||
|
"name" => $param[ 'filename' ],
|
||||||
|
"success_num" => $success_num,
|
||||||
|
"error_num" => $error_num,
|
||||||
|
"record" => $record
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
model('seal_medium')->rollback();
|
||||||
|
return $this->error('', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\model\web;
|
namespace app\model\web;
|
||||||
|
|
||||||
use app\model\system\Config as ConfigModel;
|
use app\model\system\Config as ConfigModel;
|
||||||
@@ -61,7 +60,7 @@ class Config extends BaseModel
|
|||||||
public function setCaptchaConfig($data, $site_id = 1, $app_module = 'shop')
|
public function setCaptchaConfig($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '验证码设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'CAPTCHA_CONFIG']]);
|
$res = $config->setConfig($data, '验证码设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'CAPTCHA_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,20 +73,20 @@ class Config extends BaseModel
|
|||||||
public function getCaptchaConfig($site_id = 1, $app_module = 'shop')
|
public function getCaptchaConfig($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'CAPTCHA_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'CAPTCHA_CONFIG' ] ]);
|
||||||
|
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'shop_login' => 1,
|
'shop_login' => 1,
|
||||||
'shop_reception_login' => 1,
|
'shop_reception_login' => 1,
|
||||||
'shop_reception_register' => 1
|
'shop_reception_register' => 1
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
if (isset($res['data']['value']['shop_reception_login']) === false) {
|
if (isset($res[ 'data' ][ 'value' ][ 'shop_reception_login' ]) === false) {
|
||||||
$res['data']['value']['shop_reception_login'] = 1;
|
$res[ 'data' ][ 'value' ][ 'shop_reception_login' ] = 1;
|
||||||
}
|
}
|
||||||
if (isset($res['data']['value']['shop_reception_register']) === false) {
|
if (isset($res[ 'data' ][ 'value' ][ 'shop_reception_register' ]) === false) {
|
||||||
$res['data']['value']['shop_reception_register'] = 1;
|
$res[ 'data' ][ 'value' ][ 'shop_reception_register' ] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
@@ -102,31 +101,31 @@ class Config extends BaseModel
|
|||||||
*/
|
*/
|
||||||
public function setDefaultImg($data, $site_id = 0, $app_module = 'shop')
|
public function setDefaultImg($data, $site_id = 0, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config_info = $this->getDefaultImg($site_id, $app_module)['data']['value'];
|
$config_info = $this->getDefaultImg($site_id, $app_module)[ 'data' ][ 'value' ];
|
||||||
if (!empty($config_info)) {
|
if (!empty($config_info)) {
|
||||||
$upload_model = new Upload();
|
$upload_model = new Upload();
|
||||||
if ($data['goods'] && $config_info['goods'] && $data['goods'] != $config_info['goods']) {
|
if ($data[ 'goods' ] && $config_info[ 'goods' ] && $data[ 'goods' ] != $config_info[ 'goods' ]) {
|
||||||
$upload_model->deletePic($config_info['goods'], $site_id);
|
$upload_model->deletePic($config_info[ 'goods' ], $site_id);
|
||||||
}
|
}
|
||||||
if ($data['head'] && $config_info['head'] && $data['head'] != $config_info['head']) {
|
if ($data[ 'head' ] && $config_info[ 'head' ] && $data[ 'head' ] != $config_info[ 'head' ]) {
|
||||||
$upload_model->deletePic($config_info['head'], $site_id);
|
$upload_model->deletePic($config_info[ 'head' ], $site_id);
|
||||||
}
|
}
|
||||||
if ($data['store'] && $config_info['store'] && $data['store'] != $config_info['store']) {
|
if ($data[ 'store' ] && $config_info[ 'store' ] && $data[ 'store' ] != $config_info[ 'store' ]) {
|
||||||
$upload_model->deletePic($config_info['store'], $site_id);
|
$upload_model->deletePic($config_info[ 'store' ], $site_id);
|
||||||
}
|
}
|
||||||
if ($data['article'] && $config_info['article'] && $data['article'] != $config_info['article']) {
|
if ($data[ 'article' ] && $config_info[ 'article' ] && $data[ 'article' ] != $config_info[ 'article' ]) {
|
||||||
$upload_model->deletePic($config_info['article'], $site_id);
|
$upload_model->deletePic($config_info[ 'article' ], $site_id);
|
||||||
}
|
}
|
||||||
if ($data['kefu'] && $config_info['kefu'] && $data['kefu'] != $config_info['kefu']) {
|
if ($data[ 'kefu' ] && $config_info[ 'kefu' ] && $data[ 'kefu' ] != $config_info[ 'kefu' ]) {
|
||||||
$upload_model->deletePic($config_info['kefu'], $site_id);
|
$upload_model->deletePic($config_info[ 'kefu' ], $site_id);
|
||||||
}
|
}
|
||||||
if ($data['phone'] && $config_info['phone'] && $data['phone'] != $config_info['phone']) {
|
if ($data[ 'phone' ] && $config_info[ 'phone' ] && $data[ 'phone' ] != $config_info[ 'phone' ]) {
|
||||||
$upload_model->deletePic($config_info['phone'], $site_id);
|
$upload_model->deletePic($config_info[ 'phone' ], $site_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '默认图设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DEFAULT_IMAGE']]);
|
$res = $config->setConfig($data, '默认图设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DEFAULT_IMAGE' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,9 +138,9 @@ class Config extends BaseModel
|
|||||||
public function getDefaultImg($site_id, $app_model = 'shop')
|
public function getDefaultImg($site_id, $app_model = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_model], ['config_key', '=', 'DEFAULT_IMAGE']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_model ], [ 'config_key', '=', 'DEFAULT_IMAGE' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'goods' => 'public/static/img/default_img/square.png',
|
'goods' => 'public/static/img/default_img/square.png',
|
||||||
'head' => 'public/static/img/default_img/head.png',
|
'head' => 'public/static/img/default_img/head.png',
|
||||||
'store' => 'public/static/img/default_img/store.png',
|
'store' => 'public/static/img/default_img/store.png',
|
||||||
@@ -151,14 +150,14 @@ class Config extends BaseModel
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($res['data']['value']['head'])) {
|
if (empty($res[ 'data' ][ 'value' ][ 'head' ])) {
|
||||||
$res['data']['value']['head'] = 'public/static/img/default_img/head.png';
|
$res[ 'data' ][ 'value' ][ 'head' ] = 'public/static/img/default_img/head.png';
|
||||||
}
|
}
|
||||||
if (empty($res['data']['value']['article'])) {
|
if (empty($res[ 'data' ][ 'value' ][ 'article' ])) {
|
||||||
$res['data']['value']['article'] = 'public/static/img/default_img/article.png';
|
$res[ 'data' ][ 'value' ][ 'article' ] = 'public/static/img/default_img/article.png';
|
||||||
}
|
}
|
||||||
if (empty($res['data']['value']['store'])) {
|
if (empty($res[ 'data' ][ 'value' ][ 'store' ])) {
|
||||||
$res['data']['value']['store'] = 'public/static/img/default_img/store.png';
|
$res[ 'data' ][ 'value' ][ 'store' ] = 'public/static/img/default_img/store.png';
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -174,7 +173,7 @@ class Config extends BaseModel
|
|||||||
public function setCopyright($data, $site_id = 1, $app_model = 'shop')
|
public function setCopyright($data, $site_id = 1, $app_model = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '版权设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_model], ['config_key', '=', 'COPYRIGHT']]);
|
$res = $config->setConfig($data, '版权设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_model ], [ 'config_key', '=', 'COPYRIGHT' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,16 +186,16 @@ class Config extends BaseModel
|
|||||||
public function getCopyright($site_id = 1, $app_module = 'shop')
|
public function getCopyright($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'COPYRIGHT']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'COPYRIGHT' ] ]);
|
||||||
|
|
||||||
$auth_info = cache('auth_info_copyright');
|
$auth_info = cache('auth_info_copyright');
|
||||||
if (empty($auth_info)) {
|
if (empty($auth_info)) {
|
||||||
$upgrade_model = new Upgrade();
|
$upgrade_model = new Upgrade();
|
||||||
$auth_info = $upgrade_model->authInfo();
|
$auth_info = $upgrade_model->authInfo();
|
||||||
cache('auth_info_copyright', $auth_info, ['expire' => 604800]);
|
cache('auth_info_copyright', $auth_info, [ 'expire' => 604800 ]);
|
||||||
}
|
}
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'logo' => '',
|
'logo' => '',
|
||||||
'company_name' => '',
|
'company_name' => '',
|
||||||
'copyright_link' => '',
|
'copyright_link' => '',
|
||||||
@@ -207,15 +206,16 @@ class Config extends BaseModel
|
|||||||
'market_supervision_url' => ''
|
'market_supervision_url' => ''
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
if (is_null($auth_info) || $auth_info['code'] != 0) {
|
if (is_null($auth_info) || $auth_info[ 'code' ] != 0) {
|
||||||
$res['data']['value']['logo'] = '';
|
$res[ 'data' ][ 'value' ][ 'logo' ] = '';
|
||||||
$res['data']['value']['company_name'] = '';
|
$res[ 'data' ][ 'value' ][ 'company_name' ] = '';
|
||||||
$res['data']['value']['copyright_link'] = '';
|
$res[ 'data' ][ 'value' ][ 'copyright_link' ] = '';
|
||||||
$res['data']['value']['copyright_desc'] = '';
|
$res[ 'data' ][ 'value' ][ 'copyright_desc' ] = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 检查是否授权
|
// 检查是否授权
|
||||||
$res['data']['value']['auth'] = true;
|
$res[ 'data' ][ 'value' ][ 'auth' ] = true;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ class Config extends BaseModel
|
|||||||
public function setAuth($data, $site_id = 1, $app_model = 'shop')
|
public function setAuth($data, $site_id = 1, $app_model = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '授权设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_model], ['config_key', '=', 'AUTH']]);
|
$res = $config->setConfig($data, '授权设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_model ], [ 'config_key', '=', 'AUTH' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,9 +240,9 @@ class Config extends BaseModel
|
|||||||
public function getAuth($site_id = 1, $app_module = 'shop')
|
public function getAuth($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'AUTH']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'AUTH' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'code' => '',
|
'code' => '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -259,7 +259,7 @@ class Config extends BaseModel
|
|||||||
public function setMapConfig($data, $site_id, $app_model = 'shop')
|
public function setMapConfig($data, $site_id, $app_model = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '地图设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_model], ['config_key', '=', 'MAP_CONFIG']]);
|
$res = $config->setConfig($data, '地图设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_model ], [ 'config_key', '=', 'MAP_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,16 +273,16 @@ class Config extends BaseModel
|
|||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'MAP_CONFIG']]);
|
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'MAP_CONFIG']]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'tencent_map_key' => '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE', //默认一个地图TB5BZ-FBRRX-2RJ4C-76SZY-TYQ3H-F4BFC
|
'tencent_map_key' => '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE',//默认一个地图TB5BZ-FBRRX-2RJ4C-76SZY-TYQ3H-F4BFC
|
||||||
'wap_is_open' => 1, // 手机端是否开启定位
|
'wap_is_open' => 1, // 手机端是否开启定位
|
||||||
'wap_valid_time' => 5 // 手机端定位有效期/分钟,过期后将重新获取定位信息,0为不过期
|
'wap_valid_time' => 5 // 手机端定位有效期/分钟,过期后将重新获取定位信息,0为不过期
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$res['data']['value']['wap_is_open'] = $res['data']['value']['wap_is_open'] ?? 1;
|
$res[ 'data' ][ 'value' ][ 'wap_is_open' ] = $res[ 'data' ][ 'value' ][ 'wap_is_open' ] ?? 1;
|
||||||
$res['data']['value']['wap_valid_time'] = $res['data']['value']['wap_valid_time'] ?? 5;
|
$res[ 'data' ][ 'value' ][ 'wap_valid_time' ] = $res[ 'data' ][ 'value' ][ 'wap_valid_time' ] ?? 5;
|
||||||
$res['data']['value']['tencent_map_key'] = '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE';
|
$res[ 'data' ][ 'value' ]['tencent_map_key'] = '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE';
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,19 +296,19 @@ class Config extends BaseModel
|
|||||||
public function seth5DomainName($data, $site_id = 1, $app_module = 'shop')
|
public function seth5DomainName($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$search = '/^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/';
|
$search = '/^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/';
|
||||||
if ($data['deploy_way'] == 'separate') {
|
if ($data[ 'deploy_way' ] == 'separate') {
|
||||||
if (!preg_match($search, $data['domain_name_h5'])) {
|
if (!preg_match($search, $data[ 'domain_name_h5' ])) {
|
||||||
return $this->error('', '请输入正确的域名地址');
|
return $this->error('', '请输入正确的域名地址');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 默认部署,更新店铺域名
|
// 默认部署,更新店铺域名
|
||||||
if ($data['deploy_way'] == 'default') {
|
if ($data[ 'deploy_way' ] == 'default') {
|
||||||
$this->setShopDomainConfig([
|
$this->setShopDomainConfig([
|
||||||
'domain_name' => __ROOT__
|
'domain_name' => __ROOT__
|
||||||
], $site_id);
|
], $site_id);
|
||||||
}
|
}
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, 'H5域名配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'H5_DOMAIN_NAME']]);
|
$res = $config->setConfig($data, 'H5域名配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'H5_DOMAIN_NAME' ] ]);
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -322,9 +322,9 @@ class Config extends BaseModel
|
|||||||
public function getH5DomainName($site_id = 1, $app_module = 'shop')
|
public function getH5DomainName($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'H5_DOMAIN_NAME']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'H5_DOMAIN_NAME' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'domain_name_h5' => __ROOT__ . '/h5',
|
'domain_name_h5' => __ROOT__ . '/h5',
|
||||||
'deploy_way' => 'default'
|
'deploy_way' => 'default'
|
||||||
];
|
];
|
||||||
@@ -342,7 +342,7 @@ class Config extends BaseModel
|
|||||||
public function setDomainJumpConfig($data, $site_id = 1, $app_module = 'shop')
|
public function setDomainJumpConfig($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '获取域名跳转配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DOMAIN_JUMP_CONFIG']]);
|
$res = $config->setConfig($data, '获取域名跳转配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DOMAIN_JUMP_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,12 +356,12 @@ class Config extends BaseModel
|
|||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([
|
$res = $config->getConfig([
|
||||||
['site_id', '=', $site_id],
|
[ 'site_id', '=', $site_id ],
|
||||||
['app_module', '=', $app_module],
|
[ 'app_module', '=', $app_module ],
|
||||||
['config_key', '=', 'DOMAIN_JUMP_CONFIG']
|
[ 'config_key', '=', 'DOMAIN_JUMP_CONFIG' ]
|
||||||
]);
|
]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'jump_type' => 3, // 1:用户前台,2:商家后台,3:引导页
|
'jump_type' => 3, // 1:用户前台,2:商家后台,3:引导页
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -378,19 +378,19 @@ class Config extends BaseModel
|
|||||||
public function setPcDomainName($data, $site_id = 1, $app_module = 'shop')
|
public function setPcDomainName($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$search = '/^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/';
|
$search = '/^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/';
|
||||||
if ($data['deploy_way'] == 'separate') {
|
if ($data[ 'deploy_way' ] == 'separate') {
|
||||||
if (!preg_match($search, $data['domain_name_pc'])) {
|
if (!preg_match($search, $data[ 'domain_name_pc' ])) {
|
||||||
return $this->error('', '请输入正确的域名地址');
|
return $this->error('', '请输入正确的域名地址');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 默认部署,更新店铺域名
|
// 默认部署,更新店铺域名
|
||||||
if ($data['deploy_way'] == 'default') {
|
if ($data[ 'deploy_way' ] == 'default') {
|
||||||
$this->setShopDomainConfig([
|
$this->setShopDomainConfig([
|
||||||
'domain_name' => __ROOT__
|
'domain_name' => __ROOT__
|
||||||
], $site_id);
|
], $site_id);
|
||||||
}
|
}
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, 'PC域名配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'PC_DOMAIN_NAME']]);
|
$res = $config->setConfig($data, 'PC域名配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'PC_DOMAIN_NAME' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,19 +403,19 @@ class Config extends BaseModel
|
|||||||
public function getPcDomainName($site_id = 1, $app_module = 'shop')
|
public function getPcDomainName($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'PC_DOMAIN_NAME']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'PC_DOMAIN_NAME' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'domain_name_pc' => __ROOT__ . '/web',
|
'domain_name_pc' => __ROOT__ . '/web',
|
||||||
'deploy_way' => 'default'
|
'deploy_way' => 'default'
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
if ($res['data']['value']['domain_name_pc'] == '' || empty($res['data']['value']['deploy_way']) || $res['data']['value']['deploy_way'] == 'default') {
|
if ($res[ 'data' ][ 'value' ][ 'domain_name_pc' ] == '' || empty($res[ 'data' ][ 'value' ][ 'deploy_way' ]) || $res[ 'data' ][ 'value' ][ 'deploy_way' ] == 'default') {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'domain_name_pc' => __ROOT__ . '/web'
|
'domain_name_pc' => __ROOT__ . '/web'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$res['data']['value']['deploy_way'] = $res['data']['value']['deploy_way'] ?? 'default';
|
$res[ 'data' ][ 'value' ][ 'deploy_way' ] = $res[ 'data' ][ 'value' ][ 'deploy_way' ] ?? 'default';
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -430,7 +430,7 @@ class Config extends BaseModel
|
|||||||
public function setHotSearchWords($data, $site_id, $app_module)
|
public function setHotSearchWords($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品热门搜索关键词', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG']]);
|
$res = $config->setConfig($data, '商品热门搜索关键词', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,9 +443,9 @@ class Config extends BaseModel
|
|||||||
public function getHotSearchWords($site_id, $app_module)
|
public function getHotSearchWords($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'words' => ''
|
'words' => ''
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,7 @@ class Config extends BaseModel
|
|||||||
public function setGuessYouLike($data, $site_id, $app_module)
|
public function setGuessYouLike($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品推荐', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG']]);
|
$res = $config->setConfig($data, '商品推荐', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,11 +475,11 @@ class Config extends BaseModel
|
|||||||
public function getGuessYouLike($site_id, $app_module)
|
public function getGuessYouLike($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'title' => '猜你喜欢',
|
'title' => '猜你喜欢',
|
||||||
'supportPage' => ['goods_detail', 'cart', 'collect', 'pay', 'order_detail', 'super_member', 'guafen', 'fenxiao_level'],
|
'supportPage' => [ 'goods_detail', 'cart', 'collect', 'pay', 'order_detail', 'super_member', 'guafen', 'fenxiao_level' ],
|
||||||
'sources' => 'sort',
|
'sources' => 'sort',
|
||||||
'goodsIds' => [],
|
'goodsIds' => [],
|
||||||
'fontWeight' => false,
|
'fontWeight' => false,
|
||||||
@@ -508,7 +508,7 @@ class Config extends BaseModel
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$res['data']['value']['nameLineMode'] = $res['data']['value']['nameLineMode'] ?? 'single'; // 商品名称,单行、多行展示
|
$res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,17 +522,17 @@ class Config extends BaseModel
|
|||||||
public function getDiyAdv($site_id, $app_module)
|
public function getDiyAdv($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_STARTADV']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_STARTADV' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])){
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'list' => [
|
'list' =>[
|
||||||
[
|
[
|
||||||
'title' => '启动广告',
|
'title'=>'启动广告',
|
||||||
'link' => [
|
'link'=>[
|
||||||
'name' => ''
|
'name'=>''
|
||||||
],
|
],
|
||||||
'iconType' => 'img',
|
'iconType'=>'img',
|
||||||
'imageUrl' => "public/static/ext/diyview/img/preview/advs_default.png"
|
'imageUrl'=>"public/static/ext/diyview/img/preview/advs_default.png"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'advtype' => 1,
|
'advtype' => 1,
|
||||||
@@ -552,7 +552,7 @@ class Config extends BaseModel
|
|||||||
public function setDiyAdv($data, $site_id, $app_module)
|
public function setDiyAdv($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '启动广告', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_STARTADV']]);
|
$res = $config->setConfig($data, '启动广告', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_STARTADV' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,14 +566,14 @@ class Config extends BaseModel
|
|||||||
public function getDiyVr($site_id, $app_module)
|
public function getDiyVr($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_VR']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_VR' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])){
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'title' => '工厂展示',
|
'title' => '工厂展示',
|
||||||
'url' => 'https://baidu.com',
|
'url' => 'https://baidu.com',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// $res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
|
// $res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +587,7 @@ class Config extends BaseModel
|
|||||||
public function setDiyVr($data, $site_id, $app_module)
|
public function setDiyVr($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, 'VR展示', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_VR']]);
|
$res = $config->setConfig($data, 'VR展示', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_VR' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,7 +602,7 @@ class Config extends BaseModel
|
|||||||
public function setGoodsListConfig($data, $site_id, $app_module)
|
public function setGoodsListConfig($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品列表配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_LIST_CONFIG']]);
|
$res = $config->setConfig($data, '商品列表配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_LIST_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,9 +615,9 @@ class Config extends BaseModel
|
|||||||
public function getGoodsListConfig($site_id, $app_module)
|
public function getGoodsListConfig($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_LIST_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_LIST_CONFIG' ] ]);
|
||||||
//数据格式化
|
//数据格式化
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$data = [
|
$data = [
|
||||||
'fontWeight' => false,
|
'fontWeight' => false,
|
||||||
'padding' => 10,
|
'padding' => 10,
|
||||||
@@ -644,9 +644,9 @@ class Config extends BaseModel
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
$res['data']['value'] = $data;
|
$res[ 'data' ][ 'value' ] = $data;
|
||||||
}
|
}
|
||||||
$res['data']['value']['nameLineMode'] = $res['data']['value']['nameLineMode'] ?? 'single'; // 商品名称,单行、多行展示
|
$res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,7 +660,7 @@ class Config extends BaseModel
|
|||||||
public function setDefaultSearchWords($data, $site_id, $app_module)
|
public function setDefaultSearchWords($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '默认搜索关键词', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG']]);
|
$res = $config->setConfig($data, '默认搜索关键词', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,9 +673,9 @@ class Config extends BaseModel
|
|||||||
public function getDefaultSearchWords($site_id, $app_module)
|
public function getDefaultSearchWords($site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'words' => '搜索 商品'
|
'words' => '搜索 商品'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -692,7 +692,7 @@ class Config extends BaseModel
|
|||||||
public function setGoodsSort($data, $site_id, $app_module)
|
public function setGoodsSort($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品默认排序方式', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_SORT_CONFIG']]);
|
$res = $config->setConfig($data, '商品默认排序方式', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_SORT_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,9 +705,9 @@ class Config extends BaseModel
|
|||||||
public function getGoodsSort($site_id, $app_module = 'shop')
|
public function getGoodsSort($site_id, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_SORT_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_SORT_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'type' => 'asc',
|
'type' => 'asc',
|
||||||
'default_value' => 100
|
'default_value' => 100
|
||||||
];
|
];
|
||||||
@@ -725,7 +725,7 @@ class Config extends BaseModel
|
|||||||
public function setCategoryConfig($data, $site_id = 1, $app_module = 'shop')
|
public function setCategoryConfig($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, 'PC端首页分类设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_CATEGORY_CONFIG']]);
|
$res = $config->setConfig($data, 'PC端首页分类设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_CATEGORY_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,9 +738,9 @@ class Config extends BaseModel
|
|||||||
public function getCategoryConfig($site_id = 1, $app_module = 'shop')
|
public function getCategoryConfig($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_CATEGORY_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_CATEGORY_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'category' => 1,
|
'category' => 1,
|
||||||
'img' => 1
|
'img' => 1
|
||||||
];
|
];
|
||||||
@@ -758,7 +758,7 @@ class Config extends BaseModel
|
|||||||
public function setGoodsDetailConfig($data, $site_id, $app_module = 'shop')
|
public function setGoodsDetailConfig($data, $site_id, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品详情配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DETAIL_CONFIG']]);
|
$res = $config->setConfig($data, '商品详情配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DETAIL_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,9 +771,9 @@ class Config extends BaseModel
|
|||||||
public function getGoodsDetailConfig($site_id, $app_module = 'shop')
|
public function getGoodsDetailConfig($site_id, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DETAIL_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DETAIL_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'nav_bar_switch' => 0, // 是否透明,0:不透明,1:透明
|
'nav_bar_switch' => 0, // 是否透明,0:不透明,1:透明
|
||||||
'introduction_color' => '#303133',
|
'introduction_color' => '#303133',
|
||||||
];
|
];
|
||||||
@@ -791,7 +791,7 @@ class Config extends BaseModel
|
|||||||
public function setShopDomainConfig($data, $site_id = 1, $app_module = 'shop')
|
public function setShopDomainConfig($data, $site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '店铺域名配置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_DOMAIN_CONFIG']]);
|
$res = $config->setConfig($data, '店铺域名配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_DOMAIN_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,12 +804,12 @@ class Config extends BaseModel
|
|||||||
public function getShopDomainConfig($site_id = 1, $app_module = 'shop')
|
public function getShopDomainConfig($site_id = 1, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_DOMAIN_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_DOMAIN_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'domain_name' => __ROOT__,
|
'domain_name' => __ROOT__,
|
||||||
];
|
];
|
||||||
$this->setShopDomainConfig($res['data']['value'], $site_id);
|
$this->setShopDomainConfig($res[ 'data' ][ 'value' ], $site_id);
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -817,11 +817,11 @@ class Config extends BaseModel
|
|||||||
{
|
{
|
||||||
$qq_map = new \app\model\map\QqMap(['key' => $tencent_map_key]);
|
$qq_map = new \app\model\map\QqMap(['key' => $tencent_map_key]);
|
||||||
$res = $qq_map->ipToDetail([
|
$res = $qq_map->ipToDetail([
|
||||||
'ip' => request()->ip() != '127.0.0.1' ? $_SERVER['REMOTE_ADDR'] : '',
|
'ip' => request()->ip() != '127.0.0.1' ? $_SERVER[ 'REMOTE_ADDR' ] : '',
|
||||||
]);
|
]);
|
||||||
if (!empty($res)) {
|
if (!empty($res)) {
|
||||||
if ($res['status'] != 0 && $type == 0) {
|
if ($res[ 'status' ] != 0 && $type == 0) {
|
||||||
$res['message'] = '腾讯地图配置错误,无法定位地址';
|
$res[ 'message' ] = '腾讯地图配置错误,无法定位地址';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
@@ -857,7 +857,7 @@ class Config extends BaseModel
|
|||||||
public function setGoodsNo($data, $site_id, $app_module)
|
public function setGoodsNo($data, $site_id, $app_module)
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->setConfig($data, '商品编码设置', 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_NO_CONFIG']]);
|
$res = $config->setConfig($data, '商品编码设置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_NO_CONFIG' ] ]);
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -870,9 +870,9 @@ class Config extends BaseModel
|
|||||||
public function getGoodsNo($site_id, $app_module = 'shop')
|
public function getGoodsNo($site_id, $app_module = 'shop')
|
||||||
{
|
{
|
||||||
$config = new ConfigModel();
|
$config = new ConfigModel();
|
||||||
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_NO_CONFIG']]);
|
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_NO_CONFIG' ] ]);
|
||||||
if (empty($res['data']['value'])) {
|
if (empty($res[ 'data' ][ 'value' ])) {
|
||||||
$res['data']['value'] = [
|
$res[ 'data' ][ 'value' ] = [
|
||||||
'uniqueness_switch' => 1,
|
'uniqueness_switch' => 1,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,9 +201,90 @@ class DiyViewLink extends BaseModel
|
|||||||
$link_list[ $k ][ 'child_list' ] = [];
|
$link_list[ $k ][ 'child_list' ] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PDF文件分类列表
|
||||||
|
foreach ($link_list as $k => $v) {
|
||||||
|
if (isset($v[ 'child_list' ])) {
|
||||||
|
foreach ($v[ 'child_list' ] as $ck => $cv) {
|
||||||
|
if ($cv[ 'name' ] == 'FILES_CATE_PAGE') {
|
||||||
|
$link_list[ $k ][ 'child_list' ][ $ck ][ 'child_list' ] = [ $this->getFllesCateGoryPageLinkList($params[ 'site_id' ])[ 'data' ] ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$link_list[ $k ][ 'child_list' ] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PDF文件列表
|
||||||
|
foreach ($link_list as $k => $v) {
|
||||||
|
if (isset($v[ 'child_list' ])) {
|
||||||
|
foreach ($v[ 'child_list' ] as $ck => $cv) {
|
||||||
|
if ($cv[ 'name' ] == 'FILES_LIST_PAGE') {
|
||||||
|
$link_list[ $k ][ 'child_list' ][ $ck ][ 'child_list' ] = [ $this->getFllesPageLinkList($params[ 'site_id' ])[ 'data' ] ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$link_list[ $k ][ 'child_list' ] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($link_list,true));
|
||||||
return $this->success($link_list);
|
return $this->success($link_list);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* 查询文章列表
|
||||||
|
* @param $site_id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFllesPageLinkList($site_id)
|
||||||
|
{
|
||||||
|
// $article_model = new ArticleModel();
|
||||||
|
// $condition = [ [ 'site_id', '=', $site_id ], [ 'status', '=', 1 ] ];
|
||||||
|
// $site_diy_view_list = $article_model->getArticleList($condition,'*', 'create_time desc', 100);
|
||||||
|
$files_list = model('files')->getList( [ [ 'site_id', '=', $site_id ] ]);
|
||||||
|
|
||||||
|
$link_mic = [
|
||||||
|
'name' => 'FILES_LIST',
|
||||||
|
'title' => '文件列表',
|
||||||
|
'parent' => 'FILES_LIST_PAGE',
|
||||||
|
'child_list' => []
|
||||||
|
];
|
||||||
|
foreach ($files_list as $page_k => $page_v) {
|
||||||
|
$link_mic[ 'child_list' ][] = [
|
||||||
|
'name' => 'FILES_'.$page_v[ 'files_id' ],
|
||||||
|
'title' => $page_v[ 'files_title' ],
|
||||||
|
'parent' => 'FILES_LIST',
|
||||||
|
'wap_url' => '/pages_tool/files/detail?files_id=' . $page_v[ 'files_id' ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success($link_mic);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 查询文件分类列表
|
||||||
|
* @param $site_id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFllesCateGoryPageLinkList($site_id)
|
||||||
|
{
|
||||||
|
$cate_gorylist = model('files_category')->getList( [ [ 'site_id', '=', $site_id ] ]);
|
||||||
|
$link_mic = [
|
||||||
|
'name' => 'FILESCATEGORY_LIST',
|
||||||
|
'title' => '文件分类',
|
||||||
|
'parent' => 'FILES_CATE_PAGE',
|
||||||
|
'child_list' => []
|
||||||
|
];
|
||||||
|
foreach ($cate_gorylist as $page_k => $page_v) {
|
||||||
|
$link_mic[ 'child_list' ][] = [
|
||||||
|
'name' => 'FILES_CATEGORY_'.$page_v[ 'id' ],
|
||||||
|
'title' => $page_v[ 'category_name' ],
|
||||||
|
'parent' => 'FILES_CATEGORY_LIST',
|
||||||
|
'wap_url' => '/pages_tool/files/list?category_id=' . $page_v[ 'id' ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $this->success($link_mic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* 查询文章分类列表
|
* 查询文章分类列表
|
||||||
* @param $site_id
|
* @param $site_id
|
||||||
* @return array
|
* @return array
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class Shop extends BasePlatform
|
|||||||
['user u','u.site_id = p.uniacid','left'],
|
['user u','u.site_id = p.uniacid','left'],
|
||||||
];
|
];
|
||||||
$list = $Comm_model->getPageList('platform_shop',$condition, $page, $page_size, $order,'p.*,s.site_realname,s.end_time,s.site_tel,s.logo,u.status as ustatus,u.uid','p',$join);
|
$list = $Comm_model->getPageList('platform_shop',$condition, $page, $page_size, $order,'p.*,s.site_realname,s.end_time,s.site_tel,s.logo,u.status as ustatus,u.uid','p',$join);
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export(Db::getLastSql(),true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export(Db::getLastSql(),true));
|
||||||
foreach($list['data']['list'] as &$row){
|
foreach($list['data']['list'] as &$row){
|
||||||
$row['create_time'] = date('Y-m-d H:i:s',$row['create_time']);
|
$row['create_time'] = date('Y-m-d H:i:s',$row['create_time']);
|
||||||
$row['end_time'] = date('Y-m-d H:i:s',$row['end_time']);
|
$row['end_time'] = date('Y-m-d H:i:s',$row['end_time']);
|
||||||
|
|||||||
@@ -123,11 +123,12 @@ class BaseShop extends Controller
|
|||||||
$config_view = Config::get('view');
|
$config_view = Config::get('view');
|
||||||
$config_view[ 'tpl_replace_string' ] = array_merge($config_view[ 'tpl_replace_string' ], $this->replace);
|
$config_view[ 'tpl_replace_string' ] = array_merge($config_view[ 'tpl_replace_string' ], $this->replace);
|
||||||
Config::set($config_view, 'view');
|
Config::set($config_view, 'view');
|
||||||
// 其他操作
|
|
||||||
if (!request()->isAjax()) {
|
if (!request()->isAjax()) {
|
||||||
$this->initBaseInfo();
|
$this->initBaseInfo();
|
||||||
$this->loadTemplate();
|
$this->loadTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,6 +197,14 @@ class BaseShop extends Controller
|
|||||||
$where[] = ['id','<>',2498];
|
$where[] = ['id','<>',2498];
|
||||||
$where1[] = ['id','<>',2498];
|
$where1[] = ['id','<>',2498];
|
||||||
}
|
}
|
||||||
|
if($this->site_id != 2230){
|
||||||
|
$where[] = ['id','<>',2651];
|
||||||
|
$where1[] = ['id','<>',2651];
|
||||||
|
}
|
||||||
|
if($this->site_id != 2558){
|
||||||
|
$where[] = ['id','<>',2657];
|
||||||
|
$where1[] = ['id','<>',2657];
|
||||||
|
}
|
||||||
if ($this->user_info[ 'is_admin' ] || $this->group_info[ 'is_system' ] == 1) {
|
if ($this->user_info[ 'is_admin' ] || $this->group_info[ 'is_system' ] == 1) {
|
||||||
$menus = $menu_model->getMenuList($where, $field, 'level asc,sort asc');
|
$menus = $menu_model->getMenuList($where, $field, 'level asc,sort asc');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1907,6 +1907,7 @@ class Goods extends BaseShop
|
|||||||
if ($data[ 'code' ] < 0) {
|
if ($data[ 'code' ] < 0) {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = ( new GoodsImport() )->importGoods($data[ 'data' ], $this->site_id, $type);
|
$result = ( new GoodsImport() )->importGoods($data[ 'data' ], $this->site_id, $type);
|
||||||
return $result;
|
return $result;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class Index extends BaseShop
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->assign('shop_status', 1);
|
$this->assign('shop_status', 1);
|
||||||
|
|
||||||
$this->handlePromotion();
|
$this->handlePromotion();
|
||||||
|
|||||||
@@ -25,6 +25,62 @@ use addon\coupon\model\Coupon as CouponModel;
|
|||||||
*/
|
*/
|
||||||
class Member extends BaseShop
|
class Member extends BaseShop
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function business(){
|
||||||
|
|
||||||
|
$member = new MemberModel();
|
||||||
|
if (request()->isJson()) {
|
||||||
|
$page = input('page', 1);
|
||||||
|
$page_size = input('page_size', PAGE_LIST_ROWS);
|
||||||
|
$search_text = input('search_keys', '');
|
||||||
|
|
||||||
|
$condition = [];
|
||||||
|
if (!empty($search_text)) {
|
||||||
|
$condition[] = [ 'name', 'like', '%' . $search_text . '%' ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $member->getBusinessPageList($condition, $page, $page_size,'id desc');
|
||||||
|
} else {
|
||||||
|
return $this->fetch('member/business');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加/编辑
|
||||||
|
*/
|
||||||
|
public function businesspost()
|
||||||
|
{
|
||||||
|
$member = new MemberModel();
|
||||||
|
if (request()->isJson()) {
|
||||||
|
$id = input('id', 0);
|
||||||
|
$data = [
|
||||||
|
'realname' => input('realname', ''),
|
||||||
|
];
|
||||||
|
if($id>0){
|
||||||
|
$res = model('business')->update($data,['id'=>$id]);
|
||||||
|
}else{
|
||||||
|
$res = model('business')->add($data);
|
||||||
|
}
|
||||||
|
return $member->success($res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
public function businessdelete()
|
||||||
|
{
|
||||||
|
$member = new MemberModel();
|
||||||
|
if (request()->isJson()) {
|
||||||
|
$id = input('id', 0);
|
||||||
|
$result = model('business')->delete([['id', '=', $id]]);
|
||||||
|
return $member->success($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* 会员概况
|
* 会员概况
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class Message extends BaseShop
|
|||||||
|
|
||||||
$edit_data = $edit_data_result['data'][ 0 ];
|
$edit_data = $edit_data_result['data'][ 0 ];
|
||||||
$edit_url = $edit_data['shop_url'];
|
$edit_url = $edit_data['shop_url'];
|
||||||
file_put_contents(__DIR__ . '/debug.txt', var_export($edit_url,true));
|
// file_put_contents(__DIR__ . '/debug.txt', var_export($edit_url,true));
|
||||||
$this->redirect(addon_url($edit_url, [ 'keywords' => $keywords ]));
|
$this->redirect(addon_url($edit_url, [ 'keywords' => $keywords ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class Order extends BaseShop
|
|||||||
a.invoice_type,a.invoice_title,a.taxpayer_number,a.invoice_rate,a.invoice_content,a.invoice_delivery_money,a.invoice_full_address,a.is_tax_invoice,a.invoice_email,a.invoice_title_type,a.is_fenxiao,
|
a.invoice_type,a.invoice_title,a.taxpayer_number,a.invoice_rate,a.invoice_content,a.invoice_delivery_money,a.invoice_full_address,a.is_tax_invoice,a.invoice_email,a.invoice_title_type,a.is_fenxiao,
|
||||||
a.point_money,a.member_card_money,a.member_card_order,a.invoice_status,a.invoice_remark,a.invoice_code,a.invoice_image,a.invoice_time,a.predict_delivery_time,a.is_video_number,a.close_cause,
|
a.point_money,a.member_card_money,a.member_card_order,a.invoice_status,a.invoice_remark,a.invoice_code,a.invoice_image,a.invoice_time,a.predict_delivery_time,a.is_video_number,a.close_cause,
|
||||||
a.cashier_order_type,a.cashier_sell_time,a.cashier_operator_id,a.cashier_operator_name,a.balance,a.total_balance,a.store_id,a.reduction,a.round_money,a.order_scene,
|
a.cashier_order_type,a.cashier_sell_time,a.cashier_operator_id,a.cashier_operator_name,a.balance,a.total_balance,a.store_id,a.reduction,a.round_money,a.order_scene,
|
||||||
a.store_commission_rate,a.store_commission,s.store_name,a.merch_id';
|
a.store_commission_rate,a.store_commission,s.store_name,a.merch_id,a.business';
|
||||||
$order_common_model = new OrderCommonModel();
|
$order_common_model = new OrderCommonModel();
|
||||||
if (request()->isJson()) {
|
if (request()->isJson()) {
|
||||||
$page_index = input('page', 1);
|
$page_index = input('page', 1);
|
||||||
|
|||||||