Merge remote-tracking branch 'origin/master'
# Conflicts: # .env-example
This commit is contained in:
@@ -8,7 +8,7 @@ APP_DEFAULT_TIMEZONE = Asia/Shanghai
|
|||||||
# 语言
|
# 语言
|
||||||
LANG_DEFAULT_LANG = zh-cn
|
LANG_DEFAULT_LANG = zh-cn
|
||||||
|
|
||||||
# 数据库(config/thinkorm.php)
|
# 数据库(config/thinkorm.php/database.php)
|
||||||
DATABASE_DRIVER = mysql
|
DATABASE_DRIVER = mysql
|
||||||
DATABASE_TYPE = mysql
|
DATABASE_TYPE = mysql
|
||||||
DATABASE_HOSTNAME = 127.0.0.1
|
DATABASE_HOSTNAME = 127.0.0.1
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -159,25 +159,33 @@ php webman migrate
|
|||||||
|
|
||||||
### 5.5 启动
|
### 5.5 启动
|
||||||
|
|
||||||
**Linux / Mac:**
|
**开发环境需同时启动后端与前端:**
|
||||||
|
|
||||||
|
1. **启动后端(API 服务,端口 8787):**
|
||||||
|
|
||||||
|
**Linux / Mac:**
|
||||||
```bash
|
```bash
|
||||||
php start.php start
|
php start.php start
|
||||||
```
|
```
|
||||||
|
|
||||||
**Windows:**
|
**Windows:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php windows.php
|
php windows.php
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.6 前端开发
|
2. **启动前端(Vue 开发服务,端口 1818):**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd web
|
cd web
|
||||||
pnpm dev
|
pnpm dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
3. **访问地址:**
|
||||||
|
- 安装向导:http://localhost:1818/install/
|
||||||
|
- 前台地址:http://localhost:1818/index.html/#/
|
||||||
|
- 后台地址:http://localhost:1818/index.html/#/admin
|
||||||
|
|
||||||
|
> 注意:前端通过 Vite 代理将 `/api`、`/admin`、`/install` 转发到后端 8787 端口,请勿直接访问 8787 端口的前端页面,否则可能出现 404。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 六、路由说明
|
## 六、路由说明
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use support\think\Db;
|
use support\think\Db;
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ use support\think\Db;
|
|||||||
*/
|
*/
|
||||||
class Admin extends Model
|
class Admin extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'admin';
|
protected string $table = 'admin';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,6 +12,8 @@ use support\think\Model;
|
|||||||
*/
|
*/
|
||||||
class AdminGroup extends Model
|
class AdminGroup extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'admin_group';
|
protected string $table = 'admin_group';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace app\admin\model;
|
|||||||
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use app\admin\library\Auth;
|
use app\admin\library\Auth;
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use Webman\Http\Request;
|
use Webman\Http\Request;
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ use Webman\Http\Request;
|
|||||||
*/
|
*/
|
||||||
class AdminLog extends Model
|
class AdminLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'admin_log';
|
protected string $table = 'admin_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class AdminRule extends Model
|
class AdminRule extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'admin_rule';
|
protected string $table = 'admin_rule';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,6 +12,8 @@ use support\think\Model;
|
|||||||
*/
|
*/
|
||||||
class Config extends Model
|
class Config extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
public static string $cacheTag = 'sys_config';
|
public static string $cacheTag = 'sys_config';
|
||||||
|
|
||||||
protected string $table = 'config';
|
protected string $table = 'config';
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ class CrudLog extends Model
|
|||||||
protected bool $updateTime = false;
|
protected bool $updateTime = false;
|
||||||
|
|
||||||
protected array $type = [
|
protected array $type = [
|
||||||
|
'create_time' => 'integer',
|
||||||
|
'update_time' => 'integer',
|
||||||
'table' => 'array',
|
'table' => 'array',
|
||||||
'fields' => 'array',
|
'fields' => 'array',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class DataRecycle extends Model
|
class DataRecycle extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'security_data_recycle';
|
protected string $table = 'security_data_recycle';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class DataRecycleLog extends Model
|
class DataRecycleLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'security_data_recycle_log';
|
protected string $table = 'security_data_recycle_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ class SensitiveData extends Model
|
|||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|
||||||
protected array $type = [
|
protected array $type = [
|
||||||
|
'create_time' => 'integer',
|
||||||
|
'update_time' => 'integer',
|
||||||
'data_fields' => 'array',
|
'data_fields' => 'array',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class SensitiveDataLog extends Model
|
class SensitiveDataLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'security_sensitive_data_log';
|
protected string $table = 'security_sensitive_data_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class User extends Model
|
class User extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user';
|
protected string $table = 'user';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class UserGroup extends Model
|
class UserGroup extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_group';
|
protected string $table = 'user_group';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class UserMoneyLog extends Model
|
class UserMoneyLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_money_log';
|
protected string $table = 'user_money_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class UserRule extends Model
|
class UserRule extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_rule';
|
protected string $table = 'user_rule';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class UserScoreLog extends Model
|
class UserScoreLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_score_log';
|
protected string $table = 'user_score_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace app\admin\model\mall;
|
namespace app\admin\model\mall;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,6 +10,8 @@ use support\think\Model;
|
|||||||
*/
|
*/
|
||||||
class Player extends Model
|
class Player extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
// 表名
|
// 表名
|
||||||
protected $name = 'mall_player';
|
protected $name = 'mall_player';
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ use app\admin\model\Admin as AdminModel;
|
|||||||
use app\admin\model\User as UserModel;
|
use app\admin\model\User as UserModel;
|
||||||
use support\Response;
|
use support\Response;
|
||||||
use Webman\Http\Request;
|
use Webman\Http\Request;
|
||||||
|
use Phinx\Config\Config as PhinxConfig;
|
||||||
|
use Phinx\Migration\Manager as PhinxManager;
|
||||||
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
|
use Symfony\Component\Console\Output\NullOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 安装控制器
|
* 安装控制器
|
||||||
@@ -74,7 +78,7 @@ class Install extends Api
|
|||||||
{
|
{
|
||||||
$this->setRequest($request);
|
$this->setRequest($request);
|
||||||
if ($this->isInstallComplete()) {
|
if ($this->isInstallComplete()) {
|
||||||
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]));
|
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %file% file first', ['%file%' => 'public/' . self::$lockFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
(new Terminal())->exec(false);
|
(new Terminal())->exec(false);
|
||||||
@@ -85,7 +89,7 @@ class Install extends Api
|
|||||||
{
|
{
|
||||||
$this->setRequest($request);
|
$this->setRequest($request);
|
||||||
if ($this->isInstallComplete()) {
|
if ($this->isInstallComplete()) {
|
||||||
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]));
|
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %file% file first', ['%file%' => 'public/' . self::$lockFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$newPackageManager = $request->post('manager', config('terminal.npm_package_manager'));
|
$newPackageManager = $request->post('manager', config('terminal.npm_package_manager'));
|
||||||
@@ -104,7 +108,7 @@ class Install extends Api
|
|||||||
{
|
{
|
||||||
$this->setRequest($request);
|
$this->setRequest($request);
|
||||||
if ($this->isInstallComplete()) {
|
if ($this->isInstallComplete()) {
|
||||||
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]), []);
|
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %file% file first', ['%file%' => 'public/' . self::$lockFileName]), []);
|
||||||
}
|
}
|
||||||
if (($_ENV['DATABASE_TYPE'] ?? getenv('DATABASE_TYPE'))) {
|
if (($_ENV['DATABASE_TYPE'] ?? getenv('DATABASE_TYPE'))) {
|
||||||
return $this->error(__('The .env file with database configuration was detected. Please clean up and try again!'));
|
return $this->error(__('The .env file with database configuration was detected. Please clean up and try again!'));
|
||||||
@@ -410,7 +414,7 @@ class Install extends Api
|
|||||||
{
|
{
|
||||||
$this->setRequest($request);
|
$this->setRequest($request);
|
||||||
if ($this->isInstallComplete()) {
|
if ($this->isInstallComplete()) {
|
||||||
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]));
|
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %file% file first', ['%file%' => 'public/' . self::$lockFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$envOk = $this->commandExecutionCheck();
|
$envOk = $this->commandExecutionCheck();
|
||||||
@@ -456,27 +460,32 @@ class Install extends Api
|
|||||||
return $this->error(__('File has no write permission:%s', ['config/' . self::$dbConfigFileName]));
|
return $this->error(__('File has no write permission:%s', ['config/' . self::$dbConfigFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入 dafuweng-webman/.env-example
|
// 写入 .env 和 .env-example(仅使用 Dotenv 可解析的 DATABASE_XXX 格式,避免 [DATABASE] 导致解析失败)
|
||||||
$envFile = root_path() . '.env-example';
|
$databaseBlock = "\n# Database\n"
|
||||||
$envFileContent = @file_get_contents($envFile);
|
. 'DATABASE_TYPE = mysql' . "\n"
|
||||||
if ($envFileContent) {
|
. 'DATABASE_HOSTNAME = ' . $databaseParam['hostname'] . "\n"
|
||||||
$databasePos = stripos($envFileContent, '[DATABASE]');
|
. 'DATABASE_DATABASE = ' . $databaseParam['database'] . "\n"
|
||||||
if ($databasePos !== false) {
|
. 'DATABASE_USERNAME = ' . $databaseParam['username'] . "\n"
|
||||||
$envFileContent = substr($envFileContent, 0, $databasePos);
|
. 'DATABASE_PASSWORD = ' . $databaseParam['password'] . "\n"
|
||||||
|
. 'DATABASE_HOSTPORT = ' . $databaseParam['hostport'] . "\n"
|
||||||
|
. 'DATABASE_CHARSET = utf8mb4' . "\n"
|
||||||
|
. 'DATABASE_PREFIX = ' . ($databaseParam['prefix'] ?? '') . "\n";
|
||||||
|
foreach (['.env', '.env-example'] as $envName) {
|
||||||
|
$envFile = root_path() . $envName;
|
||||||
|
$envFileContent = is_file($envFile) ? @file_get_contents($envFile) : '';
|
||||||
|
if ($envFileContent !== false) {
|
||||||
|
$cutPos = strlen($envFileContent);
|
||||||
|
foreach (['[DATABASE]', "\n# Database\n", "\n# 数据库", "\nDATABASE_DRIVER", "\nDATABASE_TYPE"] as $marker) {
|
||||||
|
$pos = stripos($envFileContent, $marker);
|
||||||
|
if ($pos !== false && $pos < $cutPos) {
|
||||||
|
$cutPos = $pos;
|
||||||
}
|
}
|
||||||
$envFileContent .= "\n" . '[DATABASE]' . "\n";
|
}
|
||||||
$envFileContent .= 'TYPE = mysql' . "\n";
|
$envFileContent = rtrim(substr($envFileContent, 0, $cutPos)) . $databaseBlock;
|
||||||
$envFileContent .= 'HOSTNAME = ' . $databaseParam['hostname'] . "\n";
|
|
||||||
$envFileContent .= 'DATABASE = ' . $databaseParam['database'] . "\n";
|
|
||||||
$envFileContent .= 'USERNAME = ' . $databaseParam['username'] . "\n";
|
|
||||||
$envFileContent .= 'PASSWORD = ' . $databaseParam['password'] . "\n";
|
|
||||||
$envFileContent .= 'HOSTPORT = ' . $databaseParam['hostport'] . "\n";
|
|
||||||
$envFileContent .= 'PREFIX = ' . ($databaseParam['prefix'] ?? '') . "\n";
|
|
||||||
$envFileContent .= 'CHARSET = utf8mb4' . "\n";
|
|
||||||
$envFileContent .= 'DEBUG = true' . "\n";
|
|
||||||
$result = @file_put_contents($envFile, $envFileContent);
|
$result = @file_put_contents($envFile, $envFileContent);
|
||||||
if (!$result) {
|
if (!$result && is_file($envFile)) {
|
||||||
return $this->error(__('File has no write permission:%s', ['/' . $envFile]));
|
return $this->error(__('File has no write permission:%s', ['%s' => $envName]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,13 +509,66 @@ class Install extends Api
|
|||||||
return $this->error(__('File has no write permission:%s', ['public/' . self::$lockFileName]));
|
return $this->error(__('File has no write permission:%s', ['public/' . self::$lockFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动执行数据库迁移(无需手动运行 phinx 命令)
|
||||||
|
$migrateResult = $this->runPhinxMigrate($databaseParam);
|
||||||
|
if ($migrateResult !== true) {
|
||||||
|
return $this->error($migrateResult);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->success('', [
|
return $this->success('', [
|
||||||
'rootPath' => $rootPath,
|
'rootPath' => $rootPath,
|
||||||
'executionWebCommand' => $envOk,
|
'executionWebCommand' => $envOk,
|
||||||
'migrateCommand' => $migrateCommand,
|
'migrateCommand' => $migrateCommand,
|
||||||
|
'migrationCompleted' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 程序化执行 Phinx 数据库迁移
|
||||||
|
* @param array $databaseParam 数据库连接参数
|
||||||
|
* @return true|string 成功返回 true,失败返回错误信息
|
||||||
|
*/
|
||||||
|
private function runPhinxMigrate(array $databaseParam): true|string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$baseDir = root_path();
|
||||||
|
$phinxConfigPath = $baseDir . 'phinx.php';
|
||||||
|
|
||||||
|
if (!is_file($phinxConfigPath)) {
|
||||||
|
return __('Failed to install SQL execution:%msg%', ['%msg%' => 'phinx.php not found']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 临时设置环境变量,供 phinx 读取数据库配置
|
||||||
|
$_ENV['DATABASE_HOSTNAME'] = $databaseParam['hostname'] ?? '127.0.0.1';
|
||||||
|
$_ENV['DATABASE_DATABASE'] = $databaseParam['database'] ?? '';
|
||||||
|
$_ENV['DATABASE_USERNAME'] = $databaseParam['username'] ?? 'root';
|
||||||
|
$_ENV['DATABASE_PASSWORD'] = $databaseParam['password'] ?? '';
|
||||||
|
$_ENV['DATABASE_HOSTPORT'] = $databaseParam['hostport'] ?? '3306';
|
||||||
|
$_ENV['DATABASE_PREFIX'] = $databaseParam['prefix'] ?? '';
|
||||||
|
putenv('DATABASE_HOSTNAME=' . $_ENV['DATABASE_HOSTNAME']);
|
||||||
|
putenv('DATABASE_DATABASE=' . $_ENV['DATABASE_DATABASE']);
|
||||||
|
putenv('DATABASE_USERNAME=' . $_ENV['DATABASE_USERNAME']);
|
||||||
|
putenv('DATABASE_PASSWORD=' . $_ENV['DATABASE_PASSWORD']);
|
||||||
|
putenv('DATABASE_HOSTPORT=' . $_ENV['DATABASE_HOSTPORT']);
|
||||||
|
putenv('DATABASE_PREFIX=' . $_ENV['DATABASE_PREFIX']);
|
||||||
|
|
||||||
|
$config = PhinxConfig::fromPhp($phinxConfigPath);
|
||||||
|
$input = new ArrayInput([]);
|
||||||
|
$output = new NullOutput();
|
||||||
|
$manager = new PhinxManager($config, $input, $output);
|
||||||
|
|
||||||
|
$environment = $config->getDefaultEnvironment();
|
||||||
|
$manager->migrate($environment);
|
||||||
|
return true;
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
if ($e->getPrevious()) {
|
||||||
|
$msg .= ' | ' . $e->getPrevious()->getMessage();
|
||||||
|
}
|
||||||
|
return __('Failed to install SQL execution:%msg%', ['%msg%' => $msg]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function isInstallComplete(): bool
|
protected function isInstallComplete(): bool
|
||||||
{
|
{
|
||||||
if (is_file(public_path(self::$lockFileName))) {
|
if (is_file(public_path(self::$lockFileName))) {
|
||||||
@@ -526,7 +588,7 @@ class Install extends Api
|
|||||||
{
|
{
|
||||||
$this->setRequest($request);
|
$this->setRequest($request);
|
||||||
if ($this->isInstallComplete()) {
|
if ($this->isInstallComplete()) {
|
||||||
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]));
|
return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %file% file first', ['%file%' => 'public/' . self::$lockFileName]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$param = $request->only(['type', 'adminname', 'adminpassword', 'sitename']);
|
$param = $request->only(['type', 'adminname', 'adminpassword', 'sitename']);
|
||||||
@@ -586,6 +648,36 @@ class Install extends Api
|
|||||||
return $envOk;
|
return $envOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取安装完成后的访问地址(根据请求来源区分 API 与前端开发模式)
|
||||||
|
* - 通过 API 访问(8787):index.html#/admin、index.html#/
|
||||||
|
* - 通过前端开发服务访问(1818):/#/admin、/#/
|
||||||
|
*/
|
||||||
|
public function accessUrls(Request $request): Response
|
||||||
|
{
|
||||||
|
$this->setRequest($request);
|
||||||
|
$host = $request->header('host', '127.0.0.1:8787');
|
||||||
|
$port = '8787';
|
||||||
|
if (str_contains($host, ':')) {
|
||||||
|
$port = substr($host, strrpos($host, ':') + 1);
|
||||||
|
}
|
||||||
|
$scheme = $request->header('x-forwarded-proto', 'http');
|
||||||
|
$base = rtrim($scheme . '://' . $host, '/');
|
||||||
|
|
||||||
|
if ($port === '1818') {
|
||||||
|
$adminUrl = $base . '/#/admin';
|
||||||
|
$frontUrl = $base . '/#/';
|
||||||
|
} else {
|
||||||
|
$adminUrl = $base . '/index.html#/admin';
|
||||||
|
$frontUrl = $base . '/index.html#/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success('', [
|
||||||
|
'adminUrl' => $adminUrl,
|
||||||
|
'frontUrl' => $frontUrl,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 安装指引
|
* 安装指引
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ return [
|
|||||||
'already installed' => 'Installed',
|
'already installed' => 'Installed',
|
||||||
'Not installed' => 'Not installed',
|
'Not installed' => 'Not installed',
|
||||||
'File has no write permission:%s' => 'File has no write permission:%s',
|
'File has no write permission:%s' => 'File has no write permission:%s',
|
||||||
'The system has completed installation. If you need to reinstall, please delete the %s file first' => 'The system has been installed, if you need to reinstall, please delete the %s file first.',
|
'The system has completed installation. If you need to reinstall, please delete the %file% file first' => 'The system has been installed. If you need to reinstall, please delete the %file% file first.',
|
||||||
'Database connection failed:%s' => 'Database connection failure:%s',
|
'Database connection failed:%s' => 'Database connection failure:%s',
|
||||||
'Failed to install SQL execution:%s' => 'Installation SQL execution failed:%s',
|
'Failed to install SQL execution:%msg%' => 'Installation SQL execution failed: %msg%',
|
||||||
'unknown' => 'Unknown',
|
'unknown' => 'Unknown',
|
||||||
'Database does not exist' => 'Database does not exist!',
|
'Database does not exist' => 'Database does not exist!',
|
||||||
'No built front-end file found, please rebuild manually!' => 'No built front-end file found, please rebuild manually.',
|
'No built front-end file found, please rebuild manually!' => 'No built front-end file found, please rebuild manually.',
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ return [
|
|||||||
'already installed' => '已安装',
|
'already installed' => '已安装',
|
||||||
'Not installed' => '未安装',
|
'Not installed' => '未安装',
|
||||||
'File has no write permission:%s' => '文件无写入权限:%s',
|
'File has no write permission:%s' => '文件无写入权限:%s',
|
||||||
'The system has completed installation. If you need to reinstall, please delete the %s file first' => '系统已完成安装。如果需要重新安装,请先删除 %s 文件',
|
'The system has completed installation. If you need to reinstall, please delete the %file% file first' => '系统已完成安装。如果需要重新安装,请先删除 %file% 文件',
|
||||||
'Database connection failed:%s' => '数据库连接失败:%s',
|
'Database connection failed:%s' => '数据库连接失败:%s',
|
||||||
'Failed to install SQL execution:%s' => '安装SQL执行失败:%s',
|
'Failed to install SQL execution:%msg%' => '安装SQL执行失败:%msg%',
|
||||||
'unknown' => '未知',
|
'unknown' => '未知',
|
||||||
'Database does not exist' => '数据库不存在!',
|
'Database does not exist' => '数据库不存在!',
|
||||||
'No built front-end file found, please rebuild manually!' => '没有找到构建好的前端文件,请手动重新构建!',
|
'No built front-end file found, please rebuild manually!' => '没有找到构建好的前端文件,请手动重新构建!',
|
||||||
|
|||||||
@@ -26,12 +26,20 @@ class LoadLangPack implements MiddlewareInterface
|
|||||||
protected function loadLang(Request $request): void
|
protected function loadLang(Request $request): void
|
||||||
{
|
{
|
||||||
// 优先从请求头 think-lang 获取前端选择的语言(与前端 axios 发送的 header 对应)
|
// 优先从请求头 think-lang 获取前端选择的语言(与前端 axios 发送的 header 对应)
|
||||||
|
// 安装页等未发送 think-lang 时,回退到 Accept-Language 或配置默认值
|
||||||
$headerLang = $request->header('think-lang');
|
$headerLang = $request->header('think-lang');
|
||||||
$allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);
|
$allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);
|
||||||
if ($headerLang && in_array(str_replace('_', '-', strtolower($headerLang)), $allowLangList)) {
|
if ($headerLang && in_array(str_replace('_', '-', strtolower($headerLang)), $allowLangList)) {
|
||||||
$langSet = str_replace('_', '-', strtolower($headerLang));
|
$langSet = str_replace('_', '-', strtolower($headerLang));
|
||||||
|
} else {
|
||||||
|
$acceptLang = $request->header('accept-language', '');
|
||||||
|
if (preg_match('/^zh[-_]?cn|^zh/i', $acceptLang)) {
|
||||||
|
$langSet = 'zh-cn';
|
||||||
|
} elseif (preg_match('/^en/i', $acceptLang)) {
|
||||||
|
$langSet = 'en';
|
||||||
} else {
|
} else {
|
||||||
$langSet = config('lang.default_lang', config('translation.locale', 'zh-cn'));
|
$langSet = config('lang.default_lang', config('translation.locale', 'zh-cn'));
|
||||||
|
}
|
||||||
$langSet = str_replace('_', '-', strtolower($langSet));
|
$langSet = str_replace('_', '-', strtolower($langSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +67,7 @@ class LoadLangPack implements MiddlewareInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. 加载控制器专用语言包(如 zh-cn/auth/group.php),供 get_route_remark 等使用
|
// 2. 加载控制器专用语言包(如 zh-cn/auth/group.php),供 get_route_remark 等使用
|
||||||
|
// 同时加载到 messages 域,使 __() 能正确翻译控制器内的文案(如安装页错误提示)
|
||||||
$controllerPath = get_controller_path($request);
|
$controllerPath = get_controller_path($request);
|
||||||
if ($controllerPath) {
|
if ($controllerPath) {
|
||||||
$controllerPathForFile = str_replace('.', '/', $controllerPath);
|
$controllerPathForFile = str_replace('.', '/', $controllerPath);
|
||||||
@@ -68,6 +77,7 @@ class LoadLangPack implements MiddlewareInterface
|
|||||||
$controllerLangFile = $appLangDir . $langSet . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $controllerPathForFile) . '.php';
|
$controllerLangFile = $appLangDir . $langSet . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $controllerPathForFile) . '.php';
|
||||||
if (is_file($controllerLangFile)) {
|
if (is_file($controllerLangFile)) {
|
||||||
$translator->addResource('phpfile', $controllerLangFile, $langSet, $controllerPath);
|
$translator->addResource('phpfile', $controllerLangFile, $langSet, $controllerPath);
|
||||||
|
$translator->addResource('phpfile', $controllerLangFile, $langSet, 'messages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\common\model;
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
use think\model\relation\BelongsTo;
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class Attachment extends Model
|
class Attachment extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'attachment';
|
protected string $table = 'attachment';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace app\common\model;
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,6 +10,8 @@ use support\think\Model;
|
|||||||
*/
|
*/
|
||||||
class User extends Model
|
class User extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user';
|
protected string $table = 'user';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
namespace app\common\model;
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class UserMoneyLog extends Model
|
class UserMoneyLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_money_log';
|
protected string $table = 'user_money_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
namespace app\common\model;
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use app\common\model\traits\TimestampInteger;
|
||||||
use support\think\Model;
|
use support\think\Model;
|
||||||
|
|
||||||
class UserScoreLog extends Model
|
class UserScoreLog extends Model
|
||||||
{
|
{
|
||||||
|
use TimestampInteger;
|
||||||
|
|
||||||
protected string $table = 'user_score_log';
|
protected string $table = 'user_score_log';
|
||||||
protected string $pk = 'id';
|
protected string $pk = 'id';
|
||||||
protected bool $autoWriteTimestamp = true;
|
protected bool $autoWriteTimestamp = true;
|
||||||
|
|||||||
25
app/common/model/traits/TimestampInteger.php
Normal file
25
app/common/model/traits/TimestampInteger.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\common\model\traits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳整型字段修复
|
||||||
|
*
|
||||||
|
* ThinkORM 对 MySQL bigint 类型识别为 'bigint',自动时间戳会错误地写入 'now' 字符串,
|
||||||
|
* 导致 SQLSTATE[HY000]: General error: 1366 Incorrect integer value: 'now' for column 'update_time'
|
||||||
|
*
|
||||||
|
* 通过显式指定 create_time、update_time 等为 integer 类型,使 ThinkORM 使用 time() 写入正确的时间戳。
|
||||||
|
*/
|
||||||
|
trait TimestampInteger
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 字段类型映射:将 bigint 时间戳字段显式声明为 integer,避免 ThinkORM 写入 'now' 字符串
|
||||||
|
*/
|
||||||
|
protected array $type = [
|
||||||
|
'create_time' => 'integer',
|
||||||
|
'update_time' => 'integer',
|
||||||
|
'last_login_time' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ return [
|
|||||||
// 默认驱动方式
|
// 默认驱动方式
|
||||||
'default' => 'mysql',
|
'default' => 'mysql',
|
||||||
// 加密key
|
// 加密key
|
||||||
'key' => '5u9HTYBPXId3i6K4S2Q08wWRVFxCENLU',
|
'key' => 'L1iYVS0PChKA9pjcFdmOGb4zfDIHo5xw',
|
||||||
// 加密方式
|
// 加密方式
|
||||||
'algo' => 'ripemd160',
|
'algo' => 'ripemd160',
|
||||||
// 驱动
|
// 驱动
|
||||||
|
|||||||
@@ -35,16 +35,30 @@ Route::get('/index.html', function () use ($installLockFile, $installCompleteMar
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ==================== 安装向导(静态页) ====================
|
// ==================== 安装向导(静态页) ====================
|
||||||
// /install、/install/、/install/index 均返回 public/install/index.html
|
// 已安装时访问 /install 重定向到应用,访问提示仅在终端显示
|
||||||
Route::get('/install', function () {
|
$installLockFileForInstall = public_path('install.lock');
|
||||||
|
$installCompleteMarkForInstall = 'install-end';
|
||||||
|
Route::get('/install', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) {
|
||||||
|
$installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall;
|
||||||
|
if ($installed && is_file(public_path('index.html'))) {
|
||||||
|
return new Response(302, ['Location' => '/index.html']);
|
||||||
|
}
|
||||||
$file = public_path('install/index.html');
|
$file = public_path('install/index.html');
|
||||||
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
||||||
});
|
});
|
||||||
Route::get('/install/', function () {
|
Route::get('/install/', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) {
|
||||||
|
$installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall;
|
||||||
|
if ($installed && is_file(public_path('index.html'))) {
|
||||||
|
return new Response(302, ['Location' => '/index.html']);
|
||||||
|
}
|
||||||
$file = public_path('install/index.html');
|
$file = public_path('install/index.html');
|
||||||
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
||||||
});
|
});
|
||||||
Route::get('/install/index', function () {
|
Route::get('/install/index', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) {
|
||||||
|
$installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall;
|
||||||
|
if ($installed && is_file(public_path('index.html'))) {
|
||||||
|
return new Response(302, ['Location' => '/index.html']);
|
||||||
|
}
|
||||||
$file = public_path('install/index.html');
|
$file = public_path('install/index.html');
|
||||||
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found');
|
||||||
});
|
});
|
||||||
@@ -65,6 +79,7 @@ Route::get('/api/install/envBaseCheck', [\app\api\controller\Install::class, 'en
|
|||||||
Route::add(['GET', 'POST'], '/api/install/envNpmCheck', [\app\api\controller\Install::class, 'envNpmCheck']);
|
Route::add(['GET', 'POST'], '/api/install/envNpmCheck', [\app\api\controller\Install::class, 'envNpmCheck']);
|
||||||
Route::post('/api/install/testDatabase', [\app\api\controller\Install::class, 'testDatabase']);
|
Route::post('/api/install/testDatabase', [\app\api\controller\Install::class, 'testDatabase']);
|
||||||
Route::add(['GET', 'POST'], '/api/install/baseConfig', [\app\api\controller\Install::class, 'baseConfig']);
|
Route::add(['GET', 'POST'], '/api/install/baseConfig', [\app\api\controller\Install::class, 'baseConfig']);
|
||||||
|
Route::get('/api/install/accessUrls', [\app\api\controller\Install::class, 'accessUrls']);
|
||||||
Route::post('/api/install/commandExecComplete', [\app\api\controller\Install::class, 'commandExecComplete']);
|
Route::post('/api/install/commandExecComplete', [\app\api\controller\Install::class, 'commandExecComplete']);
|
||||||
Route::post('/api/install/manualInstall', [\app\api\controller\Install::class, 'manualInstall']);
|
Route::post('/api/install/manualInstall', [\app\api\controller\Install::class, 'manualInstall']);
|
||||||
Route::post('/api/install/mvDist', [\app\api\controller\Install::class, 'mvDist']);
|
Route::post('/api/install/mvDist', [\app\api\controller\Install::class, 'mvDist']);
|
||||||
|
|||||||
@@ -5,6 +5,46 @@
|
|||||||
<link rel="icon" href="/install/favicon.ico" />
|
<link rel="icon" href="/install/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>BuildAdmin-安装</title>
|
<title>BuildAdmin-安装</title>
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
var urls = { adminUrl: '', frontUrl: '' };
|
||||||
|
fetch('/api/install/accessUrls').then(function(r){return r.json();}).then(function(res){
|
||||||
|
if (res && res.data) { urls.adminUrl = res.data.adminUrl || ''; urls.frontUrl = res.data.frontUrl || ''; }
|
||||||
|
}).catch(function(){});
|
||||||
|
function applyUrls() {
|
||||||
|
if (!urls.adminUrl && !urls.frontUrl) return;
|
||||||
|
document.querySelectorAll('input[type="text"], input:not([type])').forEach(function(inp){
|
||||||
|
var v = (inp.value || '').trim();
|
||||||
|
if (v && (v.indexOf('#/admin') >= 0 || v.indexOf('index.html') >= 0) && v.indexOf('#/') >= 0) {
|
||||||
|
inp.value = urls.adminUrl;
|
||||||
|
inp.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.querySelectorAll('a[href*="#/admin"]').forEach(function(a){ if (urls.adminUrl) a.href = urls.adminUrl; });
|
||||||
|
document.querySelectorAll('a[href*="#/"]').forEach(function(a){
|
||||||
|
if (urls.frontUrl && a.href.indexOf('#/admin') < 0) a.href = urls.frontUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setInterval(applyUrls, 800); });
|
||||||
|
else setInterval(applyUrls, 800);
|
||||||
|
})();
|
||||||
|
(function(){
|
||||||
|
function closeMigrateModal() {
|
||||||
|
if (!document.body) return;
|
||||||
|
var txt = document.body.innerText || document.body.textContent || '';
|
||||||
|
if (txt.indexOf('数据表迁移失败') < 0 && txt.indexOf('数据表自动迁移失败') < 0) return;
|
||||||
|
var btns = document.body.querySelectorAll('button, [role="button"], .el-button');
|
||||||
|
for (var i = 0; i < btns.length; i++) {
|
||||||
|
var b = btns[i];
|
||||||
|
if (b.textContent && b.textContent.indexOf('继续安装') >= 0) { b.click(); return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var obs = new MutationObserver(closeMigrateModal);
|
||||||
|
function start() { if (document.body) { obs.observe(document.body, { childList: true, subtree: true }); closeMigrateModal(); } }
|
||||||
|
if (document.body) start(); else document.addEventListener('DOMContentLoaded', start);
|
||||||
|
setInterval(closeMigrateModal, 150);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<script type="module" crossorigin src="/install/assets/index.js"></script>
|
<script type="module" crossorigin src="/install/assets/index.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/install/assets/index.css">
|
<link rel="stylesheet" crossorigin href="/install/assets/index.css">
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { loading } from '/@/utils/loading'
|
|||||||
import langAutoLoadMap from '/@/lang/autoload'
|
import langAutoLoadMap from '/@/lang/autoload'
|
||||||
import { mergeMessage } from '/@/lang/index'
|
import { mergeMessage } from '/@/lang/index'
|
||||||
import { useConfig } from '/@/stores/config'
|
import { useConfig } from '/@/stores/config'
|
||||||
|
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||||
import { isAdminApp } from '/@/utils/common'
|
import { isAdminApp } from '/@/utils/common'
|
||||||
import { uniq } from 'lodash-es'
|
import { uniq } from 'lodash-es'
|
||||||
|
|
||||||
@@ -16,6 +17,17 @@ const router = createRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
|
// 后台路由鉴权:未登录时访问 /admin 或 /admin/*(除 /admin/login)则跳转登录页
|
||||||
|
const isAdminRoute = to.path === adminBaseRoutePath || to.path.startsWith(adminBaseRoutePath + '/')
|
||||||
|
const isAdminLogin = to.path === adminBaseRoutePath + '/login'
|
||||||
|
if (isAdminRoute && !isAdminLogin) {
|
||||||
|
const adminInfo = useAdminInfo()
|
||||||
|
if (!adminInfo.token) {
|
||||||
|
next({ name: 'adminLogin' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false })
|
NProgress.configure({ showSpinner: false })
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
if (!window.existLoading) {
|
if (!window.existLoading) {
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ const viteConfig = ({ mode }: ConfigEnv): UserConfig => {
|
|||||||
server: {
|
server: {
|
||||||
port: parseInt(VITE_PORT),
|
port: parseInt(VITE_PORT),
|
||||||
open: VITE_OPEN != 'false',
|
open: VITE_OPEN != 'false',
|
||||||
// 开发时把 /api、/admin 代理到 webman,避免跨域
|
// 开发时把 /api、/admin、/install 代理到 webman,避免跨域
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': { target: 'http://localhost:8787', changeOrigin: true },
|
'/api': { target: 'http://localhost:8787', changeOrigin: true },
|
||||||
'/admin': { target: 'http://localhost:8787', changeOrigin: true },
|
'/admin': { target: 'http://localhost:8787', changeOrigin: true },
|
||||||
|
'/install': { target: 'http://localhost:8787', changeOrigin: true },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
Reference in New Issue
Block a user