更新若干功能
Some checks failed
Tests / PHP 8.2 (push) Has been cancelled
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled

This commit is contained in:
2026-08-20 19:16:49 +08:00
parent 72bc6502eb
commit 4ddf5e3c5f
48 changed files with 1908 additions and 18 deletions

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\AfterSaleModel;
/**
* 后台售后审核。通过只改状态,线下退款,不自动打微信。
*/
class AfterSaleService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = AfterSaleModel::class;
$this->selectField = [
'id', 'order_id', 'user_id', 'reason', 'amount', 'images',
'status', 'admin_remark', 'created_at', 'updated_at',
];
$this->queryField = ['order_id' => '=', 'user_id' => '=', 'status' => '='];
$this->with = ['order', 'user'];
}
public function list(): array
{
$result = $this->getPageList();
$price = PriceService::getInstance();
foreach ($result['items'] as &$item) {
$item['user_name'] = $item['user']['nick_name'] ?? '';
$item['order_no'] = $item['order']['order_no'] ?? '';
$item['amount_text'] = $price->centsToYuan((int) ($item['amount'] ?? 0));
unset($item['user'], $item['order']);
}
unset($item);
return $result;
}
/**
* 审核:pass=true 通过
*/
public function audit(int $id, bool $pass, string $remark = ''): mixed
{
$row = AfterSaleModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($row)) {
$this->utils->errorThrow('售后单不存在');
}
if ((int) $row['status'] !== AfterSaleModel::STATUS_PENDING) {
$this->utils->errorThrow('已处理过');
}
return $this->save($id, [
'status' => $pass ? AfterSaleModel::STATUS_APPROVED : AfterSaleModel::STATUS_REJECTED,
'admin_remark' => mb_substr(trim($remark), 0, 255),
]);
}
public function delete($ids): mixed
{
return $this->del(is_array($ids) ? $ids : [$ids]);
}
}

View File

@@ -9,6 +9,7 @@ use App\Models\business\ImageModel;
use App\Models\business\PriceSheetModel;
use App\Service\common\MediaUrlService;
use Exception;
use Illuminate\Support\Facades\DB;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -23,7 +24,7 @@ class CatalogueService extends BaseService
{
parent::__construct();
$this->model = CatalogueModel::class;
$this->selectField = ['id', 'title', 'category_id', 'cover', 'pdf', 'price', 'alias', 'identifier', 'status', 'created_at', 'updated_at'];
$this->selectField = ['id', 'title', 'category_id', 'cover', 'pdf', 'video', 'price', 'alias', 'identifier', 'status', 'created_at', 'updated_at'];
$this->queryField = ['title' => 'like', 'alias' => 'like', 'identifier' => 'like', 'status' => '='];
$this->media = MediaUrlService::getInstance();
}
@@ -55,6 +56,7 @@ class CatalogueService extends BaseService
unset($item['category']);
$item['cover'] = $this->media->toPublic($item['cover'] ?? '');
$item['pdf'] = $this->media->toPublic($item['pdf'] ?? '');
$item['video'] = $this->media->toPublic($item['video'] ?? '');
$item['show_field'] = $this->pickUsedMaterialFields($item['price_sheet'] ?? []);
}
unset($item);
@@ -76,6 +78,7 @@ class CatalogueService extends BaseService
$info = $this->getDetail($id);
$info->cover = $this->media->toPublic($info->cover);
$info->pdf = $this->media->toPublic($info->pdf);
$info->video = $this->media->toPublic($info->video);
$priceSheet = PriceSheetModel::where('catalogue_id', $id)
->where('deleted_at', 0)
@@ -134,6 +137,141 @@ class CatalogueService extends BaseService
return $this->save($id, ['status' => (int) $status]);
}
/**
* 导出商品 + 关联报价单:两个工作表,xlsx 由前端 ExcelJS 美化
*/
public function exportExcel(): array
{
$rows = CatalogueModel::where('deleted_at', 0)->orderByDesc('id')->get([
'id', 'title', 'identifier', 'alias', 'category_id', 'price', 'status',
])->toArray();
$byId = [];
foreach ($rows as &$row) {
$row['status'] = (int) ($row['status'] ?? 0) === 0 ? '上架' : '下架';
$byId[(int) $row['id']] = $row;
}
unset($row);
$ids = array_keys($byId);
$priceRows = [];
if (!empty($ids)) {
$sheets = PriceSheetModel::where('deleted_at', 0)
->whereIn('catalogue_id', $ids)
->orderBy('catalogue_id')
->orderBy('id')
->get(['id', 'catalogue_id', 'specification', 'dimension', 'routine', 'stock', 'status'])
->toArray();
foreach ($sheets as $sheet) {
$cat = $byId[(int) $sheet['catalogue_id']] ?? [];
$priceRows[] = [
'id' => $sheet['id'],
'catalogue_id' => $sheet['catalogue_id'],
'identifier' => $cat['identifier'] ?? '',
'title' => $cat['title'] ?? '',
'specification' => $sheet['specification'] ?? '',
'dimension' => $sheet['dimension'] ?? '',
'routine' => $sheet['routine'] ?? '',
'stock' => (int) ($sheet['stock'] ?? -1),
'status' => (int) ($sheet['status'] ?? 0) === 0 ? '启用' : '禁用',
];
}
}
return [
'filename' => 'catalogue.xlsx',
'title' => '商品图册',
'sheets' => [
[
'title' => '商品图册',
'sheet' => '商品',
'columns' => [
['key' => 'id', 'header' => 'ID', 'width' => 10, 'align' => 'center'],
['key' => 'title', 'header' => '商品名称', 'width' => 28],
['key' => 'identifier', 'header' => '商品编号', 'width' => 16],
['key' => 'alias', 'header' => '别名', 'width' => 24],
['key' => 'category_id', 'header' => '分类ID', 'width' => 12, 'align' => 'center'],
['key' => 'price', 'header' => '参考价', 'width' => 14, 'align' => 'right'],
['key' => 'status', 'header' => '状态', 'width' => 10, 'align' => 'center'],
],
'rows' => $rows,
],
[
'title' => '关联报价单',
'sheet' => '报价单',
'subtitle' => '按商品编号回写;库存 -1 表示不限',
'columns' => [
['key' => 'id', 'header' => 'ID', 'width' => 10, 'align' => 'center'],
['key' => 'catalogue_id', 'header' => '商品ID', 'width' => 12, 'align' => 'center'],
['key' => 'identifier', 'header' => '商品编号', 'width' => 16],
['key' => 'title', 'header' => '商品名称', 'width' => 24],
['key' => 'specification', 'header' => '规格', 'width' => 20],
['key' => 'dimension', 'header' => '尺寸', 'width' => 16],
['key' => 'routine', 'header' => '常规价', 'width' => 14, 'align' => 'right'],
['key' => 'stock', 'header' => '库存', 'width' => 10, 'align' => 'center'],
['key' => 'status', 'header' => '状态', 'width' => 10, 'align' => 'center'],
],
'rows' => $priceRows,
],
],
];
}
/**
* 导入商品 + 报价单:先落商品,再按编号挂规格
*/
public function importRows(array $rows, array $priceSheets = []): array
{
$created = 0;
$updated = 0;
$priceCreated = 0;
$priceUpdated = 0;
$now = time();
DB::connection('business')->beginTransaction();
try {
foreach ($rows as $row) {
if (!is_array($row)) {
continue;
}
$identifier = trim((string) ($row['identifier'] ?? $row['商品编号'] ?? ''));
$title = trim((string) ($row['title'] ?? $row['商品名称'] ?? ''));
if ($title === '') {
continue;
}
$payload = [
'title' => $title,
'identifier' => $identifier,
'alias' => (string) ($row['alias'] ?? $row['别名'] ?? ''),
'category_id' => (int) ($row['category_id'] ?? $row['分类ID'] ?? 0),
'price' => (string) ($row['price'] ?? $row['参考价'] ?? ''),
'status' => $this->parseStatus($row['status'] ?? $row['状态'] ?? 0),
'updated_at' => $now,
];
$exists = $identifier !== ''
? CatalogueModel::where('identifier', $identifier)->where('deleted_at', 0)->first()
: null;
if (!empty($exists)) {
CatalogueModel::where('id', $exists['id'])->update($payload);
$updated++;
} else {
$payload['created_at'] = $now;
CatalogueModel::insert($payload);
$created++;
}
}
[$priceCreated, $priceUpdated] = $this->importPriceSheets($priceSheets, $now);
DB::connection('business')->commit();
} catch (Exception $e) {
DB::connection('business')->rollBack();
$this->utils->errorThrow($e->getMessage());
}
return [
'created' => $created,
'updated' => $updated,
'price_created' => $priceCreated,
'price_updated' => $priceUpdated,
];
}
/**
* 报价单里真正有值的材质列
*/
@@ -164,7 +302,7 @@ class CatalogueService extends BaseService
private function normalize(array $params): array
{
foreach (['cover', 'pdf'] as $field) {
foreach (['cover', 'pdf', 'video'] as $field) {
if (array_key_exists($field, $params)) {
$params[$field] = $this->media->firstOf($params[$field]);
}
@@ -190,4 +328,100 @@ class CatalogueService extends BaseService
$this->utils->errorThrow('商品编号已存在:' . $identifier);
}
}
/**
* 导入报价单:优先商品编号,其次商品ID;同商品同规格同尺寸则更新
*/
private function importPriceSheets(array $rows, int $now): array
{
$created = 0;
$updated = 0;
foreach ($rows as $row) {
if (!is_array($row)) {
continue;
}
$catalogueId = $this->resolveCatalogueId($row);
$specification = trim((string) ($row['specification'] ?? $row['规格'] ?? ''));
if ($catalogueId <= 0 || $specification === '') {
continue;
}
$dimension = (string) ($row['dimension'] ?? $row['尺寸'] ?? '');
$payload = [
'catalogue_id' => $catalogueId,
'specification' => $specification,
'dimension' => $dimension,
'routine' => (string) ($row['routine'] ?? $row['常规价'] ?? ''),
'stock' => $this->parseStock($row['stock'] ?? $row['库存'] ?? -1),
'status' => $this->parseStatus($row['status'] ?? $row['状态'] ?? 0),
'updated_at' => $now,
];
$id = (int) ($row['id'] ?? $row['ID'] ?? 0);
$exists = $id > 0
? PriceSheetModel::where('id', $id)->where('catalogue_id', $catalogueId)->where('deleted_at', 0)->first()
: null;
if (empty($exists)) {
$exists = PriceSheetModel::where('catalogue_id', $catalogueId)
->where('specification', $specification)
->where('dimension', $dimension)
->where('deleted_at', 0)
->first();
}
if (!empty($exists)) {
PriceSheetModel::where('id', $exists['id'])->update($payload);
$updated++;
} else {
$payload['created_at'] = $now;
PriceSheetModel::insert($payload);
$created++;
}
}
return [$created, $updated];
}
/**
* 报价单行挂到哪件商品:编号优先,兼容导出里的商品ID
*/
private function resolveCatalogueId(array $row): int
{
$identifier = trim((string) ($row['identifier'] ?? $row['商品编号'] ?? ''));
if ($identifier !== '') {
$cat = CatalogueModel::where('identifier', $identifier)->where('deleted_at', 0)->first();
if (!empty($cat)) {
return (int) $cat['id'];
}
}
$id = (int) ($row['catalogue_id'] ?? $row['商品ID'] ?? 0);
if ($id <= 0) {
return 0;
}
$exists = CatalogueModel::where('id', $id)->where('deleted_at', 0)->exists();
return $exists ? $id : 0;
}
/**
* Excel 状态列可能是「上架/下架」或 0/1,统一成库里的数字
*/
private function parseStatus(mixed $value): int
{
$raw = trim((string) $value);
if (in_array($raw, ['上架', '启用', '正常', '0', ''], true)) {
return 0;
}
if (in_array($raw, ['下架', '禁用', '1'], true)) {
return 1;
}
return ((int) $raw) === 1 ? 1 : 0;
}
/**
* 库存:空 / 不限 → -1
*/
private function parseStock(mixed $value): int
{
$raw = trim((string) $value);
if ($raw === '' || in_array($raw, ['不限', '无限', '-1'], true)) {
return -1;
}
return (int) $raw;
}
}

View File

@@ -100,4 +100,84 @@ class FactoryInfoService extends BaseService
{
return $this->save($id, ['status' => (int) $status]);
}
/**
* 导出工厂表:只回结构化数据,xlsx 由前端 ExcelJS 美化
*/
public function exportExcel(): array
{
$rows = FactoryInfoModel::where('deleted_at', 0)->orderByDesc('id')->get([
'id', 'name', 'phone', 'classification', 'address', 'status',
])->toArray();
foreach ($rows as &$row) {
$row['status'] = (int) ($row['status'] ?? 0) === 0 ? '启用' : '禁用';
}
unset($row);
return [
'filename' => 'factory.xlsx',
'title' => '工厂信息',
'sheet' => '工厂',
'columns' => [
['key' => 'id', 'header' => 'ID', 'width' => 10, 'align' => 'center'],
['key' => 'name', 'header' => '工厂名称', 'width' => 22],
['key' => 'phone', 'header' => '电话', 'width' => 16],
['key' => 'classification', 'header' => '分类ID', 'width' => 12, 'align' => 'center'],
['key' => 'address', 'header' => '地址', 'width' => 32],
['key' => 'status', 'header' => '状态', 'width' => 10, 'align' => 'center'],
],
'rows' => $rows,
];
}
/**
* 导入工厂:前端 ExcelJS 拆好的行,按 name 更新
*/
public function importRows(array $rows): array
{
$created = 0;
$updated = 0;
$now = time();
foreach ($rows as $row) {
if (!is_array($row)) {
continue;
}
$name = trim((string) ($row['name'] ?? $row['工厂名称'] ?? ''));
if ($name === '') {
continue;
}
$payload = [
'name' => $name,
'phone' => (string) ($row['phone'] ?? $row['电话'] ?? ''),
'classification' => (int) ($row['classification'] ?? $row['分类ID'] ?? 0),
'address' => (string) ($row['address'] ?? $row['地址'] ?? ''),
'status' => $this->parseStatus($row['status'] ?? $row['状态'] ?? 0),
'updated_at' => $now,
];
$exists = FactoryInfoModel::where('name', $name)->where('deleted_at', 0)->first();
if (!empty($exists)) {
FactoryInfoModel::where('id', $exists['id'])->update($payload);
$updated++;
} else {
$payload['created_at'] = $now;
FactoryInfoModel::insert($payload);
$created++;
}
}
return ['created' => $created, 'updated' => $updated];
}
/**
* Excel 状态列可能是「启用/禁用」或 0/1,统一成库里的数字
*/
private function parseStatus(mixed $value): int
{
$raw = trim((string) $value);
if (in_array($raw, ['上架', '启用', '正常', '0', ''], true)) {
return 0;
}
if (in_array($raw, ['下架', '禁用', '1'], true)) {
return 1;
}
return ((int) $raw) === 1 ? 1 : 0;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\FeedbackModel;
/**
* 后台用户反馈
*/
class FeedbackService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = FeedbackModel::class;
$this->selectField = ['id', 'user_id', 'content', 'images', 'reply', 'status', 'created_at', 'updated_at'];
$this->queryField = ['user_id' => '=', 'status' => '=', 'content' => 'like'];
$this->with = ['user'];
}
public function list(): array
{
$result = $this->getPageList();
foreach ($result['items'] as &$item) {
$item['user_name'] = $item['user']['nick_name'] ?? '';
$item['user_phone'] = $item['user']['phone'] ?? '';
unset($item['user']);
}
unset($item);
return $result;
}
/**
* 回复反馈
*/
public function reply(int $id, string $reply): mixed
{
if ($id <= 0) {
$this->utils->errorThrow('参数错误');
}
$reply = trim($reply);
if ($reply === '') {
$this->utils->errorThrow('请填写回复');
}
return $this->save($id, [
'reply' => mb_substr($reply, 0, 500),
'status' => FeedbackModel::STATUS_REPLIED,
]);
}
public function delete($ids): mixed
{
return $this->del(is_array($ids) ? $ids : [$ids]);
}
}

View File

@@ -222,4 +222,16 @@ class ListService extends BaseService
'updated_at' => time(),
]);
}
/**
* 导出清单报价:后台画 xlsx,小程序用 text 分享
*/
public function exportQuote(int $id): array
{
$info = $this->detail($id);
if (!is_array($info)) {
$this->utils->errorThrow('清单不存在');
}
return \App\Service\common\ExcelCsvService::getInstance()->quoteFromList($info);
}
}

View File

@@ -91,6 +91,7 @@ class OrderCoreService
continue;
}
$quantity = max(1, (int) $item['quantity']);
StockService::getInstance()->assertAvailable((int) $item['price_sheet_id'], $quantity);
$unitPrice = (int) $item['unit_price'];
if ($unitPrice <= 0) {
$unitPrice = $price->resolveUnitPrice($sheet['routine'] ?? '', (string) $item['material_key'], $multiplier);
@@ -152,6 +153,9 @@ class OrderCoreService
}
unset($row);
OrderItemModel::insert($rows);
foreach ($rows as $row) {
StockService::getInstance()->deduct((int) $row['price_sheet_id'], (int) $row['quantity']);
}
ListModel::where('id', $list['id'])->update(['status' => 1, 'updated_at' => $now]);
});
@@ -270,6 +274,9 @@ class OrderCoreService
}
$this->applyPaid($orderId, (int) $payment['amount'], $now);
});
if ($status === OrderPaymentModel::STATUS_CONFIRMED) {
$this->notifySubscribe($orderId, 'pay');
}
return $this->detail($orderId);
}
@@ -308,11 +315,14 @@ class OrderCoreService
public function confirmWechatPay(string $outTradeNo, string $transactionId, int $amount): bool
{
$done = false;
DB::connection('business')->transaction(function () use ($outTradeNo, $transactionId, $amount, &$done) {
$fresh = false;
$orderId = 0;
DB::connection('business')->transaction(function () use ($outTradeNo, $transactionId, $amount, &$done, &$fresh, &$orderId) {
$payment = OrderPaymentModel::where('out_trade_no', $outTradeNo)->lockForUpdate()->first();
if (empty($payment)) {
return;
}
$orderId = (int) $payment['order_id'];
if ((int) $payment['status'] === OrderPaymentModel::STATUS_CONFIRMED) {
$done = true;
return;
@@ -325,9 +335,13 @@ class OrderCoreService
'audited_at' => $now,
'updated_at' => $now,
]);
$this->applyPaid((int) $payment['order_id'], $amount > 0 ? $amount : (int) $payment['amount'], $now);
$this->applyPaid($orderId, $amount > 0 ? $amount : (int) $payment['amount'], $now);
$done = true;
$fresh = true;
});
if ($fresh && $orderId > 0) {
$this->notifySubscribe($orderId, 'pay');
}
return $done;
}
@@ -367,6 +381,7 @@ class OrderCoreService
'updated_at' => $now,
]);
});
$this->notifySubscribe($orderId, 'ship');
return $this->detail($orderId);
}
@@ -405,4 +420,47 @@ class OrderCoreService
}
return $order->toArray();
}
/**
* 付款/发货后尽力发订阅消息,失败不影响主流程
*/
private function notifySubscribe(int $orderId, string $scene): void
{
if ($orderId <= 0) {
return;
}
try {
$order = OrderModel::where('id', $orderId)->first();
if (empty($order)) {
return;
}
$user = WxUserModel::where('id', (int) $order['user_id'])->first(['open_id']);
$openId = (string) ($user['open_id'] ?? '');
if ($openId === '') {
return;
}
$app = \App\Service\wx\WxAppService::getInstance()->current();
$tplKey = $scene === 'ship' ? 'subscribe_ship_tpl' : 'subscribe_pay_tpl';
$templateId = trim((string) ($app[$tplKey] ?? ''));
if ($templateId === '') {
return;
}
$price = PriceService::getInstance();
$page = 'pages/order/detail?id=' . $orderId;
$data = $scene === 'ship'
? [
'character_string1' => ['value' => (string) $order['order_no']],
'thing2' => ['value' => '订单已发货'],
'time3' => ['value' => date('Y-m-d H:i')],
]
: [
'character_string1' => ['value' => (string) $order['order_no']],
'amount2' => ['value' => $price->centsToYuan((int) $order['total_amount'])],
'thing3' => ['value' => '付款成功'],
];
\App\Service\wx\WxMiniService::getInstance()->sendSubscribe($openId, $templateId, $page, $data);
} catch (\Throwable) {
// 订阅消息是附加能力,模板字段对不上或用户未授权都不能挡住收款/发货
}
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\ListModel;
use App\Models\business\OrderModel;
use App\Models\business\OrderPaymentModel;
use App\Models\business\WxUserModel;
@@ -188,6 +189,15 @@ class OrderService extends BaseService
$stat['auditing'] = OrderPaymentModel::where('deleted_at', 0)
->where('status', OrderPaymentModel::STATUS_AUDITING)
->count();
$stat['list_count'] = ListModel::where('deleted_at', 0)->count();
$stat['wx_user_count'] = WxUserModel::where('deleted_at', 0)->count();
$statusMap = [];
foreach ($stat['status'] as $row) {
$statusMap[(int) $row['status']] = (int) $row['count'];
}
$stat['unpaid'] = $statusMap[OrderModel::STATUS_UNPAID] ?? 0;
$stat['paid'] = $statusMap[OrderModel::STATUS_PAID] ?? 0;
$stat['shipped'] = $statusMap[OrderModel::STATUS_SHIPPED] ?? 0;
return $stat;
}
}

View File

@@ -26,7 +26,7 @@ class PriceSheetService extends BaseService
$this->selectField = array_merge(
['id', 'catalogue_id', 'specification', 'dimension'],
PriceSheetModel::MATERIAL_FIELDS,
['status', 'created_at', 'updated_at']
['stock', 'status', 'created_at', 'updated_at']
);
$this->queryField = ['catalogue_id' => '=', 'specification' => 'like', 'status' => '='];
$this->orderBy = ['name' => 'id', 'sort' => 'asc'];
@@ -195,6 +195,9 @@ class PriceSheetService extends BaseService
$payload[$field] = is_scalar($row[$field]) ? (string) $row[$field] : '';
}
}
if (array_key_exists('stock', $row)) {
$payload['stock'] = (int) $row['stock'];
}
return $payload;
}

View File

@@ -0,0 +1,67 @@
<?php
namespace App\Service\business;
use App\Models\business\PriceSheetModel;
use App\Service\common\UtilsService;
/**
* 规格库存:stock=-1 表示不限,兼容历史数据全是不限。
*/
class StockService
{
private static mixed $_instance;
public static function getInstance(): null|static
{
$name = get_called_class();
if (!isset(self::$_instance[$name])) {
self::$_instance[$name] = new static();
}
return self::$_instance[$name];
}
/**
* 加入清单 / 下单前校验。sheetId=0 时跳过(还没选规格)。
*/
public function assertAvailable(int $sheetId, int $quantity): void
{
if ($sheetId <= 0) {
return;
}
$sheet = PriceSheetModel::where('id', $sheetId)->where('deleted_at', 0)->first();
if (empty($sheet)) {
UtilsService::getInstance()->errorThrow('规格不存在');
}
$stock = (int) ($sheet['stock'] ?? -1);
if ($stock < 0) {
return;
}
if ($stock < $quantity) {
UtilsService::getInstance()->errorThrow('库存不足(剩余 ' . $stock . ')');
}
}
/**
* 下单成功后扣库存;不限库存不写库。
*/
public function deduct(int $sheetId, int $quantity): void
{
if ($sheetId <= 0 || $quantity <= 0) {
return;
}
$sheet = PriceSheetModel::where('id', $sheetId)->where('deleted_at', 0)->first();
if (empty($sheet)) {
return;
}
$stock = (int) ($sheet['stock'] ?? -1);
if ($stock < 0) {
return;
}
$next = max(0, $stock - $quantity);
PriceSheetModel::where('id', $sheetId)->update([
'stock' => $next,
'updated_at' => time(),
]);
}
}

View File

@@ -56,6 +56,9 @@ class WxTemplateSchemaService
'header' => ['gradient', 'image', 'plain', 'split', 'editorial'],
'menu' => ['grid', 'list', 'card', 'tile', 'compact'],
],
'package' => [
'list' => ['card', 'featured', 'magazine', 'list'],
],
'effect' => [
'transition' => ['fade', 'slide', 'zoom', 'none'],
'skeleton' => ['shimmer', 'pulse', 'none'],
@@ -70,7 +73,7 @@ class WxTemplateSchemaService
*/
public const PAGE_SECTION_TYPES = [
'home' => ['search', 'hero', 'category', 'package', 'product'],
'package' => ['list'],
'package' => ['search', 'list'],
'catalog' => ['filter', 'list'],
'search' => ['search', 'list'],
'product' => ['gallery', 'info', 'spec', 'price', 'action'],
@@ -90,7 +93,7 @@ class WxTemplateSchemaService
'filter' => ['chip', 'bar', 'sidebar', 'hidden'],
'list' => [
'card', 'table', 'timeline', 'waterfall', 'grid', 'list',
'masonry', 'featured', 'shelf', 'compact', 'airy', 'mosaic', 'duo',
'masonry', 'featured', 'magazine', 'shelf', 'compact', 'airy', 'mosaic', 'duo',
'ticket', 'stacked',
],
'gallery' => ['swiper', 'stack', 'fullbleed', 'peek', 'fade', 'coverflow', 'mosaic', 'filmstrip'],
@@ -111,6 +114,7 @@ class WxTemplateSchemaService
'package' => ['card', 'scroll', 'featured', 'magazine'],
],
'package' => [
'search' => ['bar', 'overlay', 'pill', 'float'],
'list' => ['card', 'featured', 'magazine', 'list'],
],
'catalog' => [
@@ -198,6 +202,7 @@ class WxTemplateSchemaService
'mosaic' => '马赛克',
'duo' => '对开',
'card' => '卡片',
'magazine' => '刊名条',
'table' => '表格',
'timeline' => '时间线',
'ticket' => '票根',