16 Commits

Author SHA1 Message Date
e2d6a02860 chore: .well-known 不作为版本控制的文件 2025-11-28 14:36:14 +08:00
1f8504f002 fix(license): 发现源码属于上海牛之云网络科技有限公司的NiuShop开源商城。 2025-11-25 18:05:00 +08:00
9ff2492962 fix(src): 解决GROUP BY问题:只查询主键ID,避免ONLY_FULL_GROUP_BY错误 2025-11-25 11:32:31 +08:00
88355a3f48 fix(src): memberrecharge js脚本报错,找不到Order对象的定义 2025-11-24 16:57:37 +08:00
3effc03a19 chore: 注释掉file_put_contents 2025-11-24 16:04:44 +08:00
be65996398 chore(db): 数据库获得完整的初始化脚本,用来部署新的服务器 2025-11-24 16:04:01 +08:00
c58bf929b1 chore(src): 引入vue2系列最终版本,为后面稳定升级做准备 2025-11-22 16:29:40 +08:00
ec1b93e473 chore: 注释掉 file_put_contents(__DIR__ . '/debug.txt', 这样的调试方式 2025-11-22 16:22:39 +08:00
8a78cea36d chore(addon): 同步华为云第1台服务器上的addon代码 2025-11-22 16:14:32 +08:00
96f0d9b602 chore(docs): 增加关于CLodop的安装及使用说明 2025-11-22 16:08:25 +08:00
ee884a3737 chore: 同步华为云第1台服务器上代码,public下所有静态资源 2025-11-22 16:01:53 +08:00
326dbb1c3c chore: 同步华为云第1台服务器上的关于Menu针对特殊用户限制的代码 2025-11-22 15:56:34 +08:00
f03dbbfc60 chore: src/app 目录与华为云第一台服务器上的代码做第一次比较合并 2025-11-22 15:00:41 +08:00
c1170aafa8 chore: docker 配置中 docker\php\supervisord.conf
更新指定环境变量:environment=APP_ENV=local
2025-11-22 11:50:36 +08:00
198871d3c9 chore: 解决通过 think 执行命令, 无法使用.env 扩展文件的问题,例如:开发环境,生产环境等的配置 2025-11-22 11:47:03 +08:00
caaf85290f chore: 提供中文字符编码解决方案 2025-11-22 11:46:14 +08:00
99 changed files with 29362 additions and 13360 deletions

View File

@@ -61,7 +61,7 @@ services:
- "${NGINX_PORT:-80}:80"
- "${NGINX_SSL_PORT:-443}:443"
volumes:
- ./src:/var/www/html:ro
- ./src:/var/www/html:rw
# 更新下载源列表以加速apt-get
- ./docker/debian/sources.list:/etc/apt/sources.list:ro
# 创建临时目录

View File

@@ -19,6 +19,7 @@ stderr_logfile_maxbytes=0
[program:think-cron]
command=php /var/www/html/think cron:schedule
environment=APP_ENV=local
autostart=true
autorestart=true
startretries=5

View File

@@ -0,0 +1,212 @@
# PHP 中文字符编码解决方案
## 🎯 问题描述
在使用 `json_encode()` 处理包含中文字符的数据时,默认会将中文字符转换为 Unicode 编码:
```php
// ❌ 默认行为 - 中文转为Unicode
$data = ['message' => '请检查计划任务配置'];
echo json_encode($data);
// 输出:{"message":"\u8bf7\u68c0\u67e5\u8ba1\u5212\u4efb\u52a1\u914d\u7f6e"}
```
这在日志文件中查看很不方便,影响调试效率。
## 🛠️ 解决方案对比
### 方案一:`JSON_UNESCAPED_UNICODE` 标志 ⭐⭐⭐⭐⭐⭐
```php
// ✅ 推荐方案 - 保持中文原样
$data = ['message' => '请检查计划任务配置'];
echo json_encode($data, JSON_UNESCAPED_UNICODE);
// 输出:{"message":"请检查计划任务配置"}
```
**优点:**
- ✅ 中文完全可读
- ✅ 保持JSON格式
- ✅ 兼容性好
- ✅ 性能优秀
**使用场景:**
- 日志记录
- API响应
- 配置文件
- 调试输出
### 方案二:`var_export()` 函数 ⭐⭐⭐
```php
// ✅ 完全避免Unicode转义
$data = ['message' => '请检查计划任务配置'];
echo var_export($data, true);
// 输出array (
// 'message' => '请检查计划任务配置',
// )
```
**优点:**
- ✅ 完全可读
- ✅ 数组结构清晰
- ✅ 无需额外参数
**缺点:**
- ❌ 不是标准JSON格式
- ❌ 输出较冗长
**使用场景:**
- 开发调试
- 临时日志
- 数组检查
### 方案三:`print_r()` + 捕获输出 ⭐⭐
```php
// ✅ 可读性好的数组输出
$data = ['message' => '请检查计划任务配置'];
ob_start();
print_r($data);
$result = ob_get_clean();
```
**优点:**
- ✅ 格式美观
- ✅ 易于阅读
**缺点:**
- ❌ 需要输出缓冲
- ❌ 性能较差
### 方案四:自定义序列化函数 ⭐⭐⭐
```php
function serializeArray($data) {
if (!is_array($data)) return $data;
$result = [];
foreach ($data as $key => $value) {
if (is_array($value)) {
$result[$key] = serializeArray($value);
} else {
$result[$key] = $value;
}
}
return $result;
}
```
## 🎯 最佳实践组合
### 在 Cron 类中的实现
```php
class Cron extends BaseModel
{
/**
* 格式化数据为日志友好的字符串(保持中文可读性)
*/
private static function formatForLog($data): string
{
if (is_array($data) || is_object($data)) {
// JSON_UNESCAPED_UNICODE 保持中文可读性
// JSON_PRETTY_PRINT 增加格式化
// JSON_UNESCAPED_SLASHES 避免斜杠转义
return json_encode($data,
JSON_UNESCAPED_UNICODE |
JSON_PRETTY_PRINT |
JSON_UNESCAPED_SLASHES
);
}
return (string) $data;
}
/**
* 完全避免Unicode转义的格式化
*/
private static function exportForLog($data): string
{
if (is_array($data) || is_object($data)) {
return var_export($data, true);
}
return (string) $data;
}
}
```
### 使用示例
```php
// 日志记录 - 使用 formatForLog
$detail = [
'error' => $error,
'remark' => $remark,
'suggestion' => ScheduleDict::getSuggestion($cronType)
];
log_write('异常信息:' . self::formatForLog($detail), 'warning');
// 调试输出 - 使用 exportForLog
$debugData = ['config' => $config, 'status' => $status];
echo self::exportForLog($debugData);
```
## 🔧 环境配置
### 确保 PHP 版本支持
```php
// PHP 5.4+ 基本支持
json_encode($data, JSON_UNESCAPED_UNICODE);
// PHP 5.3+ 需要 polyfill
if (!defined('JSON_UNESCAPED_UNICODE')) {
define('JSON_UNESCAPED_UNICODE', 256);
}
```
### 文件编码设置
```php
// 确保文件本身是 UTF-8 编码
header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('UTF-8');
```
## 📊 性能对比
| 方法 | 执行时间 | 内存使用 | 可读性 | JSON兼容 |
|------|----------|----------|---------|-----------|
| `json_encode()` | 快 | 低 | ⭐⭐⭐⭐⭐ | ✅ |
| `var_export()` | 中 | 中 | ⭐⭐⭐⭐ | ❌ |
| `print_r()` | 慢 | 高 | ⭐⭐⭐⭐ | ❌ |
| 自定义序列化 | 慢 | 高 | ⭐⭐ | ❌ |
## 🎉 推荐配置
### 生产环境(推荐)
```php
// 使用 JSON_UNESCAPED_UNICODE 保持中文可读性
json_encode($data, JSON_UNESCAPED_UNICODE);
```
### 开发环境
```php
// 使用格式化JSON增强可读性
json_encode($data,
JSON_UNESCAPED_UNICODE |
JSON_PRETTY_PRINT |
JSON_UNESCAPED_SLASHES
);
```
### 调试模式
```php
// 使用 var_export 获得最佳可读性
var_export($data, true);
```
---
**总结:** 对于您的需求,使用 `JSON_UNESCAPED_UNICODE` 标志是最佳选择既保持了JSON格式的标准性又确保了中文字符的可读性。

310
docs/CRON_ENV_SETUP.md Normal file
View File

@@ -0,0 +1,310 @@
# Cron 任务环境变量配置指南
## 🎯 问题:如何为 `nohup php think cron:schedule` 指定 `.env` 文件
## ✅ 解决方案
**最重要的部分**
我们修改了项目目录下的 `think` 文件的内容,增加了读取环境变量的代码
```php
#!/usr/bin/env php
<?php
namespace think;
// 命令行入口文件
// 加载基础文件
require __DIR__ . '/vendor/autoload.php';
// 创建应用程序
$app = new App();
// 您的代码使用APP_ENV
$appEnv = getenv('APP_ENV') ?: '';
if ($appEnv) {
$envFile = __DIR__ . '/.env.' . $appEnv;
if (is_file($envFile)) {
$app->env->load($envFile);
}
}
// 应用初始化
$app->console->run();
```
### 方案一:使用环境变量(推荐)
```bash
# 1. 临时设置环境变量(当前会话有效)
export THINK_ENV=production
nohup php think cron:schedule > /dev/null 2>&1 &
# 2. 永久设置环境变量(写入 ~/.bashrc
echo 'export THINK_ENV=production' >> ~/.bashrc
source ~/.bashrc
nohup php think cron:schedule > /dev/null 2>&1 &
# 3. 直接传递环境变量
THINK_ENV=production nohup php think cron:schedule > /dev/null 2>&1 &
```
### 方案二:指定不同的 .env 文件
```bash
# 1. 复制环境配置文件
cp .env .env.production
# 编辑 .env.production 修改相应配置
# 2. 使用 APP_ENV 指定环境
APP_ENV=production nohup php think cron:schedule > /dev/null 2>&1 &
# 3. 或者在运行时指定
php think cron:schedule --env=production
```
### 方案三:自定义启动脚本(最佳实践)
创建专用启动脚本 `start_cron.sh`
```bash
#!/bin/bash
# 设置环境变量
export THINK_ENV=${1:-production}
# 设置工作目录
cd /path/to/your/project
# 日志文件路径
LOG_FILE="/var/log/cron_${THINK_ENV}.log"
# 启动 cron 任务
echo "Starting cron with environment: $THINK_ENV"
nohup php think cron:schedule > $LOG_FILE 2>&1 &
# 记录进程ID
echo $! > /var/run/cron_${THINK_ENV}.pid
echo "Cron started with PID: $(cat /var/run/cron_${THINK_ENV}.pid)"
```
使用方法:
```bash
chmod +x start_cron.sh
# 启动生产环境 cron
./start_cron.sh production
# 启动开发环境 cron
./start_cron.sh development
```
## 🔧 ThinkPHP 6.x 环境变量加载机制
### ThinkPHP 自动加载顺序:
1. **服务器环境变量**: `$_SERVER['APP_ENV']`
2. **系统环境变量**: `getenv('APP_ENV')`
3. **.env 文件**: 根据环境变量加载对应的 `.env.*` 文件
### 支持的环境变量:
| 变量名 | 作用 | 示例 |
|--------|------|-------|
| `APP_ENV` | 指定运行环境 | `production` |
| `THINK_ENV` | ThinkPHP 6.x 环境标识 | `production` |
| `ENV_PATH` | 自定义 .env 文件路径 | `/custom/path/.env` |
## 📁 环境配置文件结构
```
project/
├── .env # 默认配置
├── .env.development # 开发环境
├── .env.testing # 测试环境
├── .env.staging # 预发布环境
└── .env.production # 生产环境
```
## 🚀 实际使用示例
### Docker 环境中的使用
```dockerfile
# Dockerfile 中设置环境变量
ENV THINK_ENV=production
# 或者在 docker-compose.yml 中
environment:
- THINK_ENV=production
- MYSQL_HOST=mysql
- MYSQL_PORT=3306
```
### Supervisor 配置
```ini
[program:cron-production]
command=/usr/bin/php /var/www/html/think cron:schedule
environment=THINK_ENV=production
directory=/var/www/html
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/log/supervisor/cron-production.log
stderr_logfile=/var/log/supervisor/cron-production-error.log
[program:cron-development]
command=/usr/bin/php /var/www/html/think cron:schedule
environment=THINK_ENV=development
directory=/var/www/html
autostart=false
autorestart=true
user=www-data
stdout_logfile=/var/log/supervisor/cron-development.log
stderr_logfile=/var/log/supervisor/cron-development-error.log
```
### 系统服务配置
```bash
# 创建 systemd 服务文件
sudo tee /etc/systemd/system/think-cron.service > /dev/null <<EOF
[Unit]
Description=ThinkPHP Cron Scheduler
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/html
Environment=THINK_ENV=production
ExecStart=/usr/bin/php /var/www/html/think cron:schedule
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# 启用并启动服务
sudo systemctl enable think-cron
sudo systemctl start think-cron
```
## 🔍 验证配置
### 检查当前环境
```bash
# 1. 在 cron 任务中添加日志
php think cron:schedule --verbose
# 2. 检查环境变量
php -r "echo 'APP_ENV: ' . getenv('APP_ENV') . PHP_EOL;"
php -r "echo 'THINK_ENV: ' . getenv('THINK_ENV') . PHP_EOL;"
# 3. 检查 ThinkPHP 加载的配置
php think config:get app.env
```
### 测试不同环境
```bash
# 测试生产环境
APP_ENV=production php think cron:schedule --verbose
# 测试开发环境
APP_ENV=development php think cron:schedule --verbose
# 使用指定配置文件
THINK_ENV=staging php think cron:schedule --verbose
```
## 📝 日志和监控
### 日志配置
```bash
# 按环境分离日志
nohup php think cron:schedule > logs/cron_${APP_ENV:-default}.log 2>&1 &
# 带时间戳的日志
nohup php think cron:schedule > logs/cron_$(date +%Y%m%d).log 2>&1 &
```
### 进程监控
```bash
# 检查 cron 进程
ps aux | grep "think cron:schedule" | grep -v grep
# 使用 pgrep 查找进程ID
pgrep -f "think cron:schedule"
# 监控脚本
#!/bin/bash
while true; do
if ! pgrep -f "think cron:schedule"; then
echo "$(date): Cron process died, restarting..."
nohup php think cron:schedule > logs/cron.log 2>&1 &
fi
sleep 30
done
```
## 🎯 推荐配置
### 生产环境最佳实践
```bash
# 1. 使用环境变量指定配置
export APP_ENV=production
# 2. 设置适当的日志级别
nohup php think cron:schedule --quiet > /var/log/cron.log 2>&1 &
# 3. 定期检查进程状态
*/5 * * * * * /usr/bin/pgrep -f "think cron:schedule" || /usr/bin/nohup /usr/bin/php /var/www/html/think cron:schedule > /var/log/cron.log 2>&1 &
```
### 开发环境配置
```bash
# 1. 使用开发环境配置
export APP_ENV=development
# 2. 显示详细输出用于调试
nohup php think cron:schedule > /dev/null 2>&1 &
# 3. 实时查看日志
tail -f logs/cron_dev.log
```
---
### 本地开发环境配置
```bash
# 1. 使用开发环境配置
export APP_ENV=local
# 2. 显示详细输出用于调试
nohup php think cron:schedule > /dev/null 2>&1 &
# 3. 实时查看日志
tail -f logs/cron_dev.log
```
## ✅ 总结
**答案:是的,可以为 `nohup php think cron:schedule` 指定 `.env` 文件!**
**推荐方法:**
1. 使用 `APP_ENV=production` 环境变量
2. 创建对应的 `.env.production` 文件
3. 使用自定义启动脚本管理不同环境
这样可以让同一套代码在不同环境中使用不同的数据库配置、缓存配置等。

670
docs/common/CLodop.md Normal file
View 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打印难题的优秀方案特别适合需要精确控制打印格式的企业级应用

View 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, '');
```

File diff suppressed because one or more lines are too long

27
docs/diy/RADEME.md Normal file
View 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)
)
```

View File

@@ -1 +0,0 @@
HUIqMBxOaiPqppGTd9WxmjJwFwX3x-hpbnI1xujpUW4.m7oE98dVL-9XQE2gAJ9VpnsbTfOJ2csnVDIzFqe9osw

View File

@@ -1 +0,0 @@
39aLknx0mLrzjinZRvjc5pYAXUkRq0eo

201
src/LICENSE Normal file
View 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
View File

@@ -0,0 +1,144 @@
![输入图片说明](https://images.gitee.com/uploads/images/2020/1130/170320_60fa7937_6569472.png "gitee.png")
### 产品介绍
### 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>
![输入图片说明](https://images.gitee.com/uploads/images/2020/0731/095424_ac477fe3_6569472.png "fuwuqi.png")
### 商城特色:
强大的营销功能模块,丰富的行业模板和装修组件,快速搭建最适合自己的电商平台,轻松获客、裂变。开启电商运营之路。
1. &nbsp;<img src="https://images.gitee.com/uploads/images/2020/0724/121556_a96bd648_6569472.png"/>&nbsp;&nbsp;ThinkPhp6 + LayUi + ElementUi,学习维护成本低<br/>
2. &nbsp;<img src="https://images.gitee.com/uploads/images/2020/0724/121615_f801f981_6569472.png"/>&nbsp;&nbsp;前端由UNI-APP框架编写支持多端易于维护<br/>
3. &nbsp;<img src="https://images.gitee.com/uploads/images/2020/0724/121635_e51987c4_6569472.png"/>&nbsp;&nbsp;钩子 + 插件,组件化开发,可复用,开发便捷<br/>
4. &nbsp;<img src="https://images.gitee.com/uploads/images/2020/0724/121645_df103f55_6569472.png"/>&nbsp;&nbsp;标准API接口前后端分离二次开发更方便<br/>
5. &nbsp;<img src="https://images.gitee.com/uploads/images/2020/0724/121708_74c55984_6569472.png"/>&nbsp;&nbsp;代码全部开源,方便企业扩展自身业务需求
### 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>
### 体验演示二维码
![输入图片说明](https://images.gitee.com/uploads/images/2020/1204/122100_d7469b38_6569472.png "微信图片_20201204121838.png")
#### :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.在线一键安装部署,自动检测系统环境一键安装,省时省力快捷部署;
### 系统功能
![输入图片说明](https://images.gitee.com/uploads/images/2020/0728/121652_92526e64_6569472.png "新增模板 拷贝.png")
### 页面展示
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/111329_22be9395_6569472.png "页面.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115734_9722c3b5_6569472.png "QQ图片20200725114407.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115756_68fd9140_6569472.png "QQ图片20200725114501.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115806_3e7d7f5e_6569472.png "QQ图片20200725114536.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115857_dd2d4a9f_6569472.png "QQ图片20200725114608.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115918_fb9521c8_6569472.png "QQ图片20200725114633.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115931_8271c952_6569472.png "QQ图片20200725114915.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/115945_bc1cf15f_6569472.png "QQ图片20200725114915.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120006_8e2f928c_6569472.png "QQ图片20200725115009.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120032_91c3a07e_6569472.png "QQ图片20200725115036.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120047_5038561c_6569472.png "QQ图片20200725115145.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120057_33e0f799_6569472.png "QQ图片20200725115230.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120113_560de733_6569472.png "QQ图片20200725115258.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120124_76d33659_6569472.png "QQ图片20200725115325.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120133_aa4fd7d6_6569472.png "QQ图片20200725114536.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120147_36252bb9_6569472.png "QQ图片20200725115348.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120201_6ae4c750_6569472.png "QQ图片20200725115409.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120211_d84435a6_6569472.png "QQ图片20200725115430.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120225_82060219_6569472.png "QQ图片20200725115452.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120240_8a9bb074_6569472.png "QQ图片20200725115545.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120256_d3e3cba4_6569472.png "QQ图片20200725115616.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120311_81c2f1d9_6569472.png "QQ图片20200725115659.png")
### 合作伙伴
![输入图片说明](https://images.gitee.com/uploads/images/2020/0725/120430_ab7fff0d_6569472.png "画板 1 拷贝 3(4).png")
### 版权信息
版权所有Copyright © 2015-2020 NiuShop开源商城&nbsp;版权所有
All rights reserved。
上海牛之云网络科技有限公司&nbsp;提供技术支持

View File

@@ -253,7 +253,7 @@ class Enterprise extends BaseModel
*/
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);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {

View File

@@ -381,33 +381,40 @@ class FenxiaoOrder extends BaseModel
*/
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';
$list = model('fenxiao_order')->pageList($condition, $field, $order, $page, $page_size, 'fo', [], 'order_id');
// 解决GROUP BY问题只查询主键ID避免ONLY_FULL_GROUP_BY错误
$field = 'DISTINCT fo.order_id';
$list = model('fenxiao_order')->pageList($condition, $field, $order, $page, $page_size, 'fo', [], 'fo.order_id');
if (!empty($list[ 'list' ])) {
$order_id_arr = [];
foreach ($list['list'] as $k => $v)
{
$order_id_arr[] = $v['order_id'];
}
if (!empty($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) {
foreach ($order_list as $k_order => $v_order)
{
if($item['order_id'] == $v_order['order_id'])
{
$list[ 'list' ][ $k ] = array_merge($list[ 'list' ][ $k ], $v_order);
}
}
$list[ 'list' ][ $k ][ 'order_goods' ] = [];
foreach ($order_goods_list as $k_order_goods => $v_order_goods)
{
if($item['order_id'] == $v_order_goods['order_id'])
{
$list[ 'list' ][ $k ][ 'order_goods' ][] = $v_order_goods;
}
// 重新查询完整的分销订单数据
$fenxiao_orders = model('fenxiao_order')->getList([ [ 'fo.order_id', 'in', $order_ids ] ],
'fo.order_id, fo.order_no, fo.site_name, fo.member_name, fo.create_time, fo.is_settlement, fo.fenxiao_order_id',
'', 'fo');
// 重新组织数据
$new_list = [];
foreach ($fenxiao_orders as $fenxiao_order) {
$order_list = model('order')->getInfo([ [ 'order_id', '=', $fenxiao_order['order_id'] ] ],
'name,full_address,mobile,order_status_name');
$order_goods_list = model('fenxiao_order')->getList([ [ 'order_id', '=', $fenxiao_order['order_id'] ] ]);
// 合并数据
$new_item = array_merge($fenxiao_order, [
'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);

View File

@@ -44,7 +44,7 @@ class Poster extends BaseModel
[
'action' => 'imageCopy', // 背景图
'data' => [
'upload/poster/bg/fenxiao_3.png',
'upload/poster/bg/fenxiao_2.png',
0,
0,
720,
@@ -125,18 +125,18 @@ class Poster extends BaseModel
1
]
],
// [
// 'action' => 'imageText', // 写入分享语
// 'data' => [
// $params[ 'template_json' ][ 'share_content' ],
// $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' ]),
// $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_width' ] * 2,
// 1
// ]
// ],
[
'action' => 'imageText', // 写入分享语
'data' => [
$params[ 'template_json' ][ 'share_content' ],
$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' ]),
$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_width' ] * 2,
1
]
],
[
'action' => 'imageCopy', // 写入用户头像
'data' => [
@@ -179,7 +179,7 @@ class Poster extends BaseModel
$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) {
$upload = new Upload($site_id);
$cloud_res = $upload->fileCloud($res[ 'data' ][ 'path' ]);

View File

@@ -49,14 +49,14 @@ class PosterTemplate extends BaseModel
'nickname_top' => 515,
'nickname_left' => 20,
//分享语
// 'share_content' => '邀您一起分享赚佣金',
// 'share_content_is_show' => 1,
// 'share_content_font_size' => 14,
// 'share_content_color' => '#8D8D8D',
// 'share_content_width' => 130,
// 'share_content_height' => 30,
// 'share_content_top' => 550,
// 'share_content_left' => 20,
'share_content' => '邀您一起分享赚佣金',
'share_content_is_show' => 1,
'share_content_font_size' => 14,
'share_content_color' => '#8D8D8D',
'share_content_width' => 130,
'share_content_height' => 30,
'share_content_top' => 550,
'share_content_left' => 20,
]
];

View File

@@ -54,7 +54,7 @@ class Form extends BaseApi
['form_type', '=', 'custom' ]
];
$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'])) {
$data['data']['json_data'] = json_decode($data['data']['json_data'], true);
// $data['data']['title'] = model('form')->getValue(['id'=>$form_id]);

View File

@@ -7,16 +7,12 @@
.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-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-table .form-data-wrap {max-height: 50px;overflow: hidden}
.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 + .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>
@@ -211,7 +207,7 @@ layui.use(['form', 'laydate', 'laytpl'], function() {
laytpl($('#formData').html()).render(data, function(string){
layer.open({
title: '查看信息',
area: ["600px","800px"],
area: "400px",
type: 1,
content: string,
btn: ['确认']

View File

@@ -97,7 +97,7 @@
</div>
</div>
</script>
<!-- <script src="MEMBERRECHARGE_JS/order_list.js?v={$version}"></script> -->
<script src="MEMBERRECHARGE_JS/order_list.js?v={$version}"></script>
<script>
var form,laypage,element,laydate;
var is_refresh = false;

View File

@@ -22,7 +22,7 @@ return [
'name' => 'MINGPIAN_INFO',
'title' => '电子名片',
'parent' => 'BASICS_LINK',
'wap_url' => '',
'wap_url' => '/pages/contact/contact',
'web_url' => '',
'sort' => 0
]

View File

@@ -253,7 +253,7 @@ class Enterprise extends BaseModel
*/
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);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {

View File

@@ -25,7 +25,7 @@ class Personnel extends BaseShop
} else {
$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);
return $this->fetch('personnel/diy');
}

View 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">&#xe67c;</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>

View 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">&#xe67c;</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View 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">&#xe615;</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

View 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">&#xe615;</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -86,7 +86,7 @@ class Pointexchange extends BaseShop
$list = $exchange_order_model->getExchangePageList($condition, $page, $page_size, $order, $field, 'eo', [
[ '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;
} else {

View File

@@ -468,12 +468,12 @@ class Weapp extends BaseModel
$server = $this->app->server;
$message = $server->getMessage();
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' ])) {
switch ( $message[ 'MsgType' ] ) {
case 'event':
$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)) {
model('shopcompoent_goods')->update([

View File

@@ -28,13 +28,11 @@ class Config extends BaseApi
$document_info = $config_model->getRegisterDocument($site_id, 'shop');
//隐私协议
$rivacy_info = $config_model->getRrivacyDocument($site_id, 'shop');
if($type == 1){//注册
$config = $document_info;
}else{//隐私
$config = $rivacy_info;
}
return $this->response($config);
}

View File

@@ -127,6 +127,13 @@ class Goods extends BaseApi
$poster = new Poster();
$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);
}
/**

View File

@@ -333,7 +333,20 @@ class Goodssku extends BaseApi
$join = [
[ '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();
$list = $goods->getGoodsSkuPageList($condition, $page, $page_size, $order_by, $field, $alias, $join);

View File

@@ -14,12 +14,36 @@ use addon\wxoplatform\model\Config as WxOplatformConfigModel;
use app\model\web\Config as WebConfig;
use think\facade\Log;
use app\model\system\Seal as SealModel;
use Carbon\Carbon;
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
function generateNFCScheme($accessToken) {
$url = "https://api.weixin.qq.com/wxa/generatenfcscheme?access_token={$accessToken}";

View File

@@ -601,4 +601,12 @@ class Member extends BaseApi
model('personnel_message')->add($insert);
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]);
}
}

View File

@@ -16,7 +16,6 @@ class Rrapi
*/
public function test()
{
exit;
$model = new Rrmodel();
//同步流程 首先同步所有公众号-》同步商品分类-》同步商品-》同步diy首页-》diy会员-》diy自定义页面-》单独同步vr链接
$uniacid = 1083;//设置大于0同步单个

View 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);
}
}

View File

@@ -1879,6 +1879,38 @@ function paramFilter($param)
return preg_replace($filter_rule, '', $param);
}
/**
* 格式化数据为日志友好的字符串(保持中文可读性)
*
* @param mixed $data 要格式化的数据
* @return string 格式化后的字符串
*/
function formatForLog($data): string
{
if (is_array($data) || is_object($data)) {
// 使用 JSON_UNESCAPED_UNICODE 保持中文可读性
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
return (string) $data;
}
/**
* 格式化数据为可导出的字符串完全避免Unicode转义
*
* @param mixed $data 要格式化的数据
* @return string 格式化后的字符串
*/
function exportForLog($data): string
{
if (is_array($data) || is_object($data)) {
// 使用 var_export 完全避免Unicode转义
return var_export($data, true);
}
return (string) $data;
}
/**
* 简单日志写入
* @param string $msg 日志内容

View File

@@ -1,5 +1,15 @@
@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 {
padding: 8px 0;

View File

@@ -5,7 +5,8 @@
<template v-if="nc.lazyLoad">
<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),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
@@ -48,8 +49,7 @@
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<digit-nav-list></digit-nav-list>
<!-- <digit-nav-list></digit-nav-list> -->
<div class="template-edit-title">
<h3>数字项设置</h3>
<div class="layui-form-item icon-radio">
@@ -109,10 +109,11 @@
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<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'">

View File

@@ -1,9 +1,21 @@
/**
* [图片导航的图片]·组件
*/
var digitNavListHtml = '<div style="display: none;"></div>';
Vue.component("digit-nav-list", {
template: digitNavListHtml,
// var digitNavListHtml = '<div style="display: none;"></div>';
var igitNavHtml = '<div class="digit-images">';
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 () {
return {
data: this.$parent.data,
@@ -89,7 +101,7 @@
methods: {
setnum(num){
console.log(num)
console.log(this.data)
this.data.rowCount = num
if(num == 3){
this.data.list = [

View File

@@ -31,7 +31,7 @@ class Task extends Controller
log_write('Task checkCron ...', 'debug');
$cron_model = new Cron();
$result = $cron_model->checkSchedule();
log_write('Task checkCron result: ' . json_encode($result), 'debug');
log_write('Task checkCron result: ' . formatForLog($result), 'debug');
return $result;
}

View File

@@ -56,4 +56,17 @@ class ScheduleDict
if($code) return $list[$code] ?? '';
return $list;
}
public static function getSuggestion(string $type) {
switch($type) {
case self::default:
return '请检查系统计划任务配置,确保 cron 进程正常运行,并检查网络连接和 SSL 证书设置。';
case self::url:
return '请检查网络连接、目标 URL 可访问性、HTTP 状态码和接口认证配置。可以使用 curl 命令手动测试接口。';
case self::cli:
return '请检查 cron 服务状态、命令执行权限、脚本路径和 PHP CLI 环境。建议使用 crontab -l 查看当前任务配置。';
default:
return '请检查计划任务配置文件和相关权限设置,确保所有依赖服务正常运行。';
}
}
}

View File

@@ -185,7 +185,7 @@ class DiyViewEdit extends Controller
}
$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("time", time());

View File

@@ -25,7 +25,6 @@ class InitConfig
$this->initConst();
//初始化配置信息
$this->initConfig();
log_write('系统配置信息已初始化', 'debug');
}
/**

View File

@@ -106,7 +106,6 @@ class Goods extends BaseMerchant
$condition[] = [ 'ischeck', '=', 1 ];
}
}
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
if (!empty($start_sale)) $condition[] = [ 'sale_num', '>=', $start_sale ];
if (!empty($end_sale)) $condition[] = [ 'sale_num', '<=', $end_sale ];
if (!empty($start_price)) $condition[] = [ 'price', '>=', $start_price ];

View File

@@ -75,7 +75,7 @@ class Order extends BaseMerchant
$order_status = input('order_status', '');//订单状态
}
}
file_put_contents(__DIR__ . '/debug.txt', var_export($order_status,true));
$order_name = input('order_name', '');
$pay_type = input('pay_type', '');
$order_from = input('order_from', '');

View File

@@ -121,7 +121,7 @@ class Model
/**
* 获取分页列表数据
* @param array $condition
* @param bool $field
* @param bool | string $field
* @param string $order
* @param int $page
* @param int $list_rows

View File

@@ -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 = [])
{
$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) {
if (isset($v[ '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);
} catch (Exception $e) {
dump($e);
// dump($e);
return $this->error('', $e->getMessage());
}
}

View File

@@ -104,7 +104,8 @@ class GoodsApi extends BaseModel
$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; // 该商品已购数量
$res[ 'goods_sku_detail' ] = $goods_sku_detail;

View File

@@ -76,7 +76,7 @@ class Login extends BaseModel
$info = [];
$auth_tag = '';
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;
if (empty($value)) return $this->error('', 'PARAMETER_ERROR');
$info = model("member")->getInfo(
@@ -95,7 +95,8 @@ class Login extends BaseModel
// 会员不存在 第三方自动注册开启 未开启绑定手机 则进行自动注册
$config = new Config();
$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_res = $register->authRegister($data);
if ($register_res[ 'code' ] == 0) {

View File

@@ -27,6 +27,14 @@ use think\facade\Config;
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
@@ -256,6 +264,7 @@ class Member extends BaseModel
$member_info = model('member')->setIsCache(0)->getInfo($condition, $field);
if (!empty($member_info) && empty($member_info[ 'wx_openid' ]) && !empty($member_info[ 'wx_unionid' ])) {
// TODO: 注意, 华为云上的最新代码,下面都注释掉了,
$fans_model = new Fans();
$fans_condition[] = [ "unionid", "=", $member_info[ 'wx_unionid' ] ];
$fans_info = $fans_model->getFansInfo($fans_condition);

View File

@@ -143,6 +143,7 @@ class Register extends BaseModel
'ali_openid' => $data['ali_openid'] ?? '',
'baidu_openid' => $data['baidu_openid'] ?? '',
'toutiao_openid' => $data['toutiao_openid'] ?? '',
'huawei_openid' => $data['huawei_openid'] ?? '',
'headimg' => $data['avatarUrl'] ?? '',
'member_level' => !empty($member_level_info) ? $member_level_info[ 'level_id' ] : 0,
'member_level_name' => !empty($member_level_info) ? $member_level_info[ 'level_name' ] : '',

View File

@@ -1198,7 +1198,6 @@ class OrderCommon extends BaseModel
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);
file_put_contents(__DIR__ . '/debug.txt', var_export($condition,true));
$check_condition = array_column($condition, 2, 0);
if (!empty($order_list[ 'list' ])) {

View File

@@ -36,6 +36,7 @@ class OrderCreate extends BaseModel
model('order')->startTrans();
$pay_model = new Pay();
$this->out_trade_no = $pay_model->createOutTradeNo($this->member_id);
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_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['business'] = input('business','');
if($i >= 1){
//主表订单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);
}else{
$order_id = model('order')->add($order_insert_data);
$this->order_id = $order_id;
}
$order_goods_insert_data = [];
//订单项目表
foreach ($v['goods_list'] as $order_goods_v) {

View File

@@ -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'];
$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)) {//满减默认
$discount_array = $this->getManjianDiscountMoney($all_info);

View File

@@ -61,13 +61,13 @@ class Cron extends BaseModel
*/
public function execute($type = 'default')
{
log_write('计划任务开始执行', 'debug');
log_write('计划任务开始执行', 'info');
if (config('cron.default') != $type) {
log_write('计划任务方式不匹配<不能执行/model/system/Cron/execute>' . config('cron.default') . ' != ' . $type, 'debug');
log_write('计划任务方式不匹配<不能执行/model/system/Cron/execute>' . config('cron.default') . ' != ' . $type, 'warning');
return true;
}
log_write('当前执行方式:' . $type, 'debug');
log_write('当前执行方式:' . $type, 'info');
try {
//写入计划任务标记运行
@@ -78,7 +78,7 @@ class Cron extends BaseModel
$query_execute_time = $is_open_queue == 1 ? time() + 60 : time();
$list = model('cron')->getList([['execute_time', '<=', $query_execute_time]]);
$now_time = time();
log_write('计划任务开始执行,查询计划任务列表', 'debug');
log_write('计划任务开始执行,查询计划任务列表', 'info');
if (!empty($list)) {
foreach ($list as $k => $v) {
@@ -97,7 +97,7 @@ class Cron extends BaseModel
return $res ?? $this->success();
}, function ($params) {
try {
log_write('调用事件名称:' . $params['name'], 'debug');
log_write('调用事件名称:' . $params['name'], 'info');
$res = event($params['event'], ['relate_id' => $params['relate_id']]);
} catch (\Exception $e) {
$res = $this->error($e->getMessage(), $e->getMessage());
@@ -150,7 +150,7 @@ class Cron extends BaseModel
// $this->setCron();
return true;
} catch (\Exception $e) {
log_write('计划任务执行异常<model/system/Cron/execute>' . $e->getMessage(), 'debug');
log_write('计划任务执行异常<model/system/Cron/execute>' . $e->getMessage(), 'error');
return true;
}
}
@@ -252,9 +252,16 @@ class Cron extends BaseModel
$remark = 'Cron计划任务已停止当前启动的任务方式' . ScheduleDict::getType(config('cron.default')) . '。';
$error = self::getError(config('cron.default'));
if (!empty($error)) {
$remark .= json_encode($error);
$remark .= formatForLog($error);
}
log_write('Cron计划任务校验计划任务是否正常运行计划任务异常异常信息' . json_encode($error) . ',文件路径:' . $file, 'warning');
$detail = [
'error'=> $error,
'remark' => $remark,
'suggestion' => ScheduleDict::getSuggestion(config('cron.default')),
];
log_write('Cron计划任务校验计划任务是否正常运行计划任务异常异常信息' . formatForLog($detail) . ',文件路径:' . $file, 'warning');
return $this->error([], $remark);
} catch (\Exception $e) {
log_write('Cron计划任务校验计划任务是否正常运行异常' . $e->getMessage() . ',异常行:' . $e->getLine() . ',文件路径:' . $file, 'error');

View File

@@ -66,11 +66,11 @@ class Document extends BaseModel
public function getDocument($condition)
{
// $json_condition = json_encode($condition);
// $cache = Cache::get("document_" . $json_condition, "");
// if (!empty($cache)) {
// return $this->success($cache);
// }
$json_condition = json_encode($condition);
$cache = Cache::get("document_" . $json_condition, "");
if (!empty($cache)) {
return $this->success($cache);
}
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
@@ -98,7 +98,7 @@ class Document extends BaseModel
'modify_time' => 0
];
}
// Cache::tag("document")->set("document_" . $json_condition, $info);
Cache::tag("document")->set("document_" . $json_condition, $info);
return $this->success($info);
}

View File

@@ -38,7 +38,7 @@ class Menu extends BaseModel
// if (!empty($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);
return $this->success($list);

View 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());
}
}
}

View File

@@ -1,5 +1,4 @@
<?php
namespace app\model\web;
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')
{
$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;
}
@@ -74,20 +73,20 @@ class Config extends BaseModel
public function getCaptchaConfig($site_id = 1, $app_module = 'shop')
{
$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'])) {
$res['data']['value'] = [
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'shop_login' => 1,
'shop_reception_login' => 1,
'shop_reception_register' => 1
];
} else {
if (isset($res['data']['value']['shop_reception_login']) === false) {
$res['data']['value']['shop_reception_login'] = 1;
if (isset($res[ 'data' ][ 'value' ][ 'shop_reception_login' ]) === false) {
$res[ 'data' ][ 'value' ][ 'shop_reception_login' ] = 1;
}
if (isset($res['data']['value']['shop_reception_register']) === false) {
$res['data']['value']['shop_reception_register'] = 1;
if (isset($res[ 'data' ][ 'value' ][ 'shop_reception_register' ]) === false) {
$res[ 'data' ][ 'value' ][ 'shop_reception_register' ] = 1;
}
}
return $res;
@@ -102,31 +101,31 @@ class Config extends BaseModel
*/
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)) {
$upload_model = new Upload();
if ($data['goods'] && $config_info['goods'] && $data['goods'] != $config_info['goods']) {
$upload_model->deletePic($config_info['goods'], $site_id);
if ($data[ 'goods' ] && $config_info[ 'goods' ] && $data[ 'goods' ] != $config_info[ 'goods' ]) {
$upload_model->deletePic($config_info[ 'goods' ], $site_id);
}
if ($data['head'] && $config_info['head'] && $data['head'] != $config_info['head']) {
$upload_model->deletePic($config_info['head'], $site_id);
if ($data[ 'head' ] && $config_info[ 'head' ] && $data[ 'head' ] != $config_info[ 'head' ]) {
$upload_model->deletePic($config_info[ 'head' ], $site_id);
}
if ($data['store'] && $config_info['store'] && $data['store'] != $config_info['store']) {
$upload_model->deletePic($config_info['store'], $site_id);
if ($data[ 'store' ] && $config_info[ 'store' ] && $data[ 'store' ] != $config_info[ 'store' ]) {
$upload_model->deletePic($config_info[ 'store' ], $site_id);
}
if ($data['article'] && $config_info['article'] && $data['article'] != $config_info['article']) {
$upload_model->deletePic($config_info['article'], $site_id);
if ($data[ 'article' ] && $config_info[ 'article' ] && $data[ 'article' ] != $config_info[ 'article' ]) {
$upload_model->deletePic($config_info[ 'article' ], $site_id);
}
if ($data['kefu'] && $config_info['kefu'] && $data['kefu'] != $config_info['kefu']) {
$upload_model->deletePic($config_info['kefu'], $site_id);
if ($data[ 'kefu' ] && $config_info[ 'kefu' ] && $data[ 'kefu' ] != $config_info[ 'kefu' ]) {
$upload_model->deletePic($config_info[ 'kefu' ], $site_id);
}
if ($data['phone'] && $config_info['phone'] && $data['phone'] != $config_info['phone']) {
$upload_model->deletePic($config_info['phone'], $site_id);
if ($data[ 'phone' ] && $config_info[ 'phone' ] && $data[ 'phone' ] != $config_info[ 'phone' ]) {
$upload_model->deletePic($config_info[ 'phone' ], $site_id);
}
}
$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;
}
@@ -139,9 +138,9 @@ class Config extends BaseModel
public function getDefaultImg($site_id, $app_model = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_model], ['config_key', '=', 'DEFAULT_IMAGE']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_model ], [ 'config_key', '=', 'DEFAULT_IMAGE' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'goods' => 'public/static/img/default_img/square.png',
'head' => 'public/static/img/default_img/head.png',
'store' => 'public/static/img/default_img/store.png',
@@ -151,14 +150,14 @@ class Config extends BaseModel
];
}
if (empty($res['data']['value']['head'])) {
$res['data']['value']['head'] = 'public/static/img/default_img/head.png';
if (empty($res[ 'data' ][ 'value' ][ 'head' ])) {
$res[ 'data' ][ 'value' ][ 'head' ] = 'public/static/img/default_img/head.png';
}
if (empty($res['data']['value']['article'])) {
$res['data']['value']['article'] = 'public/static/img/default_img/article.png';
if (empty($res[ 'data' ][ 'value' ][ 'article' ])) {
$res[ 'data' ][ 'value' ][ 'article' ] = 'public/static/img/default_img/article.png';
}
if (empty($res['data']['value']['store'])) {
$res['data']['value']['store'] = 'public/static/img/default_img/store.png';
if (empty($res[ 'data' ][ 'value' ][ 'store' ])) {
$res[ 'data' ][ 'value' ][ 'store' ] = 'public/static/img/default_img/store.png';
}
return $res;
}
@@ -174,7 +173,7 @@ class Config extends BaseModel
public function setCopyright($data, $site_id = 1, $app_model = 'shop')
{
$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;
}
@@ -187,16 +186,16 @@ class Config extends BaseModel
public function getCopyright($site_id = 1, $app_module = 'shop')
{
$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');
if (empty($auth_info)) {
$upgrade_model = new Upgrade();
$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'])) {
$res['data']['value'] = [
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'logo' => '',
'company_name' => '',
'copyright_link' => '',
@@ -207,15 +206,16 @@ class Config extends BaseModel
'market_supervision_url' => ''
];
} else {
if (is_null($auth_info) || $auth_info['code'] != 0) {
$res['data']['value']['logo'] = '';
$res['data']['value']['company_name'] = '';
$res['data']['value']['copyright_link'] = '';
$res['data']['value']['copyright_desc'] = '';
if (is_null($auth_info) || $auth_info[ 'code' ] != 0) {
$res[ 'data' ][ 'value' ][ 'logo' ] = '';
$res[ 'data' ][ 'value' ][ 'company_name' ] = '';
$res[ 'data' ][ 'value' ][ 'copyright_link' ] = '';
$res[ 'data' ][ 'value' ][ 'copyright_desc' ] = '';
}
}
// 检查是否授权
$res['data']['value']['auth'] = true;
$res[ 'data' ][ 'value' ][ 'auth' ] = true;
return $res;
}
@@ -229,7 +229,7 @@ class Config extends BaseModel
public function setAuth($data, $site_id = 1, $app_model = 'shop')
{
$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;
}
@@ -240,9 +240,9 @@ class Config extends BaseModel
public function getAuth($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'AUTH']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'AUTH' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'code' => '',
];
}
@@ -259,7 +259,7 @@ class Config extends BaseModel
public function setMapConfig($data, $site_id, $app_model = 'shop')
{
$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;
}
@@ -273,16 +273,16 @@ class Config extends BaseModel
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'MAP_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
'tencent_map_key' => '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE', //默认一个地图TB5BZ-FBRRX-2RJ4C-76SZY-TYQ3H-F4BFC
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'tencent_map_key' => '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE',//默认一个地图TB5BZ-FBRRX-2RJ4C-76SZY-TYQ3H-F4BFC
'wap_is_open' => 1, // 手机端是否开启定位
'wap_valid_time' => 5 // 手机端定位有效期/分钟过期后将重新获取定位信息0为不过期
];
}
$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']['tencent_map_key'] = '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE';
$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' ]['tencent_map_key'] = '2PJBZ-A263Q-SED5B-4SAAB-HCUQ5-DUFHE';
return $res;
}
@@ -296,19 +296,19 @@ class Config extends BaseModel
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-~\/])+$/';
if ($data['deploy_way'] == 'separate') {
if (!preg_match($search, $data['domain_name_h5'])) {
if ($data[ 'deploy_way' ] == 'separate') {
if (!preg_match($search, $data[ 'domain_name_h5' ])) {
return $this->error('', '请输入正确的域名地址');
}
}
// 默认部署,更新店铺域名
if ($data['deploy_way'] == 'default') {
if ($data[ 'deploy_way' ] == 'default') {
$this->setShopDomainConfig([
'domain_name' => __ROOT__
], $site_id);
}
$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;
}
@@ -322,9 +322,9 @@ class Config extends BaseModel
public function getH5DomainName($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'H5_DOMAIN_NAME']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'H5_DOMAIN_NAME' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'domain_name_h5' => __ROOT__ . '/h5',
'deploy_way' => 'default'
];
@@ -342,7 +342,7 @@ class Config extends BaseModel
public function setDomainJumpConfig($data, $site_id = 1, $app_module = 'shop')
{
$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;
}
@@ -356,12 +356,12 @@ class Config extends BaseModel
{
$config = new ConfigModel();
$res = $config->getConfig([
['site_id', '=', $site_id],
['app_module', '=', $app_module],
['config_key', '=', 'DOMAIN_JUMP_CONFIG']
[ 'site_id', '=', $site_id ],
[ 'app_module', '=', $app_module ],
[ 'config_key', '=', 'DOMAIN_JUMP_CONFIG' ]
]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'jump_type' => 3, // 1用户前台2商家后台3引导页
];
}
@@ -378,19 +378,19 @@ class Config extends BaseModel
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-~\/])+$/';
if ($data['deploy_way'] == 'separate') {
if (!preg_match($search, $data['domain_name_pc'])) {
if ($data[ 'deploy_way' ] == 'separate') {
if (!preg_match($search, $data[ 'domain_name_pc' ])) {
return $this->error('', '请输入正确的域名地址');
}
}
// 默认部署,更新店铺域名
if ($data['deploy_way'] == 'default') {
if ($data[ 'deploy_way' ] == 'default') {
$this->setShopDomainConfig([
'domain_name' => __ROOT__
], $site_id);
}
$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;
}
@@ -403,19 +403,19 @@ class Config extends BaseModel
public function getPcDomainName($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'PC_DOMAIN_NAME']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'PC_DOMAIN_NAME' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'domain_name_pc' => __ROOT__ . '/web',
'deploy_way' => 'default'
];
} else {
if ($res['data']['value']['domain_name_pc'] == '' || empty($res['data']['value']['deploy_way']) || $res['data']['value']['deploy_way'] == 'default') {
$res['data']['value'] = [
if ($res[ 'data' ][ 'value' ][ 'domain_name_pc' ] == '' || empty($res[ 'data' ][ 'value' ][ 'deploy_way' ]) || $res[ 'data' ][ 'value' ][ 'deploy_way' ] == 'default') {
$res[ 'data' ][ 'value' ] = [
'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;
}
@@ -430,7 +430,7 @@ class Config extends BaseModel
public function setHotSearchWords($data, $site_id, $app_module)
{
$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;
}
@@ -443,9 +443,9 @@ class Config extends BaseModel
public function getHotSearchWords($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_HOT_SEARCH_WORDS_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'words' => ''
];
}
@@ -462,7 +462,7 @@ class Config extends BaseModel
public function setGuessYouLike($data, $site_id, $app_module)
{
$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;
}
@@ -475,11 +475,11 @@ class Config extends BaseModel
public function getGuessYouLike($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_GUESS_YOU_LIKE_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'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',
'goodsIds' => [],
'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;
}
@@ -522,17 +522,17 @@ class Config extends BaseModel
public function getDiyAdv($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_STARTADV']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
'list' => [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_STARTADV' ] ]);
if (empty($res[ 'data' ][ 'value' ])){
$res[ 'data' ][ 'value' ] = [
'list' =>[
[
'title' => '启动广告',
'link' => [
'name' => ''
'title'=>'启动广告',
'link'=>[
'name'=>''
],
'iconType' => 'img',
'imageUrl' => "public/static/ext/diyview/img/preview/advs_default.png"
'iconType'=>'img',
'imageUrl'=>"public/static/ext/diyview/img/preview/advs_default.png"
]
],
'advtype' => 1,
@@ -552,7 +552,7 @@ class Config extends BaseModel
public function setDiyAdv($data, $site_id, $app_module)
{
$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;
}
@@ -566,14 +566,14 @@ class Config extends BaseModel
public function getDiyVr($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'DIY_VR']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'DIY_VR' ] ]);
if (empty($res[ 'data' ][ 'value' ])){
$res[ 'data' ][ 'value' ] = [
'title' => '工厂展示',
'url' => 'https://baidu.com',
];
}
// $res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
// $res[ 'data' ][ 'value' ][ 'nameLineMode' ] = $res[ 'data' ][ 'value' ][ 'nameLineMode' ] ?? 'single'; // 商品名称,单行、多行展示
return $res;
}
@@ -587,7 +587,7 @@ class Config extends BaseModel
public function setDiyVr($data, $site_id, $app_module)
{
$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;
}
@@ -602,7 +602,7 @@ class Config extends BaseModel
public function setGoodsListConfig($data, $site_id, $app_module)
{
$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;
}
@@ -615,9 +615,9 @@ class Config extends BaseModel
public function getGoodsListConfig($site_id, $app_module)
{
$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 = [
'fontWeight' => false,
'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;
}
@@ -660,7 +660,7 @@ class Config extends BaseModel
public function setDefaultSearchWords($data, $site_id, $app_module)
{
$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;
}
@@ -673,9 +673,9 @@ class Config extends BaseModel
public function getDefaultSearchWords($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DEFAULT_SEARCH_WORDS_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'words' => '搜索 商品'
];
}
@@ -692,7 +692,7 @@ class Config extends BaseModel
public function setGoodsSort($data, $site_id, $app_module)
{
$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;
}
@@ -705,9 +705,9 @@ class Config extends BaseModel
public function getGoodsSort($site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_SORT_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_SORT_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'type' => 'asc',
'default_value' => 100
];
@@ -725,7 +725,7 @@ class Config extends BaseModel
public function setCategoryConfig($data, $site_id = 1, $app_module = 'shop')
{
$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;
}
@@ -738,9 +738,9 @@ class Config extends BaseModel
public function getCategoryConfig($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_CATEGORY_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_CATEGORY_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'category' => 1,
'img' => 1
];
@@ -758,7 +758,7 @@ class Config extends BaseModel
public function setGoodsDetailConfig($data, $site_id, $app_module = 'shop')
{
$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;
}
@@ -771,9 +771,9 @@ class Config extends BaseModel
public function getGoodsDetailConfig($site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_DETAIL_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_DETAIL_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'nav_bar_switch' => 0, // 是否透明0不透明1透明
'introduction_color' => '#303133',
];
@@ -791,7 +791,7 @@ class Config extends BaseModel
public function setShopDomainConfig($data, $site_id = 1, $app_module = 'shop')
{
$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;
}
@@ -804,12 +804,12 @@ class Config extends BaseModel
public function getShopDomainConfig($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'SHOP_DOMAIN_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'SHOP_DOMAIN_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'domain_name' => __ROOT__,
];
$this->setShopDomainConfig($res['data']['value'], $site_id);
$this->setShopDomainConfig($res[ 'data' ][ 'value' ], $site_id);
}
return $res;
}
@@ -817,11 +817,11 @@ class Config extends BaseModel
{
$qq_map = new \app\model\map\QqMap(['key' => $tencent_map_key]);
$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 ($res['status'] != 0 && $type == 0) {
$res['message'] = '腾讯地图配置错误,无法定位地址';
if ($res[ 'status' ] != 0 && $type == 0) {
$res[ 'message' ] = '腾讯地图配置错误,无法定位地址';
}
}
return $res;
@@ -857,7 +857,7 @@ class Config extends BaseModel
public function setGoodsNo($data, $site_id, $app_module)
{
$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;
}
@@ -870,9 +870,9 @@ class Config extends BaseModel
public function getGoodsNo($site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'GOODS_NO_CONFIG']]);
if (empty($res['data']['value'])) {
$res['data']['value'] = [
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'GOODS_NO_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'uniqueness_switch' => 1,
];
}

View File

@@ -201,9 +201,90 @@ class DiyViewLink extends BaseModel
$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);
}
/**
* 查询文章列表
* @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
* @return array

View File

@@ -56,7 +56,7 @@ class Shop extends BasePlatform
['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);
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){
$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']);

View File

@@ -123,11 +123,12 @@ class BaseShop extends Controller
$config_view = Config::get('view');
$config_view[ 'tpl_replace_string' ] = array_merge($config_view[ 'tpl_replace_string' ], $this->replace);
Config::set($config_view, 'view');
// 其他操作
if (!request()->isAjax()) {
$this->initBaseInfo();
$this->loadTemplate();
}
}
/**
@@ -196,6 +197,14 @@ class BaseShop extends Controller
$where[] = ['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) {
$menus = $menu_model->getMenuList($where, $field, 'level asc,sort asc');
} else {

View File

@@ -1907,6 +1907,7 @@ class Goods extends BaseShop
if ($data[ 'code' ] < 0) {
return $data;
}
$result = ( new GoodsImport() )->importGoods($data[ 'data' ], $this->site_id, $type);
return $result;
} else {

View File

@@ -35,6 +35,7 @@ class Index extends BaseShop
*/
public function index()
{
$this->assign('shop_status', 1);
$this->handlePromotion();

View File

@@ -25,6 +25,62 @@ use addon\coupon\model\Coupon as CouponModel;
*/
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);
}
}
/*
* 会员概况
*/

View File

@@ -89,7 +89,7 @@ class Message extends BaseShop
$edit_data = $edit_data_result['data'][ 0 ];
$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 ]));
}

View File

@@ -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.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.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();
if (request()->isJson()) {
$page_index = input('page', 1);

View File

@@ -126,7 +126,7 @@ class Seal extends BaseShop
foreach($list['data']['list'] as &$row){
$row['create_time'] = date('Y-m-d h:i:s',$row['create_time']);
}
file_put_contents(__DIR__ . '/debug.txt', var_export($list,true));
// file_put_contents(__DIR__ . '/debug.txt', var_export($list,true));
return $list;
} else {
return $this->fetch("seal/mediumimport");

View File

@@ -548,6 +548,30 @@
<!-- 商品详情 -->
<div class="layui-tab-item">
<div class="layui-form-item">
<label class="layui-form-label short-label"><span class="required">*</span>PDF标题</label>
<div class="layui-input-inline">
<input type="text" name="pdf_name" value="{$goods_info.pdf_name}" maxlength="40" autocomplete="off" placeholder="请输入PDF标题" 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>PDF文件</label>
<div class="layui-input-block">
<p class="file-upload">{if $goods_info.pdf_url}<a href="{:img($goods_info.pdf_url)}" target="_blank" style="color:#4390FF">查看文件</a>{else}未上传{/if}</p>
<button type="button" class="layui-btn" id="cert_upload">
<i class="layui-icon">&#xe67c;</i>
选择PDF文件
</button>
<input type="hidden" name="pdf_url" class="layui-input len-long" value="{$info.pdf_url ?? ''}" lay-verify="pdf_url">
</div>
<div class="word-aux">请选择pdf文件</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm"></label>
<div class="layui-input-inline special-length">
@@ -1057,7 +1081,7 @@
<script src="__STATIC__/ext/video/videojs-ie8.min.js"></script>
<script src="__STATIC__/ext/video/video.min.js"></script>
<script src="__STATIC__/ext/searchable_select/searchable_select.js"></script>
<script src="SHOP_JS/goods_edit_common.js?v=4"></script>
<script src="SHOP_JS/goods_edit_common.js?v={$version}"></script>
<script src="SHOP_JS/goods_edit.js"></script>
<script src="SHOP_JS/category_select.js"></script>

View File

@@ -0,0 +1,272 @@
<style>
.layui-layer-content {padding-bottom: 20px!important;}
</style>
<!-- 搜索框 -->
<div class="single-filter-box">
<button class="layui-btn" onclick="addLabel()">添加姓名</button>
<!-- <div class="layui-form">
<div class="layui-input-inline">
<input type="text" name="search_keys" placeholder="请输入姓名名称" autocomplete="off" class="layui-input" maxlength="10">
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
<i class="layui-icon">&#xe615;</i>
</button>
</div>
</div> -->
</div>
<!-- 列表 -->
<table id="attr_class_list" lay-filter="attr_class_list"></table>
<!-- 编辑排序 -->
<script type="text/html" id="editSort">
<input name="sort" type="number" onchange="editSort({{d.id}}, this)" value="{{d.sort}}" class="layui-input edit-sort len-short">
</script>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
</div>
</script>
<script type="text/html" id="addLabel">
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label mid"><span class="required">*</span></label>
<div class="layui-input-block">
<input name="realname" type="text" placeholder="请输入" lay-verify="required" class="layui-input len-mid" maxlength="10">
</div>
</div>
<div class="form-row mid">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="closeAttrLayer()">返回</button>
</div>
</div>
</script>
<script type="text/html" id="editLabel">
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label mid"><span class="required">*</span></label>
<div class="layui-input-block">
<input name="realname" type="text" value="{{ d.realname }}" placeholder="请输入" lay-verify="required" class="layui-input len-mid" maxlength="10">
</div>
</div>
<input type="hidden" name="id" value="{{ d.id }}">
<div class="form-row mid">
<button class="layui-btn" lay-submit lay-filter="edit_save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="closeAttrLayer()">返回</button>
</div>
</div>
</script>
<script>
var laytpl, add_attr_index = -1,
form, table;
layui.use(['form', 'laytpl'], function() {
var repeat_flag = false; //防重复标识
laytpl = layui.laytpl;
form = layui.form;
form.render();
table = new Table({
elem: '#attr_class_list',
url: ns.url("shop/member/business"),
cols: [
[ {
field: 'realname',
title: '姓名',
unresize: 'false'
},{
title: '操作',
toolbar: '#operation',
unresize: 'false',
align : 'right'
}]
]
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'edit':
editLabel(data);
break;
case 'delete':
deleteLabel(data.id);
break;
}
});
table.on("sort",function (obj) {
table.reload({
page: {
curr: 1
},
where: {
order:obj.field,
sort:obj.type
}
});
});
/**
* 删除
*/
function deleteLabel(id) {
layer.confirm('确认删除吗?', function(index) {
layer.close(index);
$.ajax({
url: ns.url("shop/member/businessdelete"),
data: {
id:id
},
dataType: 'JSON',
type: 'POST',
success: function(res) {
layer.msg(res.message);
if (res.code == 0) {
table.reload();
}
}
});
});
}
/**
* 搜索功能
*/
form.on('submit(search)', function(data) {
table.reload({
page: {
curr: 1
},
where: data.field
});
});
form.on('submit(save)', function(data) {
if (repeat_flag) return false;
repeat_flag = true;
$.ajax({
url: '{:addon_url("shop/member/businesspost")}',
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(data) {
layer.msg(data.message);
if (data.code == 0) {
table.reload();
layer.close(add_attr_index);
}
repeat_flag = false;
}
});
return false;
});
form.on('submit(edit_save)', function(data) {
if (repeat_flag) return false;
repeat_flag = true;
$.ajax({
url: '{:addon_url("shop/member/businesspost")}',
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(data) {
layer.msg(data.message);
if (data.code == 0) {
table.reload();
layer.close(add_attr_index);
}
repeat_flag = false;
}
});
return false;
});
/**
* 表单验证
*/
form.verify({
num: function(value) {
if (value == '') {
return;
}
if (value % 1 != 0) {
return '排序数值必须为整数';
}
if (value < 0) {
return '排序数值必须为大于0';
}
}
});
});
function addLabel() {
var add_attr = $("#addLabel").html();
laytpl(add_attr).render({}, function(html) {
add_attr_index = layer.open({
title: '添加姓名',
skin: 'layer-tips-class',
type: 1,
area: ['500px', '300px'],
content: html,
success: function() {
layui.use('form', function() {
var form = layui.form;
form.render('select');
});
}
});
});
}
function editLabel(data) {
var add_attr = $("#editLabel").html();
laytpl(add_attr).render(data, function(html) {
add_attr_index = layer.open({
title: '编辑姓名',
skin: 'layer-tips-class',
type: 1,
area: ['500px', '300px'],
content: html,
success: function() {
layui.use('form', function() {
var form = layui.form;
form.render('select');
});
}
});
});
// laytpl(add_attr).render(data, function(html) {
// add_attr_index = layer.open({
// title: '编辑姓名',
// skin: 'layer-tips-class',
// type: 1,
// area: ['500px', '300px'],
// content: html
// });
// });
}
function closeAttrLayer() {
layer.close(add_attr_index);
}
</script>

View File

@@ -130,7 +130,7 @@
<!-- 主动退款 -->
{include file="order/shop_active_refund" /}
<script src="SHOP_JS/order_list.js?v=3"></script>
<script src="SHOP_JS/order_list.js?v=5"></script>
<script src="SHOP_JS/lodop_funcs.js"></script>
<script>
var laypage,element, form;

View File

@@ -313,6 +313,9 @@ Order.prototype.tbody = function () {
if (order.buyer_ask_delivery_time != '' && order.buyer_ask_delivery_time != 0) tbody += '<span class="order-item-header" style="margin-left:50px;">要求送达时间:' + (order.buyer_ask_delivery_time.indexOf('-') != -1 ? order.buyer_ask_delivery_time : ns.time_to_date(order.buyer_ask_delivery_time) ) + '</span>';
else tbody += '<span class="order-item-header" style="margin-left:50px;">要求送达时间:立即送达</span>';
}
if (order.business) tbody += '<span class="order-item-header" style="color:red;">业务员:' + order.business +'</span>';
tbody += '</td>';
tbody += '<td colspan="2">';
tbody += '<div class="table-btn order-list-top-line" style="align:right;">';

View File

@@ -0,0 +1,375 @@
<style>
.layui-layer-content {padding-bottom: 20px!important;}
.layui-table-cell, .layui-table-tool-panel li {
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.layui-table-view .layui-table[lay-size=lg] .layui-table-cell {
line-height: 20px;
font-size: 12px;
}
</style>
<!-- 搜索框 -->
<!-- <div class="single-filter-box">
<button class="layui-btn" id="product_file">导入介质材料</button>
<div class="layui-form">
<div class="layui-input-inline">
<input type="text" name="search_keys" placeholder="标签组名称" autocomplete="off" class="layui-input" maxlength="10">
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
<i class="layui-icon">&#xe615;</i>
</button>
</div>
</div>
</div> -->
<!-- 列表 -->
<table id="attr_class_list" lay-filter="attr_class_list"></table>
<!-- 编辑排序 -->
<script type="text/html" id="editSort">
<input name="sort" type="number" onchange="editSort({{d.id}}, this)" value="{{d.sort}}" class="layui-input edit-sort len-short">
</script>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
</div>
</script>
<script type="text/html" id="addLabel">
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label mid"><span class="required">*</span></label>
<div class="layui-input-block">
<input name="label_name" type="text" placeholder="标签组名称" lay-verify="required" class="layui-input len-mid" maxlength="10">
</div>
</div>
<div class="form-row mid">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="closeAttrLayer()">返回</button>
</div>
</div>
</script>
<script type="text/html" id="editLabel">
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label mid"><span class="required">*</span></label>
<div class="layui-input-block">
<input name="label_name" type="text" value="{{ d.label_name }}" placeholder="标签组名称" lay-verify="required" class="layui-input len-mid" maxlength="10">
</div>
</div>
<input type="hidden" name="id" value="{{ d.id }}">
<div class="form-row mid">
<button class="layui-btn" lay-submit lay-filter="edit_save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="closeAttrLayer()">返回</button>
</div>
</div>
</script>
<script>
var laytpl, add_attr_index = -1,
form, table;
layui.use(['form', 'laytpl'], function() {
var repeat_flag = false; //防重复标识
laytpl = layui.laytpl;
form = layui.form;
form.render();
table = new Table({
elem: '#attr_class_list',
url: ns.url("shop/seal/medium"),
cols: [
[ {
field: 'name',
title: '介质',
width:'8%',
unresize: 'false'
},{
field: 'FFKM',
title: 'FFKM',
unresize: 'false'
},{
field: 'FEPM',
title: 'FEPM',
unresize: 'false'
},{
field: 'SBR',
title: 'SBR',
unresize: 'false'
},{
field: 'CR',
title: 'CR',
unresize: 'false'
},{
field: 'PTFE&PFA',
title: 'PTFE&PFA',
width:'7%',
unresize: 'false'
},{
field: 'EPDM',
title: 'EPDM',
unresize: 'false'
},{
field: 'ECO',
title: 'ECO',
unresize: 'false'
},{
field: 'ⅡR',
title: 'ⅡR',
unresize: 'false'
},{
field: 'NBR',
title: 'NBR',
unresize: 'false'
},{
field: 'ACM',
title: 'ACM',
unresize: 'false'
},{
field: 'PU',
title: 'PU',
unresize: 'false'
},{
field: 'NR',
title: 'NR',
unresize: 'false'
},{
field: 'FKM',
title: 'FKM',
unresize: 'false'
},{
field: 'AEM',
title: 'AEM',
unresize: 'false'
},{
field: 'HNBR',
title: 'HNBR',
unresize: 'false'
},{
field: 'FVMQ',
title: 'FVMQ',
unresize: 'false'
},{
field: 'CSM',
title: 'CSM',
unresize: 'false'
},{
field: 'VMQ',
title: 'VMQ',
unresize: 'false'
},
// {
// title: '操作',
// toolbar: '#operation',
// unresize: 'false',
// align : 'right'
// }
]]
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'edit':
editLabel(data);
break;
case 'delete':
deleteLabel(data.id);
break;
}
});
table.on("sort",function (obj) {
table.reload({
page: {
curr: 1
},
where: {
order:obj.field,
sort:obj.type
}
});
});
/**
* 删除
*/
function deleteLabel(id) {
layer.confirm('确认删除该标签吗?', function(index) {
layer.close(index);
$.ajax({
url: ns.url("shop/goodslabel/delete"),
data: {
id:id
},
dataType: 'JSON',
type: 'POST',
success: function(res) {
layer.msg(res.message);
if (res.code == 0) {
table.reload();
}
}
});
});
}
/**
* 搜索功能
*/
form.on('submit(search)', function(data) {
table.reload({
page: {
curr: 1
},
where: data.field
});
});
form.on('submit(save)', function(data) {
if (repeat_flag) return false;
repeat_flag = true;
$.ajax({
url: '{:addon_url("shop/goodslabel/add")}',
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(data) {
layer.msg(data.message);
if (data.code == 0) {
table.reload();
layer.close(add_attr_index);
}
repeat_flag = false;
}
});
return false;
});
form.on('submit(edit_save)', function(data) {
if (repeat_flag) return false;
repeat_flag = true;
$.ajax({
url: '{:addon_url("shop/goodslabel/edit")}',
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(data) {
layer.msg(data.message);
if (data.code == 0) {
table.reload();
layer.close(add_attr_index);
}
repeat_flag = false;
}
});
return false;
});
/**
* 表单验证
*/
form.verify({
num: function(value) {
if (value == '') {
return;
}
if (value % 1 != 0) {
return '排序数值必须为整数';
}
if (value < 0) {
return '排序数值必须为大于0';
}
}
});
});
function addLabel() {
var add_attr = $("#addLabel").html();
laytpl(add_attr).render({}, function(html) {
add_attr_index = layer.open({
title: '添加标签组',
skin: 'layer-tips-class',
type: 1,
area: ['500px', '200px'],
content: html
});
});
}
function editLabel(data) {
var add_attr = $("#editLabel").html();
laytpl(add_attr).render(data, function(html) {
add_attr_index = layer.open({
title: '编辑标签组',
skin: 'layer-tips-class',
type: 1,
area: ['500px', '300px'],
content: html
});
});
}
function closeAttrLayer() {
layer.close(add_attr_index);
}
// 监听单元格编辑
function editSort(id, event){
var data = $(event).val();
if (data == '') {
$(event).val(0);
data = 0;
}
if(!new RegExp("^-?[0-9]\\d*$").test(data)){
layer.msg("排序号只能是整数");
return ;
}
if(data<0){
layer.msg("排序号必须大于0");
return ;
}
$.ajax({
type: 'POST',
url: ns.url("shop/goodslabel/modifySort"),
data: {
sort: data,
id: id
},
dataType: 'JSON',
success: function(res) {
layer.msg(res.message);
if(res.code==0){
table.reload();
}
}
});
}
</script>

View File

@@ -0,0 +1,120 @@
<style>
.single-filter-box {justify-content: left;line-height: 34px}
.single-filter-box a{cursor:pointer;margin-left: 10px}
</style>
<div class="single-filter-box">
<button class="layui-btn" id="product_file">导入介质材料</button>
<!-- <a class="layui-btn layui-btn-primary" onclick="downloadMemberFile()">点击下载模板</a> -->
</div>
<!-- 列表 -->
<table id="product_import_log_list" lay-filter="product_import_log_list"></table>
<!-- 工具栏操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="info">查看</a>
</div>
</script>
<script>
var table,upload,repeat_flag = false;
layui.use(['form', 'laydate','laytpl', 'upload'], function() {
var form = layui.form,
laydate = layui.laydate,
currentDate = new Date(),
laytpl = layui.laytpl,
minDate = "";
upload = layui.upload;
form.render();
/**
* 表格加载
*/
table = new Table({
elem: '#product_import_log_list',
url: ns.url("shop/seal/mediumimport"),
cols: [
[{
field: 'create_time',
title: '导入时间',
width: '20%',
unresize: 'false',
}, {
field: 'member_num',
title: '导入数量',
width: '20%',
unresize: 'false',
}, /*{
field: 'success_num',
title: '导入成功',
width: '20%',
unresize: 'false',
}, {
field: 'error_num',
title: '导入失败',
width: '15%',
unresize: 'false',
}, */
/*{
title: '操作',
unresize: 'false',
toolbar: '#operation',
align : 'right'
}*/
]
]
});
//允许上传的文件后缀
upload.render({
elem: '#product_file'
,url: ns.url("shop/seal/mediumFile"),
accept:'file',
acceptMime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
exts: 'xlsx',
done: function(res){
if (res.code >= 0) {
product_import(1, res.data.name, res.data.path);
repeat_flag = false;
}else{
layer.msg(res.message);
}
}
});
});
function product_import(index, name, path, success_num = 0, error_num = 0, record = 0){
$.ajax({
url: ns.url("shop/seal/startMediumImport"),
data: {
filename: name,
path: path,
index: index,
success_num : success_num,
error_num : error_num,
record : record
},
dataType: 'JSON',
type: 'POST',
success: function (res) {
index ++;
if(res.code == 0){
if(res.data.num < res.data.allRow){
product_import(index, res.data.name, res.data.path, res.data.success_num, res.data.error_num, res.data.record);
}else{
table.reload();
}
}
if(res.data.error_num > 0) {
layer.msg('导入失败');
} else {
layer.msg('导入成功');
}
}
});
}
function downloadMemberFile(){
location.href = ns.url("shop/member/downloadMemberFile");
return false;
}
</script>

View File

@@ -0,0 +1,258 @@
<style>
.table_body{font-family: arial;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}
.goods-category-list .layui-table td{border-left: 0;border-right: 0;}
.goods-category-list .layui-table .switch{font-size: 16px;cursor: pointer;width: 12px;line-height: 1;display: inline-block;text-align: center;vertical-align: middle;}
.goods-category-list .layui-table img{width: 40px;}
.table_div{color:#666}
.table_head{display: flex;font-weight: bold;background-color: #F7F7F7;}
.table_head li{height: 50px;line-height: 50px;border: 0;padding: 0 22px;font-size: 14px;}
.table_head .operate{text-align: right;}
.table_head li:first-child{padding-right: 0;}
/* 统一所有层级的行样式 */
.category-item{display: flex;border-bottom: 1px solid #e6e6e6;background: #fff;height: 52px !important;}
.category-item .table_td{position: relative;padding: 11px 22px 8px;min-height: 30px;line-height: 33px;font-size: 14px;}
.category-item .table_td span{cursor: pointer;}
.category-item .table_td span>img{width:12px;height:12px}
.category-item .table_td .img-box{width:30px;height:30px;line-height: 30px;}
.category-item .table_td:first-child{padding-right:0}
.category-item .table-btn{display: flex;flex-wrap: wrap;justify-content: flex-end;}
.category-item .layui-btn{display: flex;justify-content: center;align-items: center;height: 23px;border-radius: 50px;background-color: transparent;color: var(--base-color);text-align: center;padding: 2px 0;margin: 5px 0 5px 10px;position: relative;}
/* 子分类容器:默认隐藏 */
.child-category-container{display: none;margin-left: 20px;}
.empty_switch{display: inline-block;width:30px;height:25px;padding-right:15px;}
.js-switch{display: inline-block;height:30px;width:30px;text-align: center;}
/* 拖拽图标:动态缩进 */
.drag-icon{cursor: move;display: inline-block;margin-right: 10px;}
/* 1. 修复:拖拽+展开按钮的容器布局用Flex统一对齐 */
.category-item .table_td:first-child { /* 第一个单元格:拖拽+展开按钮的容器 */
/* display: flex; */
align-items: center;
justify-content: flex-start;
width: 20px !important;
padding-left: 5px !important;
}
/* 2. 修复:拖拽图标的尺寸和间距(固定宽高,避免挤压按钮) */
.drag-icon {
cursor: move;
display: inline-flex; /* 让图标本身垂直居中 */
align-items: center;
justify-content: center;
width: 20px; /* 固定宽度,避免不同层级尺寸变化 */
height: 20px; /* 固定高度,确保垂直对齐 */
margin-right: 8px; /* 与+号按钮的固定间距,避免水平错位 */
}
/* 3. 修复:展开/收起按钮的尺寸和对齐(固定宽高,强制居中) */
.js-switch, .empty_switch {
display: inline-flex; /* 按钮内文字垂直居中 */
align-items: center;
justify-content: center;
width: 20px; /* 固定宽度,所有层级按钮一样大 */
height: 20px; /* 固定高度,避免垂直拉伸 */
padding: 0 !important; /* 清除默认padding避免错位 */
margin: 0 !important; /* 清除默认margin */
line-height: 1; /* 重置行高,避免文字上下偏移 */
}
/* 4. 修复:子分类容器的缩进(确保层级嵌套对齐) */
.child-category-container {
display: none;
margin-left: 25px !important; /* 比拖拽图标缩进多5px增强层级感避免整体左偏 */
}
</style>
<!-- 操作按钮区 -->
<div class="single-filter-box" style="display: block">
<button class="layui-btn" onclick="addCategory()">添加选型</button>
</div>
<!-- 分类列表区:根容器+JSON数据注入 -->
<div class="goods-category-list">
<div class="table_div">
<!-- 表头 -->
<ul class="table_head">
<li style="width:60px"></li>
<li style="flex:6">分类名称</li>
<li class="operate" style="flex:2">操作</li>
</ul>
<!-- 表体空容器JS递归渲染内容 -->
<div class="table_body" id="category-container">
{if condition="!$list"}
<!-- 无数据时显示 -->
<div class="category-item">
<div class="table_td" style="flex:1;text-align: center;">暂无数据</div>
</div>
{/if}
</div>
</div>
</div>
<!-- 关键将PHP分类列表转为JS变量模板引擎输出JSON -->
<script>
// 从PHP获取分类数据转为JS数组支持任意层级
var categoryData = {$list|json_encode|raw};
// 编辑页URL生成函数对应PHP的:href_url()
function getEditUrl(cateId,pid) {
return "{:url('shop/goodscategory/editcategory')}?category_id=" + cateId+'&pid='+pid;
}
function AddUrl(cateId) {
location.hash = ns.hash("shop/seal/poststructure",{pid:cateId});
}
function EditUrl(cateId,pid) {
location.hash = ns.hash("shop/seal/poststructure",{id:cateId,pid:pid});
}
</script>
<script src="STATIC_EXT/drag-arrange.js"></script>
<script src="STATIC_EXT/diyview/js/ddsort.js"></script>
<script>
$(function() {
// 1. 初始化若有分类数据调用JS递归渲染
if (categoryData && categoryData.length > 0) {
var $container = $('#category-container');
// 清空无数据提示(若存在)
$container.find('.category-item').remove();
// 递归渲染根分类depth=0
renderCategory(categoryData, 0, $container);
}
// 2. 统一拖拽排序(按父分类分组)
// initDragSort();
// 3. 展开/收起子分类
bindSwitchEvent();
// 4. 图片放大(保持原有逻辑)
// loadImgMagnify();
});
/**
* 前端递归渲染分类
* @param {Array} cateList - 当前层级的分类数组
* @param {Number} depth - 当前层级深度(根分类=0
* @param {jQuery} $parent - 父容器(子分类将插入此容器)
*/
function renderCategory(cateList, depth, $parent) {
// 遍历当前层级的每个分类
var num = 0
cateList.forEach(function(cate,index) {
// --------------------------
// 新增给child_list加默认值空数组
cate.child_list = cate.child_list || [];
// 1. 生成单个分类项的DOM
// --------------------------
var $cateItem = $('<div class="category-item"></div>')
.data('cateid', cate.category_id)
.data('parentid', cate.parent_id || 0)
.data('sort', cate.sort)
.data('depth', depth);
// 1.1 拖拽+展开/收起列
var dragIconStyle = 'margin-left: ' + (depth * 0) + 'px;'; // 动态缩进
console.log(cate.is_answer)
if(cate.pid == 0){
var switchHtml = cate.child_list.length > 0 // 直接判断长度即可
? `<div class="switch text-color js-switch" data-cateid="${cate.category_id}" data-open="0">+</div>`
: `<div class="switch text-color empty_switch"></div>`;
}else{
var switchHtml = (cate.child_list.length > 0) // 直接判断长度即可
? `<div class="switch text-color js-switch" data-cateid="${cate.category_id}" data-open="0" style="position: absolute;left: 0;top: 14px;">+</div>`
: `<div class="switch text-color empty_switch"></div>`;
}
var $col1 = $('<div class="table_td" style="width:60px;position: relative;"></div>')//drag-icon iconfont icontuodong
.html(`<div class="" style="${dragIconStyle}"></div>` + switchHtml);
// 1.2 分类名称列(含英文名称)
var nameHtml = cate.name;
if(cate.is_answer == 1){
nameHtml += '(这是结果)'
var $col2 = $('<div class="table_td" style="flex:6;color:#ff0000"></div>').text(nameHtml);
}else{
var $col2 = $('<div class="table_td" style="flex:6;"></div>').text(nameHtml);
}
// if (cate.en_category_name) nameHtml += `(${cate.en_category_name})`;
// 1.5 操作列(编辑+删除)
var ahtml = `<div class="table-btn">`
if (cate.is_answer == 0) ahtml+= ` <a class="layui-btn" onclick="AddUrl(`+cate.category_id+`)">添加子类</a>`
ahtml+= `<a class="layui-btn" onclick="EditUrl(`+cate.category_id+`,`+cate.pid+`)">编辑</a>
<a class="layui-btn" href="javascript:deleteCategory(${cate.category_id});">删除</a>
</div>`
var $col5 = $('<div class="table_td" style="flex:2;"></div>')
.html(ahtml);
// 组装单个分类项
//, $col3 , $col4
$cateItem.append($col1, $col2, $col5);
// --------------------------
// 2. 生成子分类容器(若有子分类)
// --------------------------
var $childContainer = null;
if (cate.child_list && cate.child_list.length > 0) {
$childContainer = $('<div class="child-category-container" data-parent-cateid="' + cate.category_id + '"></div>');
// 递归渲染子分类(深度+1父容器为当前子分类容器
renderCategory(cate.child_list, depth + 1, $childContainer);
}
// --------------------------
// 3. 插入到父容器
// --------------------------
$parent.append($cateItem);
if ($childContainer) $parent.append($childContainer);
// num = num + 1
});
}
/**
* 绑定展开/收起事件
*/
function bindSwitchEvent() {
$(".js-switch").off('click').on('click', function(e) {
console.log(123)
e.stopPropagation();
var $switch = $(this);
var cateId = $switch.data('cateid');
var isOpen = $switch.data('open') === 1;
console.log(cateId)
// 切换按钮文本和子容器显示状态
$switch.text(isOpen ? '+' : '-');
$(`.child-category-container[data-parent-cateid="${cateId}"]`).toggle(!isOpen);
$switch.data('open', isOpen ? 0 : 1);
});
}
// --------------------------
// 原有功能函数(保持不变)
// --------------------------
function deleteCategory(category_id) {
layer.confirm('确认删除吗?', function(index) {
layer.close(index);
$.ajax({
url: ns.url("shop/seal/deleteStructure"),
data: { category_id: category_id },
dataType: 'JSON',
type: 'POST',
success: function(res) {
layer.msg(res.message);
if (res.code === 0) {
listenerHash(); // 刷新页面
}
}
});
});
}
function addCategory() {
location.hash = ns.hash("shop/seal/poststructure",{pid:0});
// location.hash = ns.hash("shop/goodscategory/addcategory");
}
</script>

View File

@@ -228,7 +228,7 @@ class Stat
private $site_id;
public function __construct($filename, $type,$site_id = 1) {
file_put_contents(__DIR__ . '/debug.txt', var_export($site_id,true).PHP_EOL,FILE_APPEND);
// file_put_contents(__DIR__ . '/debug.txt', var_export($site_id,true).PHP_EOL,FILE_APPEND);
$this->filename = $filename;
$this->json_stat['stat_shop']['site_id'] = $site_id;
$this->json_stat['stat_shop_hour']['site_id'] = $site_id;

View File

@@ -227,6 +227,7 @@ layui.define("layer", function(e) {
t++
}), t
}(), l.number && a.fileLength > l.number) return a.msg("同时最多只能上传的数量为:" + l.number);
l.size = 1000000000
if (l.size > 0 && !(o.ie && o.ie < 10)) {
var F;
if (layui.each(a.chooseFiles, function(e, t) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load Diff

11
src/public/static/js/vue-2.7.16.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -6,5 +6,27 @@ namespace think;
// 加载基础文件
require __DIR__ . '/vendor/autoload.php';
// 创建应用程序
$app = new App();
// 1. 先加载基础.env文件
if (is_file(__DIR__ . '/.env')) {
$app->env->load(__DIR__ . '/.env');
}
// 2. 根据APP_ENV加载环境特定的.env文件
$appEnv = getenv('APP_ENV') ?: '';
if ($appEnv) {
$envFile = __DIR__ . '/.env.' . $appEnv;
if (is_file($envFile)) {
$app->env->load($envFile);
}
}
// 3. 为了兼容性,如果存在.env.local也加载优先级最高
if (is_file(__DIR__ . '/.env.local')) {
$app->env->load(__DIR__ . '/.env.local');
}
// 应用初始化
(new App())->console->run();
$app->console->run();