feat: 添加产品购买链接相关接口
This commit is contained in:
339
app/admin/controller/v1/ProductPurchaseLink.php
Normal file
339
app/admin/controller/v1/ProductPurchaseLink.php
Normal file
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\controller\v1;
|
||||
|
||||
use app\admin\model\v1\ProductModel;
|
||||
use app\admin\model\v1\ProductPurchaseLinkModel;
|
||||
use app\admin\model\v1\ProductPurchaseLinkPlatformModel;
|
||||
use app\admin\validate\v1\ProductPurchaseLinkValidate;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use think\facade\Db;
|
||||
|
||||
class ProductPurchaseLink
|
||||
{
|
||||
/**
|
||||
* 获取购买平台
|
||||
*/
|
||||
public function platforms()
|
||||
{
|
||||
$platforms = ProductPurchaseLinkPlatformModel::withoutField([
|
||||
'language_id',
|
||||
'desc',
|
||||
'sort',
|
||||
'created_at'
|
||||
])
|
||||
->language(request()->lang_id)
|
||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||
->select();
|
||||
|
||||
return success('获取成功', $platforms);
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买链接分布数据
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$params = request()->param([
|
||||
'name' => '',
|
||||
'spu' => '',
|
||||
'page/d' => 1,
|
||||
'size/d' => 10
|
||||
]);
|
||||
|
||||
$links = ProductModel::alias('pd')
|
||||
->field([
|
||||
'pd.id',
|
||||
'pd.spu',
|
||||
'pd.name',
|
||||
'CASE WHEN pd.is_show = 0 THEN "已下架" WHEN pd.is_show = 1 THEN "已上架" END' => 'is_show',
|
||||
'pf.id' => 'platform_id',
|
||||
'pf.platform' => 'platform_name',
|
||||
'min(pl.id)' => 'link_id',
|
||||
'pl.link'
|
||||
])
|
||||
->leftJoin('product_purchase_link pl', 'pl.product_id = pd.id')
|
||||
->leftJoin('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||
->where(function ($query) use ($params) {
|
||||
$query->where('pd.is_show', '=', 1);
|
||||
if (!empty($params['name'])) {
|
||||
$query->where('pd.name', 'like', '%' . $params['name'] . '%');
|
||||
}
|
||||
if (!empty($params['spu'])) {
|
||||
$query->where('pd.spu', 'like', '%' . $params['spu'] . '%');
|
||||
}
|
||||
})
|
||||
->where('pd.language_id', '=', request()->lang_id)
|
||||
->group('pd.id')
|
||||
->order(['pl.sort' => 'asc', 'pl.id' => 'desc', 'pd.id' => 'desc'])
|
||||
->paginate([
|
||||
'list_rows' => $params['size'],
|
||||
'page' => $params['page'],
|
||||
]);
|
||||
if ($links->isEmpty()) {
|
||||
return success('获取成功', []);
|
||||
}
|
||||
|
||||
$others = ProductPurchaseLinkModel::alias('pl')
|
||||
->field([
|
||||
'pl.product_id',
|
||||
'pl.platform_id',
|
||||
'pf.platform' => 'platform_name',
|
||||
'pl.id' => 'link_id',
|
||||
'pl.link'
|
||||
])
|
||||
->join('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||
->where('pl.language_id', '=', request()->lang_id)
|
||||
->where('pl.product_id', 'in', array_column($links->items(), 'id'))
|
||||
->where('pl.id', 'not in', array_column($links->items(), 'link_id'))
|
||||
->select();
|
||||
if (!$others->isEmpty()) {
|
||||
$others_map = [];
|
||||
$others_arr = $others->toArray();
|
||||
foreach ($others_arr as $other) {
|
||||
$product_id = $other['product_id'];
|
||||
unset($other['product_id']);
|
||||
$others_map[$product_id][] = $other;
|
||||
}
|
||||
$links->each(function ($item) use ($others_map) {
|
||||
if (!empty($others_map[$item['id']])) {
|
||||
$item['rowspan'] = $others_map[$item['id']];
|
||||
}
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
return success('获取成功', $links);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入
|
||||
*/
|
||||
public function import()
|
||||
{
|
||||
$file = request()->file('file');
|
||||
if ($file->getSize() > 20 * 1024 * 1024) {
|
||||
return error('上传文件不能超过20M');
|
||||
}
|
||||
|
||||
$reader = IOFactory::createReader('Xlsx');
|
||||
|
||||
// 读取文件
|
||||
$spreadsheet = $reader->load($file->getRealPath());
|
||||
|
||||
// 获取活动sheet
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// 获取行数
|
||||
$rows = $sheet->getHighestRow();
|
||||
|
||||
// 从表格获取数据
|
||||
$xlsx_data = [];
|
||||
for ($i=2; $i <= $rows; $i++) {
|
||||
$xlsx_data[$i] = [
|
||||
'spu' => $sheet->getCell('A' . $i)->getValue(),
|
||||
'platform' => $sheet->getCell('B' . $i)->getValue(),
|
||||
'link' => $sheet->getCell('C' . $i)->getValue(),
|
||||
];
|
||||
}
|
||||
|
||||
$platforms_name = array_unique(array_column($xlsx_data, 'platform'));
|
||||
$platforms_map = ProductPurchaseLinkPlatformModel::language(request()->lang_id)
|
||||
->where('platform', 'in', $platforms_name)
|
||||
->column('id', 'platform');
|
||||
|
||||
$data = [];
|
||||
$errors = [];
|
||||
$chunks = array_chunk($xlsx_data, 500, true);
|
||||
// 分组验证每行,并组装数据
|
||||
foreach ($chunks as $chunk) {
|
||||
$spus = array_unique(array_column($chunk, 'spu'));
|
||||
$products_map = ProductModel::language(request()->lang_id)
|
||||
->where('spu', 'in', $spus)
|
||||
->column('id', 'spu');
|
||||
|
||||
$items = [];
|
||||
foreach ($chunk as $r => $it) {
|
||||
if (empty($platforms_map[$it['platform']])) {
|
||||
$errors[] = sprintf("第%d行,平台名称错误", $r);
|
||||
continue;
|
||||
}
|
||||
if (empty($products_map[$it['spu']])) {
|
||||
$errors[] = sprintf("第%d行,型号不存在", $r);
|
||||
continue;
|
||||
}
|
||||
$items[] = [
|
||||
'language_id' => request()->lang_id,
|
||||
'product_id' => $products_map[$it['spu']],
|
||||
'platform_id' => $platforms_map[$it['platform']],
|
||||
'link' => $it['link'],
|
||||
'sort' => 0,
|
||||
];
|
||||
}
|
||||
if (!empty($items)) {
|
||||
$data[] = $items;
|
||||
}
|
||||
}
|
||||
|
||||
// 组装sql,并执行
|
||||
if (!empty($data)) {
|
||||
$link_model = new ProductPurchaseLinkModel();
|
||||
$sql = sprintf(
|
||||
'REPLACE INTO %s (id, language_id, product_id, platform_id, link, sort) VALUES ',
|
||||
$link_model->getTable(),
|
||||
);
|
||||
foreach ($data as $items) {
|
||||
$products_id = array_unique(array_column($items, 'product_id'));
|
||||
$links = $link_model->field([
|
||||
'id',
|
||||
'product_id',
|
||||
'platform_id'
|
||||
])
|
||||
->where('product_id', 'in', $products_id)
|
||||
->select();
|
||||
$links_map = [];
|
||||
if (!$links->isEmpty()) {
|
||||
foreach ($links as $link) {
|
||||
$links_map[$link['product_id'] . '_' . $link['platform_id']] = $link['id'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($items as $item) {
|
||||
$item['id'] = null;
|
||||
if (!empty($links_map[$item['product_id'] . '_' . $item['platform_id']])) {
|
||||
$item['id'] = $links_map[$item['product_id'] . '_' . $item['platform_id']];
|
||||
}
|
||||
$sql .= sprintf(
|
||||
'(%d, %d, %d, %d, "%s", %d),',
|
||||
$item['id'],
|
||||
$item['language_id'],
|
||||
$item['product_id'],
|
||||
$item['platform_id'],
|
||||
$item['link'],
|
||||
$item['sort']
|
||||
);
|
||||
}
|
||||
}
|
||||
Db::execute(rtrim($sql, ','));
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
return error(implode(";\n", $errors));
|
||||
}
|
||||
|
||||
return success('导入成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
$schema = [
|
||||
'spu' => '型号',
|
||||
'platform' => '平台',
|
||||
'link' => '链接'
|
||||
];
|
||||
|
||||
// 获取导出数据
|
||||
$data = $this->getExportLinkData();
|
||||
|
||||
// 获取Spreadsheet对象
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// 写入表头
|
||||
$title = array_values($schema);
|
||||
$title_col = 'A';
|
||||
foreach ($title as $value) {
|
||||
// 单元格内容写入
|
||||
$sheet->setCellValue($title_col . '1', $value);
|
||||
$title_col++;
|
||||
}
|
||||
|
||||
// 写入数据
|
||||
$row = 2;
|
||||
$keys = array_keys($schema);
|
||||
foreach ($data as $item) {
|
||||
$data_col = 'A';
|
||||
foreach ($keys as $key) {
|
||||
$sheet->setCellValue($data_col . $row, $item[$key] ?? '');
|
||||
$data_col++;
|
||||
}
|
||||
$row++;
|
||||
}
|
||||
|
||||
flush();
|
||||
ob_flush();
|
||||
$filename = date('YmdHms');
|
||||
header('Access-Control-Expose-Headers: Content-Disposition');
|
||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; Charset=UTF-8');
|
||||
header('Content-Disposition: attachment;filename=' . $filename . '.xlsx');
|
||||
header('Cache-Control: max-age=0');
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
||||
$writer->save('php://output');
|
||||
}
|
||||
private function getExportLinkData()
|
||||
{
|
||||
$params = request()->param([
|
||||
'name' => '',
|
||||
'spu' => ''
|
||||
]);
|
||||
|
||||
return ProductModel::alias('pd')
|
||||
->field([
|
||||
'pd.spu',
|
||||
'pf.platform',
|
||||
'pl.link'
|
||||
])
|
||||
->leftJoin('product_purchase_link pl', 'pl.product_id = pd.id')
|
||||
->leftJoin('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||
->where(function ($query) use ($params) {
|
||||
$query->where('pd.is_show', '=', 1);
|
||||
if (!empty($params['name'])) {
|
||||
$query->where('pd.name', 'like', '%' . $params['name'] . '%');
|
||||
}
|
||||
if (!empty($params['spu'])) {
|
||||
$query->where('pd.spu', 'like', '%' . $params['spu'] . '%');
|
||||
}
|
||||
})
|
||||
->where('pd.language_id', '=', request()->lang_id)
|
||||
->order(['pl.sort' => 'asc', 'pl.id' => 'desc', 'pd.id' => 'desc'])
|
||||
->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购买链接
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
$put = request()->put([
|
||||
'link',
|
||||
'platform_id'
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'link' => $put['link'],
|
||||
'platform_id' => $put['platform_id']
|
||||
];
|
||||
$validate = new ProductPurchaseLinkValidate;
|
||||
if (!$validate->scene('update')->check($data)) {
|
||||
return error($validate->getError());
|
||||
}
|
||||
|
||||
$link = ProductPurchaseLinkModel::bypk($data['id'])->find();
|
||||
if (empty($link)) {
|
||||
return error('请确认操作对象是否存在');
|
||||
}
|
||||
|
||||
if (!$link->save($data)) {
|
||||
return error('操作失败');
|
||||
}
|
||||
return success('操作成功');
|
||||
}
|
||||
}
|
||||
31
app/admin/model/v1/ProductPurchaseLinkModel.php
Normal file
31
app/admin/model/v1/ProductPurchaseLinkModel.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductPurchaseLinkBaseModel;
|
||||
|
||||
/**
|
||||
* 产品 - 购买链接模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductPurchaseLinkModel extends ProductPurchaseLinkBaseModel
|
||||
{
|
||||
// 关联产品
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductModel::class, 'product_id', 'id');
|
||||
}
|
||||
|
||||
// 关联平台
|
||||
public function platform()
|
||||
{
|
||||
return $this->belongsTo(ProductPurchaseLinkPlatformModel::class, 'platform_id', 'id');
|
||||
}
|
||||
|
||||
// 根据语言查询
|
||||
public function scopeLanguage($query, $value)
|
||||
{
|
||||
$query->where('language_id', '=', $value);
|
||||
}
|
||||
}
|
||||
19
app/admin/model/v1/ProductPurchaseLinkPlatformModel.php
Normal file
19
app/admin/model/v1/ProductPurchaseLinkPlatformModel.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use app\common\model\ProductPurchasePlatformBaseModel;
|
||||
|
||||
/**
|
||||
* 产品 - 采购链接平台模型
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ProductPurchaseLinkPlatformModel extends ProductPurchasePlatformBaseModel
|
||||
{
|
||||
// 根据语言查询
|
||||
public function scopeLanguage($query, $value)
|
||||
{
|
||||
$query->where('language_id', '=', $value);
|
||||
}
|
||||
}
|
||||
@@ -184,6 +184,24 @@ Route::group('v1', function () {
|
||||
Route::delete('delete/:id', 'ProductCategory/delete');
|
||||
});
|
||||
|
||||
// 产品购买链接
|
||||
Route::group('buypass', function () {
|
||||
// 购买链接平台列表
|
||||
Route::get('platforms', 'ProductPurchaseLink/platforms');
|
||||
|
||||
// 购买链接列表
|
||||
Route::get('index', 'ProductPurchaseLink/index');
|
||||
|
||||
// 购买链接导入
|
||||
Route::post('import', 'ProductPurchaseLink/import');
|
||||
|
||||
// 购买链接导出
|
||||
Route::get('export', 'ProductPurchaseLink/export');
|
||||
|
||||
// 购买链接更新
|
||||
Route::put('update/:id', 'ProductPurchaseLink/update');
|
||||
});
|
||||
|
||||
// 产品回收站
|
||||
Route::group('trash', function () {
|
||||
// 产品回收站列表
|
||||
|
||||
45
app/admin/validate/v1/ProductPurchaseLinkValidate.php
Normal file
45
app/admin/validate/v1/ProductPurchaseLinkValidate.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\validate\v1;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class ProductPurchaseLinkValidate extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'id' => 'require|integer',
|
||||
'link' => 'url|max:255',
|
||||
'platform_id' => 'integer'
|
||||
];
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'id.require' => 'id不能为空',
|
||||
'id.integer' => 'id字段类型错误',
|
||||
'link.url' => '链接格式不正确',
|
||||
'link.max' => '链接不能超过255个字符',
|
||||
'platform_id.integer' => '平台id类型错误'
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* 更新场景
|
||||
*/
|
||||
public function sceneUpdate()
|
||||
{
|
||||
return $this->only(['id', 'link', 'platform_id'])->remove('id', 'require');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user