generated from liutk/owl-admin-base
Merge branch 'main' of https://gitea.hmily.club/pdkj/store-manage into main
commit
785fe05ad3
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\AppVersionService;
|
||||
use App\Enums\AppOs;
|
||||
use App\Enums\AppUpdateStrategy;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\Operation;
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
|
||||
/**
|
||||
* @property AppVersionService $service
|
||||
*/
|
||||
class AppVersionController extends AdminController
|
||||
{
|
||||
protected string $serviceName = AppVersionService::class;
|
||||
|
||||
public function list(): Page
|
||||
{
|
||||
$crud = $this->baseCRUD()->tableLayout('fixed')
|
||||
->headerToolbar([
|
||||
$this->createTypeButton('drawer', 'lg')->visible(Admin::user()->can('admin.app_versions.create')),
|
||||
amis('reload')->align('right'),
|
||||
])
|
||||
->bulkActions([])
|
||||
->columns([
|
||||
amis()->TableColumn('name', __('app_version.name')),
|
||||
amis()->TableColumn('version', __('app_version.version')),
|
||||
amis()->TableColumn('title', __('app_version.title')),
|
||||
amis()->TableColumn('update_strategy', __('app_version.update_strategy'))->type('mapping')->map(AppUpdateStrategy::labelMap()),
|
||||
amis()->TableColumn('is_force', __('app_version.is_force'))->type('static-mapping')->map([
|
||||
'0' => '<span class="label label-success">否</span>',
|
||||
'1' => '<span class="label label-danger">是</span>',
|
||||
]),
|
||||
amis()->TableColumn('os', __('app_version.os'))->type('mapping')->map(AppOs::labelMap()),
|
||||
amis()->TableColumn('is_release', __('app_version.is_release'))->type('static-mapping')->map([
|
||||
'0' => '<span class="label label-default">否</span>',
|
||||
'1' => '<span class="label label-success">是</span>',
|
||||
]),
|
||||
amis()->TableColumn('release_at', __('app_version.release_at')),
|
||||
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime'),
|
||||
Operation::make()->label(__('admin.actions'))->buttons([
|
||||
$this->rowEditTypeButton('drawer', 'lg')->visible(Admin::user()->can('admin.app_versions.update')),
|
||||
$this->rowDeleteButton()->visible(Admin::user()->can('admin.app_versions.delete')),
|
||||
$this->rowShowButton()->visible(Admin::user()->can('admin.app_versions.view')),
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
|
||||
public function form($isEdit = false): Form
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
amis()->TextControl('name', __('app_version.name'))
|
||||
->placeholder(__('app_version.name'))
|
||||
->required(),
|
||||
amis()->NumberControl('version', __('app_version.version'))
|
||||
->placeholder(__('app_version.version'))
|
||||
->precision(0)
|
||||
->required(),
|
||||
amis()->TextControl('title', __('app_version.title'))
|
||||
->placeholder(__('app_version.title'))
|
||||
->required(),
|
||||
amis()->TextareaControl('description', __('app_version.description'))
|
||||
->placeholder(__('app_version.description'))
|
||||
->minRows(10)
|
||||
->required(),
|
||||
amis()->RadiosControl('update_strategy', __('app_version.update_strategy'))
|
||||
->options(AppUpdateStrategy::options())
|
||||
->value(AppUpdateStrategy::Wgt->value)
|
||||
->required(),
|
||||
amis()->RadiosControl('is_force', __('app_version.is_force'))
|
||||
->options([
|
||||
['label' => '是', 'value' => true],
|
||||
['label' => '否', 'value' => false],
|
||||
])
|
||||
->value(false)
|
||||
->required(),
|
||||
amis()->RadiosControl('os', __('app_version.os'))->options(AppOs::options())->value(AppOs::Android->value)->required(),
|
||||
|
||||
amis()->FileControl('android[wgt_url]', __('app_version.wgt_url'))
|
||||
->accept('.wgt')
|
||||
->useChunk(false)
|
||||
->visibleOn('${AND(os == "'.AppOs::Android->value.'", update_strategy == "wgt")}'),
|
||||
amis()->FileControl('android[apk_url]', __('app_version.apk_url'))
|
||||
->accept('.apk')
|
||||
->useChunk(false)
|
||||
->visibleOn('${os == "'.AppOs::Android->value.'"}'),
|
||||
|
||||
amis()->FileControl('ios[wgt_url]', __('app_version.wgt_url'))
|
||||
->accept('.wgt')
|
||||
->useChunk(false)
|
||||
->visibleOn('${AND(os == "'.AppOs::Ios->value.'", update_strategy == "wgt")}'),
|
||||
amis()->TextControl('ios[apk_url]', '苹果应用地址')
|
||||
->placeholder('苹果应用地址')
|
||||
->visibleOn('${os == "'.AppOs::Ios->value.'"}'),
|
||||
|
||||
amis()->DateTimeControl('release_at', __('app_version.release_at'))
|
||||
->valueFormat('YYYY-MM-DD HH:mm:ss')
|
||||
->description('必须设置发布时间,才可更新'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail(): Form
|
||||
{
|
||||
return $this->baseDetail()->body([
|
||||
amis()->Property()->items([
|
||||
['label' => __('app_version.name'), 'content' => '${name}'],
|
||||
['label' => __('app_version.version'), 'content' => '${version}'],
|
||||
['label' => __('app_version.os'), 'content' => amis()->Mapping()->name('os')->map(AppOs::labelMap())],
|
||||
['label' => __('app_version.title'), 'content' => '${title}', 'span' => 3],
|
||||
['label' => __('app_version.description'), 'content' => amis()->TextareaControl()->name('description')->static()->labelClassName('hidden'), 'span' => 3],
|
||||
['label' => __('app_version.update_strategy'), 'content' => amis()->Mapping()->name('update_strategy')->map(AppUpdateStrategy::labelMap())],
|
||||
[
|
||||
'label' => __('app_version.is_force'),
|
||||
'content' => amis()->Mapping()->name('${is_force}')->static()->map([
|
||||
'0' => '<span class="label label-success">否</span>',
|
||||
'1' => '<span class="label label-danger">是</span>',
|
||||
]),
|
||||
],
|
||||
['label' => __('app_version.apk_url'), 'content' => amis()->Link()->href('${apk_url}')->body('下载')->blank()->visibleOn('${apk_url != null && apk_url != ""}')],
|
||||
['label' => __('app_version.wgt_url'), 'content' => amis()->Link()->href('${wgt_url}')->body('下载')->blank()->visibleOn('${wgt_url != null && wgt_url != ""}')],
|
||||
['label' => __('app_version.release_at'), 'content' => '${release_at}'],
|
||||
['label' => __('app_version.created_at'), 'content' => '${created_at}'],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Filters;
|
||||
|
||||
use EloquentFilter\ModelFilter;
|
||||
|
||||
class AppVersionFilter extends ModelFilter
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services;
|
||||
|
||||
use App\Admin\Filters\AppVersionFilter;
|
||||
use App\Enums\AppOs;
|
||||
use App\Enums\AppUpdateStrategy;
|
||||
use App\Models\AppVersion;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
|
||||
class AppVersionService extends BaseService
|
||||
{
|
||||
protected string $modelName = AppVersion::class;
|
||||
|
||||
protected string $modelFilterName = AppVersionFilter::class;
|
||||
|
||||
public function sortColumn()
|
||||
{
|
||||
return 'version';
|
||||
}
|
||||
|
||||
public function getEditData($id)
|
||||
{
|
||||
return tap(parent::getEditData($id), function ($instance) {
|
||||
switch ($instance?->os) {
|
||||
case AppOs::Android:
|
||||
$instance->setAttribute('android', [
|
||||
'apk_url' => $instance->apk_url,
|
||||
'wgt_url' => $instance->wgt_url,
|
||||
]);
|
||||
break;
|
||||
|
||||
case AppOs::Ios:
|
||||
$instance->setAttribute('ios', [
|
||||
'apk_url' => $instance->apk_url,
|
||||
'wgt_url' => $instance->wgt_url,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function store($data): bool
|
||||
{
|
||||
Validator::validate(
|
||||
data: $data,
|
||||
rules: [
|
||||
'name' => ['bail', 'required', 'max:255'],
|
||||
'version' => ['bail', 'required', 'int'],
|
||||
'title' => ['bail', 'required', 'max:255'],
|
||||
'description' => ['bail', 'required'],
|
||||
'update_strategy' => ['bail', 'required', Rule::enum(AppUpdateStrategy::class)],
|
||||
'is_force' => ['bail', 'required', 'bool'],
|
||||
'os' => ['bail', 'required', Rule::enum(AppOs::class)],
|
||||
'release_at' => ['bail', 'nullable', 'date_format:Y-m-d H:i:s'],
|
||||
],
|
||||
attributes: [
|
||||
'name' => __('app_version.name'),
|
||||
'version' => __('app_version.version'),
|
||||
'title' => __('app_version.title'),
|
||||
'description' => __('app_version.description'),
|
||||
'update_strategy' => __('app_version.update_strategy'),
|
||||
'is_force' => __('app_version.is_force'),
|
||||
'os' => __('app_version.os'),
|
||||
'release_at' => __('app_version.release_at'),
|
||||
],
|
||||
);
|
||||
|
||||
// 全量包
|
||||
$apkUrl = '';
|
||||
// 增量包
|
||||
$wgtUrl = '';
|
||||
// 更新策略
|
||||
$aus = AppUpdateStrategy::from($data['update_strategy']);
|
||||
|
||||
switch (AppOs::from($data['os'])) {
|
||||
case AppOs::Android:
|
||||
$apkUrl = (string) Arr::get($data, 'android.apk_url');
|
||||
$wgtUrl = (string) Arr::get($data, 'android.wgt_url');
|
||||
if ($aus === AppUpdateStrategy::Apk) {
|
||||
admin_abort_if($apkUrl === '', '请上传全量包');
|
||||
} else {
|
||||
admin_abort_if($wgtUrl === '', '请上传增量包');
|
||||
}
|
||||
break;
|
||||
|
||||
case AppOs::Ios:
|
||||
$apkUrl = (string) Arr::get($data, 'ios.apk_url');
|
||||
$wgtUrl = (string) Arr::get($data, 'ios.wgt_url');
|
||||
if ($aus === AppUpdateStrategy::Apk) {
|
||||
admin_abort_if($apkUrl === '', '苹果应用地址 不能为空。');
|
||||
} else {
|
||||
admin_abort_if($wgtUrl === '', '请上传增量包');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
admin_abort('未知操作系统');
|
||||
break;
|
||||
}
|
||||
|
||||
$model = $this->getModel();
|
||||
|
||||
$instance = new $model($data);
|
||||
|
||||
try {
|
||||
$filename = $data['name'].'_'.time();
|
||||
if ($extension = pathinfo($apkUrl, PATHINFO_EXTENSION)) {
|
||||
$filename .= '.'.$extension;
|
||||
}
|
||||
$instance->apk_url = $this->saveUploadedFile($apkUrl, "app-versions/{$filename}");
|
||||
} catch (FileNotFoundException $e) {
|
||||
admin_abort('全量包未找到,请重新上传');
|
||||
}
|
||||
|
||||
try {
|
||||
$filename = $data['name'].'_'.time();
|
||||
if ($extension = pathinfo($wgtUrl, PATHINFO_EXTENSION)) {
|
||||
$filename .= '.'.$extension;
|
||||
}
|
||||
$instance->wgt_url = $this->saveUploadedFile($wgtUrl, "app-versions/{$filename}");
|
||||
} catch (FileNotFoundException $e) {
|
||||
admin_abort('增量包未找到,请重新上传');
|
||||
}
|
||||
|
||||
return $instance->save();
|
||||
}
|
||||
|
||||
public function update($primaryKey, $data): bool
|
||||
{
|
||||
Validator::validate(
|
||||
data: $data,
|
||||
rules: [
|
||||
'name' => ['bail', 'required', 'max:255'],
|
||||
'version' => ['bail', 'required', 'int'],
|
||||
'title' => ['bail', 'required', 'max:255'],
|
||||
'description' => ['bail', 'required'],
|
||||
'update_strategy' => ['bail', 'required', Rule::enum(AppUpdateStrategy::class)],
|
||||
'is_force' => ['bail', 'required', 'bool'],
|
||||
'os' => ['bail', 'required', Rule::enum(AppOs::class)],
|
||||
'release_at' => ['bail', 'nullable', 'date_format:Y-m-d H:i:s'],
|
||||
],
|
||||
attributes: [
|
||||
'name' => __('app_version.name'),
|
||||
'version' => __('app_version.version'),
|
||||
'title' => __('app_version.title'),
|
||||
'description' => __('app_version.description'),
|
||||
'update_strategy' => __('app_version.update_strategy'),
|
||||
'is_force' => __('app_version.is_force'),
|
||||
'os' => __('app_version.os'),
|
||||
'release_at' => __('app_version.release_at'),
|
||||
],
|
||||
);
|
||||
|
||||
// 全量包
|
||||
$apkUrl = '';
|
||||
// 增量包
|
||||
$wgtUrl = '';
|
||||
// 更新策略
|
||||
$aus = AppUpdateStrategy::from($data['update_strategy']);
|
||||
|
||||
switch (AppOs::from($data['os'])) {
|
||||
case AppOs::Android:
|
||||
$apkUrl = (string) Arr::get($data, 'android.apk_url');
|
||||
$wgtUrl = (string) Arr::get($data, 'android.wgt_url');
|
||||
if ($aus === AppUpdateStrategy::Apk) {
|
||||
admin_abort_if($apkUrl === '', '请上传全量包');
|
||||
} else {
|
||||
admin_abort_if($wgtUrl === '', '请上传增量包');
|
||||
}
|
||||
break;
|
||||
|
||||
case AppOs::Ios:
|
||||
$apkUrl = (string) Arr::get($data, 'ios.apk_url');
|
||||
$wgtUrl = (string) Arr::get($data, 'ios.wgt_url');
|
||||
if ($aus === AppUpdateStrategy::Apk) {
|
||||
admin_abort_if($apkUrl === '', '苹果应用地址 不能为空。');
|
||||
} else {
|
||||
admin_abort_if($wgtUrl === '', '请上传增量包');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
admin_abort('未知操作系统');
|
||||
break;
|
||||
}
|
||||
|
||||
$instance = $this->query()->whereKey($primaryKey)->firstOrFail();
|
||||
$instance->fill($data);
|
||||
|
||||
try {
|
||||
$filename = $data['name'].'_'.time();
|
||||
if ($extension = pathinfo($apkUrl, PATHINFO_EXTENSION)) {
|
||||
$filename .= '.'.$extension;
|
||||
}
|
||||
$instance->apk_url = $this->saveUploadedFile($apkUrl, "app-versions/{$filename}");
|
||||
} catch (FileNotFoundException $e) {
|
||||
admin_abort('全量包未找到,请重新上传');
|
||||
}
|
||||
|
||||
try {
|
||||
$filename = $data['name'].'_'.time();
|
||||
if ($extension = pathinfo($wgtUrl, PATHINFO_EXTENSION)) {
|
||||
$filename .= '.'.$extension;
|
||||
}
|
||||
$instance->wgt_url = $this->saveUploadedFile($wgtUrl, "app-versions/{$filename}");
|
||||
} catch (FileNotFoundException $e) {
|
||||
admin_abort('增量包未找到,请重新上传');
|
||||
}
|
||||
|
||||
return $instance->save();
|
||||
}
|
||||
|
||||
protected function saveUploadedFile(string $from, string $to): string
|
||||
{
|
||||
if ($from === '' || preg_match('/^https?:\/\//', $from)) {
|
||||
return $from;
|
||||
}
|
||||
|
||||
$disk = Storage::disk(Admin::config('admin.upload.disk'));
|
||||
|
||||
if (! $disk->exists($from)) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
$disk->move($from, $to);
|
||||
|
||||
return $disk->url($to);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Admin\Controllers\AgreementController;
|
||||
use App\Admin\Controllers\AppVersionController;
|
||||
use App\Admin\Controllers\BaseKeywordController;
|
||||
use App\Admin\Controllers\CockpitController;
|
||||
use App\Admin\Controllers\Complaint\ComplaintController;
|
||||
|
|
@ -219,6 +220,8 @@ Route::group([
|
|||
$router->post('agreement/download', [AgreementController::class, 'download'])->name('agreement.download');
|
||||
$router->resource('agreement', AgreementController::class);
|
||||
|
||||
$router->resource('app-versions', AppVersionController::class);
|
||||
|
||||
// 修改上传
|
||||
$router->post('upload_file', [\App\Admin\Controllers\IndexController::class, 'uploadFile']);
|
||||
$router->post('upload_image', [\App\Admin\Controllers\IndexController::class, 'uploadImage']);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum AppOs: string
|
||||
{
|
||||
case Android = 'android';
|
||||
case Ios = 'ios';
|
||||
|
||||
public function text(): string
|
||||
{
|
||||
return $this->options()[$this->value];
|
||||
}
|
||||
|
||||
public static function options()
|
||||
{
|
||||
return [
|
||||
self::Android->value => '安卓',
|
||||
self::Ios->value => '苹果',
|
||||
];
|
||||
}
|
||||
|
||||
public static function labelMap(): array
|
||||
{
|
||||
return [
|
||||
self::Android->value => '<span class="label bg-primary">'.self::Android->text().'</span>',
|
||||
self::Ios->value => '<span class="label label-success">'.self::Ios->text().'</span>',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum AppUpdateStrategy: string
|
||||
{
|
||||
case Apk = 'apk';
|
||||
case Wgt = 'wgt';
|
||||
|
||||
public function text(): string
|
||||
{
|
||||
return $this->options()[$this->value];
|
||||
}
|
||||
|
||||
public static function options(): array
|
||||
{
|
||||
return [
|
||||
self::Apk->value => '全量包',
|
||||
self::Wgt->value => '热更新',
|
||||
];
|
||||
}
|
||||
|
||||
public static function labelMap(): array
|
||||
{
|
||||
return [
|
||||
self::Apk->value => '<span class="label bg-danger">'.self::Apk->text().'</span>',
|
||||
self::Wgt->value => '<span class="label label-primary">'.self::Wgt->text().'</span>',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\AppOs;
|
||||
use App\Enums\AppUpdateStrategy;
|
||||
use App\Traits\HasDateTimeFormatter;
|
||||
use EloquentFilter\Filterable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AppVersion extends Model
|
||||
{
|
||||
use Filterable, HasFactory, HasDateTimeFormatter;
|
||||
|
||||
protected $appends = [
|
||||
'is_release',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
'is_force' => false,
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'os' => AppOs::class,
|
||||
'update_strategy' => AppUpdateStrategy::class,
|
||||
'is_force' => 'bool',
|
||||
'release_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'os',
|
||||
'name',
|
||||
'version',
|
||||
'title',
|
||||
'description',
|
||||
'update_strategy',
|
||||
'is_force',
|
||||
'apk_url',
|
||||
'wgt_url',
|
||||
'release_at',
|
||||
];
|
||||
|
||||
protected function isRelease(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, $attributes) {
|
||||
return (bool) $attributes['release_at'];
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('app_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('os')->comment('操作系统: android, ios');
|
||||
$table->string('name')->comment('版本名称');
|
||||
$table->integer('version')->comment('版本号');
|
||||
$table->string('title')->nullable()->comment('更新标题');
|
||||
$table->text('description')->nullable()->comment('更新描述');
|
||||
$table->string('apk_url')->nullable()->comment('全量包地址');
|
||||
$table->string('wgt_url')->nullable()->comment('增量包地址');
|
||||
$table->boolean('is_force')->default(false)->comment('是否强制更新');
|
||||
$table->string('update_strategy')->comment('更新策略: apk 全量包, wgt 热更新');
|
||||
$table->timestamp('release_at')->nullable()->comment('发布时间');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('app_versions');
|
||||
}
|
||||
};
|
||||
|
|
@ -15,8 +15,6 @@ class AdminPermissionSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
// AdminMenu::truncate();
|
||||
// AdminPermission::truncate();
|
||||
$data = [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
@ -359,6 +357,13 @@ class AdminPermissionSeeder extends Seeder
|
|||
'download' => '打包下载',
|
||||
]
|
||||
],
|
||||
'app_versions' => [
|
||||
'name' => 'App版本管理',
|
||||
'icon' => 'flowbite:inbox-full-outline',
|
||||
'uri' => '/app-versions',
|
||||
'resource' => true,
|
||||
'children' => []
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'id' => 'ID',
|
||||
'name' => '版本名称',
|
||||
'version' => '版本号',
|
||||
'title' => '更新标题',
|
||||
'description' => '更新描述',
|
||||
'is_force' => '强制更新',
|
||||
'update_strategy' => '更新策略',
|
||||
'os' => '操作系统',
|
||||
'apk_url' => '全量包',
|
||||
'wgt_url' => '增量包',
|
||||
'is_release' => '是否发布',
|
||||
'release_at' => '发布时间',
|
||||
'created_at' => '创建时间',
|
||||
];
|
||||
Loading…
Reference in New Issue