chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace addon\appmall\controller\backend;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use Exception;
|
||||
use ywxapp\controller\BackendBase;
|
||||
|
||||
/**
|
||||
* 插件审核(运营后台,中心站)
|
||||
*
|
||||
* 审核开发者通过 Market::submit 提交的插件上架申请(appmall_addon_submissions)。
|
||||
* status: 0=待审核 1=已发布 2=已驳回。
|
||||
*/
|
||||
class AddonReview extends BackendBase
|
||||
{
|
||||
/**
|
||||
* 审核列表 / 页面
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$status = $this->request->param('status', '');
|
||||
$query = Db::name('appmall_addon_submissions')->order('id', 'desc');
|
||||
if ($status !== '') {
|
||||
$query->where('status', (int) $status);
|
||||
}
|
||||
$list = $query->paginate([
|
||||
'page' => (int) $this->request->param('page', 1),
|
||||
'list_rows' => (int) $this->request->param('limit', 10),
|
||||
]);
|
||||
$this->result->setCount($list->total())->success($list->items(), '获取成功');
|
||||
}
|
||||
return View::fetch('addonreview/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过:标记已发布(status=1)
|
||||
* 注意:正式上架到 appmall_addon_list 由发布流程处理,此处仅切换审核态。
|
||||
*/
|
||||
public function audit()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$row = Db::name('appmall_addon_submissions')->where('id', $id)->find();
|
||||
if (empty($row)) {
|
||||
return $this->result->error('提交记录不存在');
|
||||
}
|
||||
if ((int) $row['status'] === 1) {
|
||||
return $this->result->error('该提交已发布');
|
||||
}
|
||||
Db::name('appmall_addon_submissions')->where('id', $id)
|
||||
->update(['status' => 1, 'reject_reason' => '', 'update_at' => time()]);
|
||||
return $this->result->success([], '已通过审核');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回:标记已驳回(status=2)并记录原因
|
||||
*/
|
||||
public function reject()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$reason = trim(input('reason', ''));
|
||||
if ($reason === '') {
|
||||
return $this->result->error('请填写驳回原因');
|
||||
}
|
||||
$row = Db::name('appmall_addon_submissions')->where('id', $id)->find();
|
||||
if (empty($row)) {
|
||||
return $this->result->error('提交记录不存在');
|
||||
}
|
||||
Db::name('appmall_addon_submissions')->where('id', $id)
|
||||
->update(['status' => 2, 'reject_reason' => $reason, 'update_at' => time()]);
|
||||
return $this->result->success([], '已驳回');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace addon\appmall\controller\backend;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use Exception;
|
||||
use ywxapp\controller\BackendBase;
|
||||
use ywxapp\library\Mailer;
|
||||
|
||||
/**
|
||||
* 开发者管理(运营后台,含审核)
|
||||
* 由原核心 app/backend/controller/Developer.php 剥离到 market 插件。
|
||||
*/
|
||||
class Developer extends BackendBase
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$status = $this->request->param('status', '');
|
||||
$query = Db::name('appmall_developers');
|
||||
if ($status !== '') {
|
||||
$query->where('status', (int) $status);
|
||||
}
|
||||
$list = $query->order('status', 'asc')
|
||||
->order('id', 'desc')
|
||||
->paginate([
|
||||
'page' => (int) $this->request->param('page', 1),
|
||||
'list_rows' => (int) $this->request->param('limit', 10),
|
||||
]);
|
||||
$this->result->setCount($list->total())->success($list->items(), '获取成功');
|
||||
}
|
||||
return View::fetch('developer/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过:激活并邮件下发令牌
|
||||
*/
|
||||
public function approve()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$dev = Db::name('appmall_developers')->where('id', $id)->find();
|
||||
if (empty($dev)) {
|
||||
return $this->result->error('记录不存在');
|
||||
}
|
||||
Db::name('appmall_developers')->where('id', $id)->update(['status' => 1, 'update_at' => time()]);
|
||||
Mailer::send($dev['email'], '开发者申请已通过', $this->tokenMail($dev['username'], $dev['token']));
|
||||
return $this->result->success([], '已通过并发送令牌邮件');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
$id = (int) input('id');
|
||||
Db::name('appmall_developers')->where('id', $id)->update(['status' => -1, 'update_at' => time()]);
|
||||
return $this->result->success([], '已禁用');
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新发送令牌邮件(仅已激活)
|
||||
*/
|
||||
public function resend()
|
||||
{
|
||||
$id = (int) input('id');
|
||||
$dev = Db::name('appmall_developers')->where('id', $id)->find();
|
||||
if (empty($dev)) {
|
||||
return $this->result->error('记录不存在');
|
||||
}
|
||||
if ((int) $dev['status'] !== 1) {
|
||||
return $this->result->error('仅已激活账号可重发');
|
||||
}
|
||||
Mailer::send($dev['email'], '您的开发者令牌', $this->tokenMail($dev['username'], $dev['token']));
|
||||
return $this->result->success([], '已重发令牌邮件');
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置令牌(已激活则同步邮件通知)
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$dev = Db::name('appmall_developers')->where('id', $id)->find();
|
||||
if (empty($dev)) {
|
||||
return $this->result->error('记录不存在');
|
||||
}
|
||||
$token = bin2hex(random_bytes(32));
|
||||
Db::name('appmall_developers')->where('id', $id)->update(['token' => $token, 'update_at' => time()]);
|
||||
if ((int) $dev['status'] === 1) {
|
||||
Mailer::send($dev['email'], '您的开发者令牌已重置', $this->tokenMail($dev['username'], $token));
|
||||
}
|
||||
return $this->result->success(['token' => $token], '已重置令牌' . ((int) $dev['status'] === 1 ? '并邮件通知' : ''));
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function tokenMail($name, $token): string
|
||||
{
|
||||
return "尊敬的 {$name}:<br>您的开发者令牌如下:<br><br>"
|
||||
. "<code style=\"background:#f4f4f4;padding:4px 8px;border-radius:4px;\">{$token}</code><br><br>"
|
||||
. '请将其配置到开发者控制台的 <b>APPMARKET_DEV_TOKEN</b> 环境变量。';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace addon\appmall\controller\backend;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use Exception;
|
||||
use ywxapp\controller\BackendBase;
|
||||
use ywxapp\library\StreamZipResponse;
|
||||
|
||||
/**
|
||||
* 主框架版本管理(运营后台,中心站)
|
||||
*
|
||||
* 上传核心包 zip → 入库(草稿)→ 发布(status=1)→ 客户端可见可下载。
|
||||
* 原 upgrade 插件功能,已合并进 market(应用服务中心)。
|
||||
*/
|
||||
class Framework extends BackendBase
|
||||
{
|
||||
/**
|
||||
* 版本列表 / 页面
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$this->ensurePatchColumns();
|
||||
$status = $this->request->param('status', '');
|
||||
$query = Db::name('appmall_framework_list');
|
||||
if ($status !== '') {
|
||||
$query->where('status', (int) $status);
|
||||
}
|
||||
$list = $query->order('id', 'desc')
|
||||
->paginate([
|
||||
'page' => (int) $this->request->param('page', 1),
|
||||
'list_rows' => (int) $this->request->param('limit', 10),
|
||||
]);
|
||||
$this->result->setCount($list->total())->success($list->items(), '获取成功');
|
||||
}
|
||||
return View::fetch('framework/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传并登记一个主框架核心包(zip),默认草稿态
|
||||
*
|
||||
* 同一版本号对应一行记录:整包(type=0)写 file_path/file_hash,
|
||||
* 增量补丁(type=1)写 patch_path/patch_hash/patch_from,二者可先后上传共存。
|
||||
*/
|
||||
public function upload()
|
||||
{
|
||||
try {
|
||||
$this->ensurePatchColumns();
|
||||
$version = trim(input('version', ''));
|
||||
$title = trim(input('title', ''));
|
||||
$changelog = input('changelog', '');
|
||||
$type = (int) input('type', 0); // 0=整包 1=补丁 2=完整安装包
|
||||
$fromVer = trim(input('from_version', ''));
|
||||
if (!preg_match('/^\d+\.\d+\.\d+$/', $version)) {
|
||||
return $this->result->error('版本号格式不正确(需 x.y.z)');
|
||||
}
|
||||
if ($type === 1 && $fromVer === '') {
|
||||
return $this->result->error('增量补丁必须填写「基础版本」');
|
||||
}
|
||||
if ($type === 1 && !preg_match('/^\d+\.\d+\.\d+$/', $fromVer)) {
|
||||
return $this->result->error('基础版本号格式不正确(需 x.y.z)');
|
||||
}
|
||||
$file = $this->request->file('file');
|
||||
if (empty($file)) {
|
||||
return $this->result->error('请上传核心包 zip');
|
||||
}
|
||||
if (strtolower(substr($file->getOriginalName(), -4)) !== '.zip') {
|
||||
return $this->result->error('仅支持 zip 格式');
|
||||
}
|
||||
|
||||
// 整包需校验 ywxapp 核心结构;补丁只校验为合法 zip(含变更文件即可)
|
||||
$tmp = $file->getRealPath();
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($tmp) !== true) {
|
||||
return $this->result->error('zip 包无法打开');
|
||||
}
|
||||
if ($type === 0) {
|
||||
$hasCore = false;
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$nm = $zip->statIndex($i)['name'];
|
||||
if (preg_match('#^(ywxapp/)?(service|controller|library|traits)/#', $nm)) {
|
||||
$hasCore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
if (!$hasCore) {
|
||||
return $this->result->error('核心包结构不正确:应包含 ywxapp 核心目录(service/controller/...)');
|
||||
}
|
||||
} elseif ($type === 2) {
|
||||
// 完整安装包:必须含 config/ 与占位符 .env,且不得夹带 runtime/vendor/data 或真实 .env.*
|
||||
$hasConfig = false;
|
||||
$hasEnv = false;
|
||||
$bad = false;
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$nm = $zip->statIndex($i)['name'];
|
||||
if ($nm === 'config' || strpos($nm, 'config/') === 0) {
|
||||
$hasConfig = true;
|
||||
}
|
||||
if ($nm === '.env') {
|
||||
$hasEnv = true;
|
||||
}
|
||||
if (preg_match('#^(runtime/|vendor/|data/|\.env\.)#', $nm)) {
|
||||
$bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
if ($bad) {
|
||||
return $this->result->error('安装包结构不正确:不应包含 runtime/vendor/data 或真实 .env.* 文件');
|
||||
}
|
||||
if (!$hasConfig || !$hasEnv) {
|
||||
return $this->result->error('安装包结构不正确:必须包含 config/ 目录与 .env 占位符');
|
||||
}
|
||||
} else {
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
$dir = root_path() . 'runtime' . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR;
|
||||
if (!is_dir($dir)) {
|
||||
@mkdir($dir, 0755, true);
|
||||
}
|
||||
$saveName = 'ywxapp-' . $version . ($type === 1 ? '-patch' : ($type === 2 ? '-install' : '')) . '.zip';
|
||||
$file->move($dir, $saveName);
|
||||
$absPath = realpath($dir . $saveName);
|
||||
if (!$absPath || !is_file($absPath)) {
|
||||
return $this->result->error('核心包保存失败');
|
||||
}
|
||||
$hash = hash_file('sha256', $absPath);
|
||||
|
||||
$exist = Db::name('appmall_framework_list')->where('version', $version)->find();
|
||||
// 公共字段:标题/日志仅在填写时覆盖,避免后传的包把先前信息清空
|
||||
$data = [
|
||||
'version' => $version,
|
||||
'status' => 0, // 重新上传任一包均回到草稿,需再次发布
|
||||
'update_at' => time(),
|
||||
];
|
||||
if ($title !== '' || !$exist) {
|
||||
$data['title'] = $title ?: ('主框架 ' . $version);
|
||||
}
|
||||
if (trim((string) $changelog) !== '' || !$exist) {
|
||||
$data['changelog'] = $changelog;
|
||||
}
|
||||
if ($type === 1) {
|
||||
// 增量补丁:只更新 patch 字段,不动整包
|
||||
$data['patch_path'] = $absPath;
|
||||
$data['patch_hash'] = $hash;
|
||||
$data['patch_from'] = $fromVer;
|
||||
$data['from_version'] = $fromVer; // 兼容旧客户端镜像
|
||||
} elseif ($type === 2) {
|
||||
// 完整安装包:只更新 install 字段,与整包/补丁独立共存
|
||||
$data['install_path'] = $absPath;
|
||||
$data['install_hash'] = $hash;
|
||||
} else {
|
||||
// 整包:只更新整包字段,不动补丁
|
||||
$data['file_path'] = $absPath;
|
||||
$data['file_hash'] = $hash;
|
||||
}
|
||||
if ($exist) {
|
||||
Db::name('appmall_framework_list')->where('id', $exist['id'])->update($data);
|
||||
$id = $exist['id'];
|
||||
// type 兼容标志:有整包即 0,仅补丁为 1
|
||||
$hasFull = ($type === 0) || !empty($exist['file_path']);
|
||||
Db::name('appmall_framework_list')->where('id', $id)->update(['type' => $hasFull ? 0 : 1]);
|
||||
} else {
|
||||
$data['type'] = $type;
|
||||
$data['create_at'] = time();
|
||||
$id = Db::name('appmall_framework_list')->insertGetId($data);
|
||||
}
|
||||
$tip = $type === 1 ? '增量补丁已上传' : ($type === 2 ? '完整安装包已上传' : '整包已上传');
|
||||
return $this->result->success(['id' => $id], $tip . ',请点击「发布」使其对外可下载');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布:将某版本置为已发布(status=1),客户端即可检测到
|
||||
*/
|
||||
public function publish()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
if ($id <= 0) {
|
||||
return $this->result->error('缺少版本ID');
|
||||
}
|
||||
$row = Db::name('appmall_framework_list')->where('id', $id)->find();
|
||||
if (empty($row)) {
|
||||
return $this->result->error('版本不存在');
|
||||
}
|
||||
if (empty($row['file_path']) && empty($row['patch_path'])) {
|
||||
return $this->result->error('该版本尚未上传任何包,无法发布');
|
||||
}
|
||||
Db::name('appmall_framework_list')->where('id', $id)->update(['status' => 1, 'update_at' => time()]);
|
||||
$tip = empty($row['file_path'])
|
||||
? (empty($row['patch_path'])
|
||||
? (empty($row['install_path']) ? '已发布' : '已发布(完整安装包,可供全新部署下载)')
|
||||
: '已发布(仅增量补丁:只有停在 ' . ($row['patch_from'] ?: $row['from_version']) . ' 的客户端可升级,建议补传整包)')
|
||||
: (empty($row['patch_path']) ? '已发布(整包)' : '已发布(整包 + 增量补丁)');
|
||||
return $this->result->success([], $tip);
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除版本(同时删除整包与补丁物理文件)
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
if ($id <= 0) {
|
||||
return $this->result->error('缺少版本ID');
|
||||
}
|
||||
$row = Db::name('appmall_framework_list')->where('id', $id)->find();
|
||||
foreach (['file_path', 'patch_path', 'install_path'] as $col) {
|
||||
if ($row && !empty($row[$col]) && is_file($row[$col])) {
|
||||
@unlink($row[$col]);
|
||||
}
|
||||
}
|
||||
Db::name('appmall_framework_list')->where('id', $id)->delete();
|
||||
return $this->result->success([], '已删除');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载核心包(供运营本地校验)
|
||||
* ?type=patch 下载增量补丁,默认整包
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
$id = (int) input('id');
|
||||
$kind = input('type', 'full');
|
||||
$kind = in_array($kind, ['patch', 'install'], true) ? $kind : 'full';
|
||||
$row = Db::name('appmall_framework_list')->where('id', $id)->find();
|
||||
if ($kind === 'patch') {
|
||||
$path = $row['patch_path'] ?? '';
|
||||
$suffix = '-patch';
|
||||
} elseif ($kind === 'install') {
|
||||
$path = $row['install_path'] ?? '';
|
||||
$suffix = '-install';
|
||||
} else {
|
||||
$path = $row['file_path'] ?? '';
|
||||
$suffix = '';
|
||||
}
|
||||
if (empty($row) || empty($path) || !is_file($path)) {
|
||||
return json(['code' => 0, 'msg' => '文件不存在']);
|
||||
}
|
||||
return new StreamZipResponse($path, 'ywxapp-' . $row['version'] . $suffix . '.zip');
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容已安装库:在线补齐 patch_path / patch_hash / patch_from 列
|
||||
*/
|
||||
private function ensurePatchColumns(): void
|
||||
{
|
||||
$table = \ywxapp\model\BaseModel::currentPrefix() . 'appmall_framework_list';
|
||||
try {
|
||||
$defs = [
|
||||
'patch_path' => "varchar(255) DEFAULT '' COMMENT '增量补丁 zip 物理路径'",
|
||||
'patch_hash' => "varchar(64) DEFAULT '' COMMENT '补丁 SHA256 校验值'",
|
||||
'patch_from' => "varchar(20) DEFAULT '' COMMENT '补丁适用的基础版本'",
|
||||
'install_path' => "varchar(255) DEFAULT '' COMMENT '完整安装包 zip 物理路径'",
|
||||
'install_hash' => "varchar(64) DEFAULT '' COMMENT '完整安装包 SHA256 校验值'",
|
||||
];
|
||||
foreach ($defs as $col => $def) {
|
||||
$cols = Db::query("SHOW COLUMNS FROM `{$table}` LIKE '{$col}'");
|
||||
if (empty($cols)) {
|
||||
Db::execute("ALTER TABLE `{$table}` ADD COLUMN `{$col}` {$def}");
|
||||
}
|
||||
}
|
||||
// 历史数据迁移:旧「补丁行」(type=1 且 patch_path 为空) 把整包字段挪到补丁字段
|
||||
Db::execute(
|
||||
"UPDATE `{$table}` SET patch_path = file_path, patch_hash = file_hash, patch_from = from_version,"
|
||||
. " file_path = '', file_hash = ''"
|
||||
. " WHERE type = 1 AND (patch_path = '' OR patch_path IS NULL) AND file_path <> ''"
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace addon\appmall\controller\backend;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use Exception;
|
||||
use ywxapp\controller\BackendBase;
|
||||
|
||||
/**
|
||||
* 收益与结算管理(运营后台,中心站)
|
||||
*
|
||||
* - 收益账本:每笔已支付订单按平台抽成记账,归属对应开发者;
|
||||
* - 提现单:开发者发起(或运营代发)后在此审核打款/驳回。
|
||||
*/
|
||||
class Revenue extends BackendBase
|
||||
{
|
||||
/**
|
||||
* 收益账本列表
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$devId = $this->request->param('developer_id', '');
|
||||
$query = Db::name('appmall_addon_revenues')->order('id', 'desc');
|
||||
if ($devId !== '') {
|
||||
$query->where('developer_id', (int) $devId);
|
||||
}
|
||||
$list = $query->paginate([
|
||||
'page' => (int) $this->request->param('page', 1),
|
||||
'list_rows' => (int) $this->request->param('limit', 10),
|
||||
]);
|
||||
// 汇总:总销售额 / 总抽成 / 总开发者收益
|
||||
$summary = Db::name('appmall_addon_revenues')
|
||||
->field('SUM(amount) as total_amount, SUM(commission) as total_commission, SUM(income) as total_income')
|
||||
->find();
|
||||
$this->result->setCount($list->total())->success([
|
||||
'list' => $list->items(),
|
||||
'summary' => [
|
||||
'total_amount' => $summary['total_amount'] ?? 0,
|
||||
'total_commission' => $summary['total_commission'] ?? 0,
|
||||
'total_income' => $summary['total_income'] ?? 0,
|
||||
],
|
||||
], '获取成功');
|
||||
}
|
||||
return View::fetch('revenue/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现单列表
|
||||
*/
|
||||
public function withdrawals()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$status = $this->request->param('status', '');
|
||||
$query = Db::name('appmall_addon_withdrawals')->order('id', 'desc');
|
||||
if ($status !== '') {
|
||||
$query->where('status', (int) $status);
|
||||
}
|
||||
$list = $query->paginate([
|
||||
'page' => (int) $this->request->param('page', 1),
|
||||
'list_rows' => (int) $this->request->param('limit', 10),
|
||||
]);
|
||||
$this->result->setCount($list->total())->success($list->items(), '获取成功');
|
||||
}
|
||||
return View::fetch('revenue/withdrawal');
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过:标记已打款,释放冻结金额,并将对应收益置为已结算
|
||||
*/
|
||||
public function settle()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$w = Db::name('appmall_addon_withdrawals')->where('id', $id)->find();
|
||||
if (empty($w)) {
|
||||
return $this->result->error('提现单不存在');
|
||||
}
|
||||
if ((int) $w['status'] !== 0) {
|
||||
return $this->result->error('该单已处理');
|
||||
}
|
||||
Db::transaction(function () use ($w) {
|
||||
// 释放冻结(实际打款为线下/对接支付,此处仅结算记账)
|
||||
Db::name('appmall_developers')->where('id', $w['developer_id'])
|
||||
->dec('frozen_balance', $w['amount'])->update();
|
||||
Db::name('appmall_addon_withdrawals')->where('id', $w['id'])
|
||||
->update(['status' => 1, 'update_at' => time()]);
|
||||
// 同步将该开发者待结算收益置为已结算
|
||||
Db::name('appmall_addon_revenues')->where('developer_id', $w['developer_id'])
|
||||
->where('status', 0)
|
||||
->update(['status' => 1, 'settle_at' => time()]);
|
||||
});
|
||||
return $this->result->success([], '已结算打款');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回提现:冻结金额退回开发者可提现余额
|
||||
*/
|
||||
public function rejectWithdrawal()
|
||||
{
|
||||
try {
|
||||
$id = (int) input('id');
|
||||
$reason = input('reason', '');
|
||||
$w = Db::name('appmall_addon_withdrawals')->where('id', $id)->find();
|
||||
if (empty($w)) {
|
||||
return $this->result->error('提现单不存在');
|
||||
}
|
||||
if ((int) $w['status'] !== 0) {
|
||||
return $this->result->error('该单已处理');
|
||||
}
|
||||
Db::transaction(function () use ($w, $reason) {
|
||||
Db::name('appmall_developers')->where('id', $w['developer_id'])
|
||||
->dec('frozen_balance', $w['amount'])
|
||||
->inc('balance', $w['amount'])->update();
|
||||
Db::name('appmall_addon_withdrawals')->where('id', $w['id'])
|
||||
->update(['status' => -1, 'remark' => $reason, 'update_at' => time()]);
|
||||
});
|
||||
return $this->result->success([], '已驳回,金额已退回');
|
||||
} catch (Exception $e) {
|
||||
return $this->result->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user