Merge branch 'dev'

This commit is contained in:
zpc 2025-06-25 18:27:04 +08:00
commit 0c8bc4a6e9
32 changed files with 5220 additions and 119 deletions

View File

@ -22,16 +22,17 @@ abstract class MyController extends BaseController
if ($platform == "APP_ANDROID" || $platform == "APP_IOS") {
// 密钥和加密算法
$secretKey = 'g6R@9!zB2fL#1cVm'; // 必须是 16/24/32 位
$cipher = 'AES-128-CBC';
$iv = substr(md5($secretKey), 0, 16); // IV 长度必须是 16 字节
// $secretKey = 'g6R@9!zB2fL#1cVm'; // 必须是 16/24/32 位
// $cipher = 'AES-128-CBC';
// $iv = substr(md5($secretKey), 0, 16); // IV 长度必须是 16 字节
// 对 $data 进行加密处理
$dataString = json_encode($data, JSON_UNESCAPED_UNICODE);
$encrypted = openssl_encrypt($dataString, $cipher, $secretKey, 0, $iv);
// $dataString = json_encode($data, JSON_UNESCAPED_UNICODE);
// $encrypted = openssl_encrypt($dataString, $cipher, $secretKey, 0, $iv);
return [
'ret' => $status,
'payload' => $encrypted,
// 'payload' => $data,//$encrypted,
'data' => $data,
'note' => $msg,
'ts' => time(), // 当前时间戳
];
@ -39,6 +40,17 @@ abstract class MyController extends BaseController
$request = request();
return compact('status', 'msg', 'data');
}
protected function encryption($data)
{
$secretKey = 'g6R@9!zB2fL#1cVm'; // 必须是 16/24/32 位
$cipher = 'AES-128-CBC';
$iv = substr(md5($secretKey), 0, 16); // IV 长度必须是 16 字节
// 对 $data 进行加密处理
$dataString = json_encode($data, JSON_UNESCAPED_UNICODE);
$encrypted = openssl_encrypt($dataString, $cipher, $secretKey, 0, $iv);
return $encrypted;
}
/**
* 返回操作成功json

View File

@ -0,0 +1,179 @@
<?php
namespace app\admin\controller;
use think\facade\View;
use think\facade\Db;
use app\common\model\FFCategories;
class FFCategoriesController extends Base
{
/**
* 商品分类列表
*/
public function index()
{
if (request()->isAjax()) {
$limit = input('param.limit', 15);
$page = input('param.page', 1);
$offset = ($page - 1) * $limit;
$category_name = input('param.category_name', '');
$status = input('param.status', '');
$where = [];
if ($category_name) {
$where[] = ['category_name', 'like', "%{$category_name}%"];
}
if ($status !== '') {
$where[] = ['status', '=', $status];
}
$res = FFCategories::where($where)
->order(['sort_order' => 'asc', 'id' => 'desc'])
->limit($offset, $limit)
->select();
$total = FFCategories::where($where)->count();
return $this->renderTable('获取成功', $total, $res, 0);
}
return View::fetch('FFCategories/index');
}
/**
* 添加商品分类
*/
public function add()
{
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'category_name' => 'require',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
// 默认值设置
if (!isset($param['parent_id'])) {
$param['parent_id'] = 0;
$param['category_level'] = 1;
} else if ($param['parent_id'] > 0) {
// 查询父级分类的等级,并设置当前分类的等级为父级+1
$parent = FFCategories::where('id', $param['parent_id'])->find();
if (!$parent) {
return $this->renderError('父级分类不存在');
}
$param['category_level'] = $parent['category_level'] + 1;
// 分类最多支持3级
if ($param['category_level'] > 3) {
return $this->renderError('分类最多支持3级');
}
}
if (!isset($param['sort_order'])) {
$param['sort_order'] = 0;
}
if (!isset($param['status'])) {
$param['status'] = 1;
}
$res = FFCategories::create($param);
if ($res) {
return $this->renderSuccess('添加成功', ['url' => (string) url('ff_products')]);
} else {
return $this->renderError('添加失败');
}
}
// 获取父级分类列表
$parentList = FFCategories::where([
['category_level', '<', 3], // 只查询1级和2级分类作为父级
['status', '=', 1]
])
->order('sort_order', 'asc')
->select();
View::assign('parentList', $parentList);
return View::fetch('FFCategories/add');
}
/**
* 编辑商品分类
*/
public function edit()
{
$id = input('param.id', 0);
$info = FFCategories::where('id', $id)->find();
if (empty($info)) {
return $this->renderError('数据不存在');
}
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'category_name' => 'require',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
// 不允许修改分类级别和父级分类,因为会影响分类结构
unset($param['parent_id']);
unset($param['category_level']);
$res = FFCategories::update($param, ['id' => $id]);
if ($res) {
return $this->renderSuccess('编辑成功', ['url' => (string) url('ff_products')]);
} else {
return $this->renderError('编辑失败');
}
}
View::assign('info', $info);
return View::fetch('FFCategories/edit');
}
/**
* 修改分类状态
*/
public function status()
{
$id = input('param.id', 0);
$status = input('param.status', 0);
$res = FFCategories::update(['status' => $status], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 删除分类
*/
public function del()
{
$id = input('param.id', 0);
// 检查是否有子分类
$hasChildren = FFCategories::where('parent_id', $id)->count();
if ($hasChildren > 0) {
return $this->renderError('该分类下有子分类,无法删除');
}
$res = FFCategories::destroy($id);
if ($res) {
return $this->renderSuccess('删除成功');
} else {
return $this->renderError('删除失败');
}
}
}

View File

@ -0,0 +1,250 @@
<?php
namespace app\admin\controller;
use think\facade\View;
use think\facade\Db;
use app\common\model\FFCategories;
use app\common\model\FFProducts;
class FFProductsController extends Base
{
/**
* 商品列表
*/
public function index()
{
if (request()->isAjax()) {
$limit = input('param.limit', 15);
$page = input('param.page', 1);
$offset = ($page - 1) * $limit;
$product_name = input('param.product_name', '');
$status = input('param.status', '');
$is_hot = input('param.is_hot', '');
$is_new = input('param.is_new', '');
$is_recommend = input('param.is_recommend', '');
$category_name = input('param.category_name', '');
$where = [];
if ($product_name) {
$where[] = ['product_name', 'like', "%{$product_name}%"];
}
if ($status !== '') {
$where[] = ['status', '=', $status];
}
if ($is_hot !== '') {
$where[] = ['is_hot', '=', $is_hot];
}
if ($is_new !== '') {
$where[] = ['is_new', '=', $is_new];
}
if ($is_recommend !== '') {
$where[] = ['is_recommend', '=', $is_recommend];
}
if ($category_name) {
$where[] = ['category_name', 'like', "%{$category_name}%"];
}
$res = FFProducts::where($where)
->order('id', 'desc')
->limit($offset, $limit)
->select();
$total = FFProducts::where($where)->count();
return $this->renderTable('获取成功', $total, $res, 0);
}
return View::fetch('FFProducts/index');
}
/**
* 添加商品
*/
public function add()
{
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'product_name' => 'require',
'price' => 'require|float',
'stock' => 'require|number',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
// 处理多选的分类,转换为逗号分隔的字符串
if (isset($param['categories']) && is_array($param['categories'])) {
$param['category_name'] = implode(',', $param['categories']);
unset($param['categories']);
}
// 设置默认值
if (!isset($param['status'])) {
$param['status'] = 1;
}
if (!isset($param['sales'])) {
$param['sales'] = 0;
}
if (!isset($param['is_hot'])) {
$param['is_hot'] = 0;
}
if (!isset($param['is_new'])) {
$param['is_new'] = 0;
}
if (!isset($param['is_recommend'])) {
$param['is_recommend'] = 0;
}
$res = FFProducts::create($param);
if ($res) {
return $this->renderSuccess('添加成功', ['url' => (string) url('ff_products')]);
} else {
return $this->renderError('添加失败');
}
}
// 获取分类列表
$categories = FFCategories::where('status', 1)
->order('sort_order', 'asc')
->select();
View::assign('categories', $categories);
return View::fetch('FFProducts/add');
}
/**
* 编辑商品
*/
public function edit()
{
$id = input('param.id', 0);
$info = FFProducts::where('id', $id)->find();
if (empty($info)) {
return $this->renderError('数据不存在');
}
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'product_name' => 'require',
'price' => 'require|float',
'stock' => 'require|number',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
// 处理多选的分类,转换为逗号分隔的字符串
if (isset($param['categories']) && is_array($param['categories'])) {
$param['category_name'] = implode(',', $param['categories']);
unset($param['categories']);
}
$res = FFProducts::update($param, ['id' => $id]);
if ($res) {
return $this->renderSuccess('编辑成功', ['url' => (string) url('ff_products')]);
} else {
return $this->renderError('编辑失败');
}
}
// 获取分类列表
$categories = FFCategories::where('status', 1)
->order('sort_order', 'asc')
->select()->toArray();
// 将已有的分类名称转为数组
$selectedCategories = [];
if ($info['category_name']) {
$selectedCategories = explode(',', $info['category_name']);
}
View::assign('categories', $categories);
View::assign('selectedCategories', $selectedCategories);
View::assign('info', $info);
return View::fetch('FFProducts/edit');
}
/**
* 修改商品状态(上架/下架)
*/
public function status()
{
$id = input('param.id', 0);
$status = input('param.status', 0);
$res = FFProducts::update(['status' => $status], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 修改热销状态
*/
public function hot()
{
$id = input('param.id', 0);
$is_hot = input('param.is_hot', 0);
$res = FFProducts::update(['is_hot' => $is_hot], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 修改新品状态
*/
public function new()
{
$id = input('param.id', 0);
$is_new = input('param.is_new', 0);
$res = FFProducts::update(['is_new' => $is_new], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 修改推荐状态
*/
public function recommend()
{
$id = input('param.id', 0);
$is_recommend = input('param.is_recommend', 0);
$res = FFProducts::update(['is_recommend' => $is_recommend], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 删除商品
*/
public function del()
{
$id = input('param.id', 0);
$res = FFProducts::destroy($id);
if ($res) {
return $this->renderSuccess('删除成功');
} else {
return $this->renderError('删除失败');
}
}
}

View File

@ -0,0 +1,185 @@
<?php
namespace app\admin\controller;
use think\facade\View;
use think\facade\Db;
use app\common\model\News;
class NewsController extends Base
{
/**
* 资讯列表
*/
public function index()
{
if (request()->isAjax()) {
$limit = input('param.limit', 15);
$page = input('param.page', 1);
$offset = ($page - 1) * $limit;
$title = input('param.title', '');
$status = input('param.status', '');
$where = [];
if ($title) {
$where[] = ['title', 'like', "%{$title}%"];
}
if ($status !== '') {
$where[] = ['status', '=', $status];
}
$res = News::where($where)
->order('id', 'desc')
->limit($offset, $limit)
->select();
$total = News::where($where)->count();
return $this->renderTable('获取成功', $total, $res, 0);
}
return View::fetch('News/index');
}
/**
* 添加资讯
*/
public function add()
{
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'title' => 'require',
// 'author_id' => 'require|number',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
$param['author_id'] = 1;
// 如果状态为发布,确保有发布时间
if (isset($param['status']) && $param['status'] == 1 && empty($param['publish_time'])) {
$param['publish_time'] = date('Y-m-d H:i:s');
}
$res = News::create($param);
if ($res) {
return $this->renderSuccess('添加成功', ['url' => (string) url('news')]);
} else {
return $this->renderError('添加失败');
}
}
return View::fetch('News/add');
}
/**
* 编辑资讯
*/
public function edit()
{
$id = input('param.id', 0);
$info = News::where('id', $id)->find();
if (empty($info)) {
return $this->renderError('数据不存在');
}
if (request()->isPost()) {
$param = input('post.');
$validate = $this->validate($param, [
'title' => 'require',
// 'author_id' => 'require|number',
]);
if (true !== $validate) {
return $this->renderError($validate);
}
$param['author_id'] = 1;
// 如果状态为发布,确保有发布时间
if (isset($param['status']) && $param['status'] == 1 && empty($param['publish_time'])) {
$param['publish_time'] = date('Y-m-d H:i:s');
}
$res = News::update($param, ['id' => $id]);
if ($res) {
return $this->renderSuccess('编辑成功', ['url' => (string) url('news')]);
} else {
return $this->renderError('编辑失败');
}
}
View::assign('info', $info);
return View::fetch('News/edit');
}
/**
* 修改资讯状态(发布/草稿)
*/
public function status()
{
$id = input('param.id', 0);
$status = input('param.status', 0);
// 如果状态为发布,确保有发布时间
$update = ['status' => $status];
if ($status == 1) {
$info = News::where('id', $id)->find();
if (!$info->publish_time) {
$update['publish_time'] = date('Y-m-d H:i:s');
}
}
$res = News::update($update, ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 修改热榜状态
*/
public function hot()
{
$id = input('param.id', 0);
$is_hot = input('param.is_hot', 0);
$res = News::update(['is_hot' => $is_hot], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 修改精选状态
*/
public function featured()
{
$id = input('param.id', 0);
$is_featured = input('param.is_featured', 0);
$res = News::update(['is_featured' => $is_featured], ['id' => $id]);
if ($res) {
return $this->renderSuccess('操作成功');
} else {
return $this->renderError('操作失败');
}
}
/**
* 删除资讯
*/
public function del()
{
$id = input('param.id', 0);
$res = News::destroy($id);
if ($res) {
return $this->renderSuccess('删除成功');
} else {
return $this->renderError('删除失败');
}
}
}

View File

@ -37,7 +37,7 @@ class Upload extends Base
}
// 文件格式校验
$ext = ['jpg', 'png', 'jpeg', 'JPG', 'PNG', 'JPEG', 'gif', 'apk', 'mp3'];
$ext = ['jpg', 'png', 'jpeg', 'JPG', 'PNG', 'JPEG', 'gif', 'apk', 'mp3','webp','avif'];
$type = substr($_FILES['file']['name'], strrpos($_FILES['file']['name'], '.') + 1);
if (!in_array($type, $ext)) {
return $this->renderError("文件格式错误");

View File

@ -400,6 +400,17 @@ Route::rule('float_ball_edit', 'FloatBall/edit', 'GET|POST');
Route::rule('float_ball_del', 'FloatBall/del', 'POST');
Route::rule('float_ball_status', 'FloatBall/status', 'POST');
#============================
#NewsController.php资讯管理
#============================
Route::rule('news', 'NewsController/index', 'GET|POST');
Route::rule('news_add', 'NewsController/add', 'GET|POST');
Route::rule('news_edit', 'NewsController/edit', 'GET|POST');
Route::rule('news_del', 'NewsController/del', 'POST');
Route::rule('news_status', 'NewsController/status', 'POST');
Route::rule('news_hot', 'NewsController/hot', 'POST');
Route::rule('news_featured', 'NewsController/featured', 'POST');
#============================
#Reward.php奖励管理
#============================
@ -457,7 +468,7 @@ Route::rule('Statistics/getCurrencyInfoData', 'Statistics/getCurrencyInfoData',
// 盒子下架日志相关路由
Route::post('goods_offshelf_read', 'GoodsOffshelfController/read');
Route::get('goods_offshelf_unread_count', 'GoodsOffshelfController/getUnreadCount');
#============================
# dynamicJs
@ -484,4 +495,25 @@ Route::rule('diamond_get_max_sort', 'Diamond/get_max_sort', 'GET');
#VerificationCode.php 验证码管理
#============================
Route::rule('verification_code', 'VerificationCode/index', 'GET|POST');
#============================
#News.php 新闻管理
#============================
Route::rule('news', 'News/index', 'GET|POST');
#============================
#FFProductsController.php商品分类管理
#============================
Route::rule('ff_categories', 'FFCategoriesController/index', 'GET|POST');
Route::rule('ff_categories_add', 'FFCategoriesController/add', 'GET|POST');
Route::rule('ff_categories_edit', 'FFCategoriesController/edit', 'GET|POST');
Route::rule('ff_categories_del', 'FFCategoriesController/del', 'POST');
Route::rule('ff_categories_status', 'FFCategoriesController/status', 'POST');
Route::rule('ff_products', 'FFProductsController/index', 'GET|POST');
Route::rule('ff_products_add', 'FFProductsController/add', 'GET|POST');
Route::rule('ff_products_edit', 'FFProductsController/edit', 'GET|POST');
Route::rule('ff_products_del', 'FFProductsController/del', 'POST');
Route::rule('ff_products_status', 'FFProductsController/status', 'POST');
Route::rule('ff_products_hot', 'FFProductsController/hot', 'POST');
Route::rule('ff_products_new', 'FFProductsController/new', 'POST');
Route::rule('ff_products_recommend', 'FFProductsController/recommend', 'POST');

View File

@ -0,0 +1,78 @@
{include file="Public/header3" /}
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="category_name" id="category_name" autocomplete="off" placeholder="请输入分类名称" class="layui-input"
lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">父级分类</label>
<div class="layui-input-block">
<select name="parent_id" lay-filter="parent_id">
<option value="0">顶级分类</option>
{foreach $parentList as $parent}
<option value="{$parent.id}">{$parent.category_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" name="sort_order" id="sort_order" value="0" autocomplete="off" placeholder="请输入排序数值" class="layui-input">
<div class="layui-form-mid layui-word-aux">数值越小越靠前</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="启用" checked>
<input type="radio" name="status" value="0" title="禁用">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
{include file="Public/footer" /}
<script>
layui.use(['form', 'layer', 'jquery'], function () {
var form = layui.form,
layer = layui.layer,
$ = layui.jquery;
// 表单提交
form.on('submit(saveBtn)', function (data) {
if (!data.field.category_name) {
layer.msg('分类名称不能为空', { icon: 2 });
return false;
}
$.ajax({
url: '{:url("/admin/ff_categories_add")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,85 @@
{include file="Public/header3" /}
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<input type="hidden" name="id" value="{$info.id}">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="category_name" id="category_name" autocomplete="off" placeholder="请输入分类名称" class="layui-input"
lay-verify="required" value="{$info.category_name}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">父级分类</label>
<div class="layui-input-block">
<div class="layui-form-mid">{if $info.parent_id == 0}顶级分类{else}父级ID{$info.parent_id}{/if}</div>
<div class="layui-form-mid layui-word-aux">为维护分类结构,不允许修改父级分类</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类层级</label>
<div class="layui-input-block">
<div class="layui-form-mid">
{if $info.category_level == 1}一级分类{elseif $info.category_level == 2}二级分类{else}三级分类{/if}
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" name="sort_order" id="sort_order" value="{$info.sort_order}" autocomplete="off" placeholder="请输入排序数值" class="layui-input">
<div class="layui-form-mid layui-word-aux">数值越小越靠前</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="启用" {if $info.status eq 1}checked{/if}>
<input type="radio" name="status" value="0" title="禁用" {if $info.status eq 0}checked{/if}>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
{include file="Public/footer" /}
<script>
layui.use(['form', 'layer', 'jquery'], function () {
var form = layui.form,
layer = layui.layer,
$ = layui.jquery;
// 表单提交
form.on('submit(saveBtn)', function (data) {
if (!data.field.category_name) {
layer.msg('分类名称不能为空', { icon: 2 });
return false;
}
$.ajax({
url: '{:url("/admin/ff_categories_edit")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,179 @@
{include file="Public:header3"/}
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-header">商品分类管理</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
<div class="layui-form-item">
<div class="layui-inline">
<input type="text" id="searchCategoryName" placeholder="请输入分类名称" class="layui-input">
</div>
<div class="layui-inline">
<select id="searchStatus">
<option value="">全部状态</option>
<option value="0">禁用</option>
<option value="1">启用</option>
</select>
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm" id="btnSearch"><i
class="layui-icon">&#xe615;</i>搜索</button>
<button class="layui-btn layui-btn-sm" id="btnAdd"><i class="layui-icon">&#xe654;</i>添加</button>
</div>
</div>
</div>
<table id="tableList" lay-filter="tableList"></table>
</div>
</div>
</div>
<!-- 表格操作列 -->
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
{{# if(d.status == 0){ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="enable">启用</a>
{{# }else{ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="disable">禁用</a>
{{# } }}
</script>
<!-- 状态模板 -->
<script type="text/html" id="statusTpl">
{{# if(d.status == 1){ }}
<span class="layui-badge layui-bg-green">启用</span>
{{# }else{ }}
<span class="layui-badge">禁用</span>
{{# } }}
</script>
<!-- 分类层级模板 -->
<script type="text/html" id="levelTpl">
{{# if(d.category_level == 1){ }}
<span>一级分类</span>
{{# }else if(d.category_level == 2){ }}
<span>二级分类</span>
{{# }else if(d.category_level == 3){ }}
<span>三级分类</span>
{{# } }}
</script>
{include file="Public/footer3" /}
<script>
layui.use(['table', 'form', 'jquery', 'layer', 'laydate'], function () {
var $ = layui.jquery;
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
// 渲染表格
var tableIns = table.render({
elem: '#tableList',
url: '{:url("/admin/ff_categories")}',
page: true,
cols: [[
{ type: 'numbers', title: '序号', width: 60 },
{ field: 'category_name', title: '分类名称', width: 200 },
{ field: 'category_level', title: '分类层级', width: 100, templet: '#levelTpl' },
{ field: 'parent_id', title: '父级ID', width: 100 },
{ field: 'sort_order', title: '排序', width: 80 },
{ field: 'status', title: '状态', width: 80, templet: '#statusTpl' },
{
field: 'create_time', title: '创建时间', width: 160, templet: function (d) {
return layui.util.toDateString(new Date(d.create_time).getTime(), 'yyyy-MM-dd HH:mm:ss');
}
},
{
field: 'update_time', title: '更新时间', width: 160, templet: function (d) {
return layui.util.toDateString(new Date(d.update_time).getTime(), 'yyyy-MM-dd HH:mm:ss');
}
},
{ title: '操作', toolbar: '#tableBar', width: 200 }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
text: {
none: '暂无相关数据'
}
});
// 搜索按钮点击事件
$('#btnSearch').click(function () {
tableIns.reload({
where: {
category_name: $('#searchCategoryName').val(),
status: $('#searchStatus').val()
},
page: {
curr: 1
}
});
});
// 添加按钮点击事件
$('#btnAdd').click(function () {
layer.open({
type: 2,
title: '添加商品分类',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: true,
content: '{:url("/admin/ff_categories_add")}'
});
});
// 表格工具条点击事件
table.on('tool(tableList)', function (obj) {
var data = obj.data;
var layEvent = obj.event;
if (layEvent === 'edit') {
layer.open({
type: 2,
title: '编辑商品分类',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: true,
content: '{:url("/admin/ff_categories_edit")}?id=' + data.id
});
} else if (layEvent === 'del') {
layer.confirm('确定要删除该分类吗?', function (i) {
layer.close(i);
layer.load(2);
$.post('{:url("/admin/ff_categories_del")}', { id: data.id }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
});
} else if (layEvent === 'enable') {
layer.load(2);
$.post('{:url("/admin/ff_categories_status")}', { id: data.id, status: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'disable') {
layer.load(2);
$.post('{:url("/admin/ff_categories_status")}', { id: data.id, status: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
}
});
});
</script>

View File

@ -0,0 +1,438 @@
{include file="Public/header3" /}
<link href="https://unpkg.com/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet" />
<style>
#editor—wrapper {
border: 1px solid #ccc;
z-index: 100;
}
#toolbar-container {
border-bottom: 1px solid #ccc;
}
#editor-container {
height: 500px;
}
.category-checkbox {
display: inline-block;
margin-right: 15px;
margin-bottom: 10px;
}
.custom-checkbox {
margin-right: 5px;
vertical-align: middle;
}
.category-label {
display: inline-block;
padding: 5px 10px;
border: 1px solid #e6e6e6;
background-color: #f2f2f2;
border-radius: 3px;
cursor: pointer;
margin-bottom: 5px;
font-size: 13px;
}
.category-label:hover {
background-color: #e6e6e6;
}
.category-label.checked {
background-color: #009688;
color: #fff;
border-color: #009688;
}
</style>
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<div class="layui-form-item">
<label class="layui-form-label">商品名称</label>
<div class="layui-input-block">
<input type="text" name="product_name" id="product_name" autocomplete="off" placeholder="请输入商品名称"
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所属分类</label>
<div class="layui-input-block" id="categoriesContainer">
{foreach $categories as $category}
<label class="category-label">
<input type="checkbox" lay-ignore class="custom-checkbox" name="categories[]"
value="{$category.category_name}" style="display:none;">
{$category.category_name}
</label>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">商品价格</label>
<div class="layui-input-inline">
<input type="text" name="price" id="price" autocomplete="off" placeholder="请输入价格" class="layui-input"
lay-verify="required|number">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">商品库存</label>
<div class="layui-input-inline">
<input type="text" name="stock" id="stock" autocomplete="off" placeholder="请输入库存" class="layui-input"
lay-verify="required|number" value="0">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">剩余库存</label>
<div class="layui-input-inline">
<input type="text" name="sales" id="sales" autocomplete="off" placeholder="请输入初始销量" class="layui-input"
value="0">
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">封面图</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadCover">上传封面图</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="coverPreview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="cover_image" id="cover_image" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片1</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail1">上传详情图1</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail1Preview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="detail_image1" id="detail_image1" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片2</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail2">上传详情图2</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail2Preview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="detail_image2" id="detail_image2" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片3</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail3">上传详情图3</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail3Preview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="detail_image3" id="detail_image3" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片4</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail4">上传详情图4</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail4Preview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="detail_image4" id="detail_image4" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
<textarea name="product_desc" id="product_desc" placeholder="请输入商品描述" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情内容</label>
<div class="layui-input-block">
<div id="editor—wrapper">
<div id="toolbar-container"><!-- 工具栏 --></div>
<div id="editor-container"><!-- 编辑器 --></div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">商品状态</label>
<div class="layui-input-inline">
<input type="radio" name="status" value="0" title="下架">
<input type="radio" name="status" value="1" title="上架" checked>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">热销商品</label>
<div class="layui-input-inline">
<input type="radio" name="is_hot" value="0" title="否" checked>
<input type="radio" name="is_hot" value="1" title="是">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">新品</label>
<div class="layui-input-inline">
<input type="radio" name="is_new" value="0" title="否">
<input type="radio" name="is_new" value="1" title="是" checked>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">推荐</label>
<div class="layui-input-inline">
<input type="radio" name="is_recommend" value="0" title="否">
<input type="radio" name="is_recommend" value="1" title="是" checked>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
{include file="Public/footer" /}
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
const { createEditor, createToolbar } = window.wangEditor
const editorConfig = {
placeholder: 'Type here...',
onChange(editor) {
const html = editor.getHtml()
console.log('editor content', html)
},
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
customUpload: async (file, insertFn) => {
console.log(file);
// 上传图片
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/admin/picture?dir=products', {
method: 'POST',
body: formData
});
console.log("res", res);
const result = await res.json();
// 成功后插入图片
insertFn(result.data.imgurl, '图片描述', result.data.imgurl);
}
}
const editor = createEditor({
selector: '#editor-container',
html: '<p><br></p>',
config: editorConfig,
mode: 'default',
})
const toolbarConfig = {}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default',
})
layui.use(['form', 'upload', 'layer', 'laydate'], function () {
var form = layui.form,
layer = layui.layer,
upload = layui.upload,
$ = layui.jquery;
// 自定义复选框的点击事件
$('.category-label').click(function () {
// 获取隐藏的checkbox
var checkbox = $(this).find('.custom-checkbox');
// 切换选中状态
if (checkbox.prop('checked')) {
checkbox.prop('checked', false);
$(this).removeClass('checked');
} else {
checkbox.prop('checked', true);
$(this).addClass('checked');
}
});
// 封面图上传
upload.render({
elem: '#uploadCover',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#coverPreview").attr("src", res.data.path);
$("#cover_image").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图1上传
upload.render({
elem: '#uploadDetail1',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail1Preview").attr("src", res.data.path);
$("#detail_image1").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图2上传
upload.render({
elem: '#uploadDetail2',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail2Preview").attr("src", res.data.path);
$("#detail_image2").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图3上传
upload.render({
elem: '#uploadDetail3',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail3Preview").attr("src", res.data.path);
$("#detail_image3").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图4上传
upload.render({
elem: '#uploadDetail4',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail4Preview").attr("src", res.data.path);
$("#detail_image4").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 表单提交
form.on('submit(saveBtn)', function (data) {
// 获取富文本编辑器内容
data.field.detail_html = editor.getHtml();
if (!data.field.product_name) {
layer.msg('商品名称不能为空', { icon: 2 });
return false;
}
if (!data.field.price) {
layer.msg('商品价格不能为空', { icon: 2 });
return false;
}
// 检查是否选择了分类
var selectedCategories = [];
$('.custom-checkbox:checked').each(function () {
selectedCategories.push($(this).val());
});
if (selectedCategories.length === 0) {
layer.msg('请至少选择一个分类', { icon: 2 });
return false;
}
$.ajax({
url: '{:url("/admin/ff_products_add")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,448 @@
{include file="Public/header3" /}
<link href="https://unpkg.com/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet" />
<style>
#editor—wrapper {
border: 1px solid #ccc;
z-index: 100;
}
#toolbar-container {
border-bottom: 1px solid #ccc;
}
#editor-container {
height: 500px;
}
.category-checkbox {
display: inline-block;
margin-right: 15px;
margin-bottom: 10px;
}
.custom-checkbox {
margin-right: 5px;
vertical-align: middle;
}
.category-label {
display: inline-block;
padding: 5px 10px;
border: 1px solid #e6e6e6;
background-color: #f2f2f2;
border-radius: 3px;
cursor: pointer;
margin-bottom: 5px;
font-size: 13px;
}
.category-label:hover {
background-color: #e6e6e6;
}
.category-label.checked {
background-color: #009688;
color: #fff;
border-color: #009688;
}
</style>
<body>
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<input type="hidden" name="id" value="{$info.id}">
<div class="layui-form-item">
<label class="layui-form-label">商品名称</label>
<div class="layui-input-block">
<input type="text" name="product_name" id="product_name" autocomplete="off" placeholder="请输入商品名称"
class="layui-input" lay-verify="required" value="{$info.product_name}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所属分类</label>
<div class="layui-input-block" id="categoriesContainer">
{foreach $categories as $category}
<label class="category-label {if in_array($category.category_name, $selectedCategories)}checked{/if}">
<input type="checkbox" lay-ignore class="custom-checkbox" name="categories[]" value="{$category.category_name}" style="display:none;" {if in_array($category.category_name, $selectedCategories)}checked{/if}>
{$category.category_name}
</label>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">商品价格</label>
<div class="layui-input-inline">
<input type="text" name="price" id="price" autocomplete="off" placeholder="请输入价格" class="layui-input"
lay-verify="required|number" value="{$info.price}">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">商品库存</label>
<div class="layui-input-inline">
<input type="text" name="stock" id="stock" autocomplete="off" placeholder="请输入库存" class="layui-input"
lay-verify="required|number" value="{$info.stock}">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">剩余库存</label>
<div class="layui-input-inline">
<input type="text" name="sales" id="sales" autocomplete="off" placeholder="请输入销量" class="layui-input"
value="{$info.sales}">
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">封面图</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadCover">上传封面图</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="coverPreview" style="max-width: 200px; max-height: 150px;"
src="{$info.cover_image}">
</div>
<input type="hidden" name="cover_image" id="cover_image" value="{$info.cover_image}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片1</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail1">上传详情图1</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail1Preview" style="max-width: 200px; max-height: 150px;"
src="{$info.detail_image1}">
</div>
<input type="hidden" name="detail_image1" id="detail_image1" value="{$info.detail_image1}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片2</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail2">上传详情图2</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail2Preview" style="max-width: 200px; max-height: 150px;"
src="{$info.detail_image2}">
</div>
<input type="hidden" name="detail_image2" id="detail_image2" value="{$info.detail_image2}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片3</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail3">上传详情图3</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail3Preview" style="max-width: 200px; max-height: 150px;"
src="{$info.detail_image3}">
</div>
<input type="hidden" name="detail_image3" id="detail_image3" value="{$info.detail_image3}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情图片4</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadDetail4">上传详情图4</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="detail4Preview" style="max-width: 200px; max-height: 150px;"
src="{$info.detail_image4}">
</div>
<input type="hidden" name="detail_image4" id="detail_image4" value="{$info.detail_image4}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
<textarea name="product_desc" id="product_desc" placeholder="请输入商品描述"
class="layui-textarea">{$info.product_desc}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">详情内容</label>
<div class="layui-input-block">
<div id="editor—wrapper">
<div id="toolbar-container"><!-- 工具栏 --></div>
<div id="editor-container"><!-- 编辑器 --></div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">商品状态</label>
<div class="layui-input-inline">
<input type="radio" name="status" value="0" title="下架" {if $info.status eq 0}checked{/if}>
<input type="radio" name="status" value="1" title="上架" {if $info.status eq 1}checked{/if}>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">热销商品</label>
<div class="layui-input-inline">
<input type="radio" name="is_hot" value="0" title="否" {if $info.is_hot eq 0}checked{/if}>
<input type="radio" name="is_hot" value="1" title="是" {if $info.is_hot eq 1}checked{/if}>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">新品</label>
<div class="layui-input-inline">
<input type="radio" name="is_new" value="0" title="否" {if $info.is_new eq 0}checked{/if}>
<input type="radio" name="is_new" value="1" title="是" {if $info.is_new eq 1}checked{/if}>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">推荐</label>
<div class="layui-input-inline">
<input type="radio" name="is_recommend" value="0" title="否" {if $info.is_recommend eq 0}checked{/if}>
<input type="radio" name="is_recommend" value="1" title="是" {if $info.is_recommend eq 1}checked{/if}>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
</body>
{include file="Public/footer" /}
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
const { createEditor, createToolbar } = window.wangEditor
const editorConfig = {
placeholder: 'Type here...',
onChange(editor) {
const html = editor.getHtml()
console.log('editor content', html)
},
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
customUpload: async (file, insertFn) => {
console.log(file);
// 上传图片
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/admin/picture?dir=products', {
method: 'POST',
body: formData
});
console.log("res", res);
const result = await res.json();
// 成功后插入图片
insertFn(result.data.imgurl, '图片描述', result.data.imgurl);
}
}
const editor = createEditor({
selector: '#editor-container',
html: '{$info.detail_html|raw}',
config: editorConfig,
mode: 'default',
})
const toolbarConfig = {}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default',
})
layui.use(['form', 'upload', 'layer', 'laydate'], function () {
var form = layui.form,
layer = layui.layer,
upload = layui.upload,
$ = layui.jquery;
// 自定义复选框的点击事件
$('.category-label').click(function() {
// 获取隐藏的checkbox
var checkbox = $(this).find('.custom-checkbox');
// 切换选中状态
if(checkbox.prop('checked')) {
checkbox.prop('checked', false);
$(this).removeClass('checked');
} else {
checkbox.prop('checked', true);
$(this).addClass('checked');
}
});
// 封面图上传
upload.render({
elem: '#uploadCover',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#coverPreview").attr("src", res.data.path);
$("#cover_image").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图1上传
upload.render({
elem: '#uploadDetail1',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail1Preview").attr("src", res.data.path);
$("#detail_image1").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图2上传
upload.render({
elem: '#uploadDetail2',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail2Preview").attr("src", res.data.path);
$("#detail_image2").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图3上传
upload.render({
elem: '#uploadDetail3',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail3Preview").attr("src", res.data.path);
$("#detail_image3").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 详情图4上传
upload.render({
elem: '#uploadDetail4',
url: '/admin/picture',
accept: "file",
data: {
dir: 'products'
},
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#detail4Preview").attr("src", res.data.path);
$("#detail_image4").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 表单提交
form.on('submit(saveBtn)', function (data) {
// 获取富文本编辑器内容
data.field.detail_html = editor.getHtml();
if (!data.field.product_name) {
layer.msg('商品名称不能为空', { icon: 2 });
return false;
}
if (!data.field.price) {
layer.msg('商品价格不能为空', { icon: 2 });
return false;
}
// 检查是否选择了分类
var selectedCategories = [];
$('.custom-checkbox:checked').each(function() {
selectedCategories.push($(this).val());
});
if (selectedCategories.length === 0) {
layer.msg('请至少选择一个分类', { icon: 2 });
return false;
}
$.ajax({
url: '{:url("/admin/ff_products_edit")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,308 @@
{include file="Public:header3"/}
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-header">商品管理</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
<div class="layui-form-item">
<div class="layui-inline">
<input type="text" id="searchProductName" placeholder="请输入商品名称关键词" class="layui-input">
</div>
<div class="layui-inline">
<input type="text" id="searchCategoryName" placeholder="请输入分类名称关键词" class="layui-input">
</div>
<div class="layui-inline">
<select id="searchStatus">
<option value="">全部状态</option>
<option value="0">下架</option>
<option value="1">上架</option>
</select>
</div>
<div class="layui-inline">
<select id="searchIsHot">
<option value="">全部热销</option>
<option value="0">非热销</option>
<option value="1">热销</option>
</select>
</div>
<div class="layui-inline">
<select id="searchIsNew">
<option value="">全部新品</option>
<option value="0">非新品</option>
<option value="1">新品</option>
</select>
</div>
<div class="layui-inline">
<select id="searchIsRecommend">
<option value="">全部推荐</option>
<option value="0">非推荐</option>
<option value="1">推荐</option>
</select>
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm" id="btnSearch"><i
class="layui-icon">&#xe615;</i>搜索</button>
<button class="layui-btn layui-btn-sm" id="btnAdd"><i class="layui-icon">&#xe654;</i>添加</button>
</div>
</div>
</div>
<table id="tableList" lay-filter="tableList"></table>
</div>
</div>
</div>
<!-- 表格操作列 -->
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
{{# if(d.status == 0){ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="publish">上架</a>
{{# }else{ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="draft">下架</a>
{{# } }}
{{# if(d.is_hot == 0){ }}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="setHot">设为热销</a>
{{# }else{ }}
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="cancelHot">取消热销</a>
{{# } }}
{{# if(d.is_new == 0){ }}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="setNew">设为新品</a>
{{# }else{ }}
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="cancelNew">取消新品</a>
{{# } }}
{{# if(d.is_recommend == 0){ }}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="setRecommend">设为推荐</a>
{{# }else{ }}
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="cancelRecommend">取消推荐</a>
{{# } }}
</script>
<!-- 状态模板 -->
<script type="text/html" id="statusTpl">
{{# if(d.status == 1){ }}
<span class="layui-badge layui-bg-green">上架</span>
{{# }else{ }}
<span class="layui-badge">下架</span>
{{# } }}
</script>
<!-- 热销模板 -->
<script type="text/html" id="hotTpl">
{{# if(d.is_hot == 1){ }}
<span class="layui-badge layui-bg-orange"></span>
{{# }else{ }}
<span></span>
{{# } }}
</script>
<!-- 新品模板 -->
<script type="text/html" id="newTpl">
{{# if(d.is_new == 1){ }}
<span class="layui-badge layui-bg-blue"></span>
{{# }else{ }}
<span></span>
{{# } }}
</script>
<!-- 推荐模板 -->
<script type="text/html" id="recommendTpl">
{{# if(d.is_recommend == 1){ }}
<span class="layui-badge layui-bg-cyan"></span>
{{# }else{ }}
<span></span>
{{# } }}
</script>
{include file="Public/footer3" /}
<script>
layui.use(['table', 'form', 'jquery', 'layer', 'laydate'], function () {
var $ = layui.jquery;
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
// 渲染表格
var tableIns = table.render({
elem: '#tableList',
url: '{:url("/admin/ff_products")}',
page: true,
cols: [[
{ type: 'numbers', title: '序号', width: 60 },
{ field: 'product_name', title: '商品名称', width: 180 },
{ field: 'category_name', title: '分类', width: 150 },
{
field: 'cover_image', title: '封面图', width: 100, templet: function (d) {
return d.cover_image ? '<img src="' + d.cover_image + '" style="max-height: 50px;">' : '';
}
},
{ field: 'price', title: '价格', width: 100 },
{ field: 'stock', title: '库存', width: 80 },
{ field: 'sales', title: '销量', width: 80 },
{ field: 'is_hot', title: '热销', width: 80, templet: '#hotTpl' },
{ field: 'is_new', title: '新品', width: 80, templet: '#newTpl' },
{ field: 'is_recommend', title: '推荐', width: 80, templet: '#recommendTpl' },
{ field: 'status', title: '状态', width: 80, templet: '#statusTpl' },
{
field: 'create_time', title: '创建时间', width: 160, templet: function (d) {
return layui.util.toDateString(new Date(d.create_time).getTime(), 'yyyy-MM-dd HH:mm:ss');
}
},
{ title: '操作', toolbar: '#tableBar', width: 380 }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
text: {
none: '暂无相关数据'
}
});
// 搜索按钮点击事件
$('#btnSearch').click(function () {
tableIns.reload({
where: {
product_name: $('#searchProductName').val(),
category_name: $('#searchCategoryName').val(),
status: $('#searchStatus').val(),
is_hot: $('#searchIsHot').val(),
is_new: $('#searchIsNew').val(),
is_recommend: $('#searchIsRecommend').val()
},
page: {
curr: 1
}
});
});
// 添加按钮点击事件
$('#btnAdd').click(function () {
layer.open({
type: 2,
title: '添加商品',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: false,
content: '{:url("/admin/ff_products_add")}'
});
});
// 表格工具条点击事件
table.on('tool(tableList)', function (obj) {
var data = obj.data;
var layEvent = obj.event;
if (layEvent === 'edit') {
layer.open({
type: 2,
title: '编辑商品',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: false,
content: '{:url("/admin/ff_products_edit")}?id=' + data.id
});
} else if (layEvent === 'del') {
layer.confirm('确定要删除该商品吗?', function (i) {
layer.close(i);
layer.load(2);
$.post('{:url("/admin/ff_products_del")}', { id: data.id }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
});
} else if (layEvent === 'publish') {
layer.load(2);
$.post('{:url("/admin/ff_products_status")}', { id: data.id, status: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'draft') {
layer.load(2);
$.post('{:url("/admin/ff_products_status")}', { id: data.id, status: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'setHot') {
layer.load(2);
$.post('{:url("/admin/ff_products_hot")}', { id: data.id, is_hot: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'cancelHot') {
layer.load(2);
$.post('{:url("/admin/ff_products_hot")}', { id: data.id, is_hot: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'setNew') {
layer.load(2);
$.post('{:url("/admin/ff_products_new")}', { id: data.id, is_new: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'cancelNew') {
layer.load(2);
$.post('{:url("/admin/ff_products_new")}', { id: data.id, is_new: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'setRecommend') {
layer.load(2);
$.post('{:url("/admin/ff_products_recommend")}', { id: data.id, is_recommend: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'cancelRecommend') {
layer.load(2);
$.post('{:url("/admin/ff_products_recommend")}', { id: data.id, is_recommend: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
}
});
});
</script>

View File

@ -0,0 +1,218 @@
{include file="Public/header3" /}
<link href="https://unpkg.com/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet" />
<style>
#editor—wrapper {
border: 1px solid #ccc;
z-index: 100;
/* 按需定义 */
}
#toolbar-container {
border-bottom: 1px solid #ccc;
}
#editor-container {
height: 500px;
}
</style>
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<div class="layui-form-item">
</div>
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" id="title" autocomplete="off" placeholder="请输入资讯标题" class="layui-input"
lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">封面图</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadCover">上传封面图</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="coverPreview" style="max-width: 200px; max-height: 150px;">
</div>
<input type="hidden" name="cover_image" id="cover_image" value="">
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">热榜</label>
<div class="layui-input-inline">
<input type="radio" name="is_hot" value="0" title="否" checked>
<input type="radio" name="is_hot" value="1" title="是">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">精选</label>
<div class="layui-input-inline">
<input type="radio" name="is_featured" value="0" title="否">
<input type="radio" name="is_featured" value="1" title="是" checked>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容详情</label>
<div class="layui-input-block">
<div id="editor—wrapper">
<div id="toolbar-container"><!-- 工具栏 --></div>
<div id="editor-container"><!-- 编辑器 --></div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">作者姓名</label>
<div class="layui-input-inline">
<input type="text" name="author_name" id="author_name" placeholder="请输入作者姓名" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<input type="radio" name="status" value="0" title="草稿">
<input type="radio" name="status" value="1" title="发布" checked>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发布时间</label>
<div class="layui-input-block">
<input type="text" name="publish_time" id="publish_time" autocomplete="off" placeholder="请选择发布时间"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
{include file="Public/footer" /}
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
const { createEditor, createToolbar } = window.wangEditor
const editorConfig = {
placeholder: 'Type here...',
onChange(editor) {
const html = editor.getHtml()
console.log('editor content', html)
// 也可以同步到 <textarea>
},
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
customUpload: async (file, insertFn) => {
console.log(file);
// 模拟上传到 COS 的过程
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/admin/picture?dir=news', {
method: 'POST',
body: formData
});
console.log("resresresresres", res);
const result = await res.json();
// // 成功后插入图片
insertFn(result.data.imgurl, '图片描述', result.data.imgurl);
}
}
const editor = createEditor({
selector: '#editor-container',
html: '<p><br></p>',
config: editorConfig,
mode: 'default', // or 'simple'
})
const toolbarConfig = {}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default', // or 'simple'
})
layui.use(['form', 'upload', 'layer', 'laydate'], function () {
var form = layui.form,
layer = layui.layer,
upload = layui.upload,
laydate = layui.laydate,
// layedit = layui.layedit,
$ = layui.jquery;
// 初始化日期选择器
laydate.render({
elem: '#publish_time',
type: 'datetime',
value: new Date()
});
// 上传封面图
upload.render({
elem: '#uploadCover',
url: '/admin/picture',
accept: "file",
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#coverPreview").attr("src", res.data.path);
$("#cover_image").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 表单提交
form.on('submit(saveBtn)', function (data) {
// 同步富文本编辑器内容
data.field.content = editor.getHtml();
if (!data.field.title) {
layer.msg('标题不能为空', { icon: 2 });
return false;
}
// 如果发布状态为"发布"且未设置发布时间,则设置为当前时间
if (data.field.status == 1 && !data.field.publish_time) {
data.field.publish_time = layui.util.toDateString(new Date(), 'yyyy-MM-dd HH:mm:ss');
}
$.ajax({
url: '{:url("/admin/news_add")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,225 @@
{include file="Public/header3" /}
<link href="https://unpkg.com/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet" />
<style>
#editor—wrapper {
border: 1px solid #ccc;
z-index: 100;
/* 按需定义 */
}
#toolbar-container {
border-bottom: 1px solid #ccc;
}
#editor-container {
height: 500px;
}
</style>
<div class="layui-form" style="width: 90%; margin: 0 auto; padding-top: 20px;">
<input type="hidden" name="id" value="{$info.id}">
<div class="layui-form-item">
</div>
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" id="title" autocomplete="off" placeholder="请输入资讯标题" class="layui-input"
lay-verify="required" value="{$info.title}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">封面图</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="uploadCover">上传封面图</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="coverPreview" style="max-width: 200px; max-height: 150px;"
src="{$info.cover_image}">
</div>
<input type="hidden" name="cover_image" id="cover_image" value="{$info.cover_image}">
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">热榜</label>
<div class="layui-input-inline">
<input type="radio" name="is_hot" value="0" title="否" {if $info.is_hot eq 0}checked{/if}>
<input type="radio" name="is_hot" value="1" title="是" {if $info.is_hot eq 1}checked{/if}>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">精选</label>
<div class="layui-input-inline">
<input type="radio" name="is_featured" value="0" title="否" {if $info.is_featured eq 0}checked{/if}>
<input type="radio" name="is_featured" value="1" title="是" {if $info.is_featured eq 1}checked{/if}>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容详情</label>
<div class="layui-input-block">
<div id="editor—wrapper">
<div id="toolbar-container"><!-- 工具栏 --></div>
<div id="editor-container"><!-- 编辑器 --></div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">作者姓名</label>
<div class="layui-input-inline">
<input type="text" name="author_name" id="author_name" placeholder="请输入作者姓名" class="layui-input"
value="{$info.author_name}">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<input type="radio" name="status" value="0" title="草稿" {if $info.status eq 0}checked{/if}>
<input type="radio" name="status" value="1" title="发布" {if $info.status eq 1}checked{/if}>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发布时间</label>
<div class="layui-input-block">
<input type="text" name="publish_time" id="publish_time" autocomplete="off" placeholder="请选择发布时间"
class="layui-input" value="{$info.publish_time}">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBtn">保存</button>
</div>
</div>
</div>
{include file="Public/footer" /}
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
const { createEditor, createToolbar } = window.wangEditor
const editorConfig = {
placeholder: 'Type here...',
onChange(editor) {
const html = editor.getHtml()
console.log('editor content', html)
// 也可以同步到 <textarea>
},
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
customUpload: async (file, insertFn) => {
console.log(file);
// 模拟上传到 COS 的过程
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/admin/picture?dir=news', {
method: 'POST',
body: formData
});
console.log("resresresresres", res);
const result = await res.json();
// // 成功后插入图片
insertFn(result.data.imgurl, '图片描述', result.data.imgurl);
}
}
const editor = createEditor({
selector: '#editor-container',
html: '{$info.content|raw}',
config: editorConfig,
mode: 'default', // or 'simple'
})
const toolbarConfig = {}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default', // or 'simple'
})
layui.use(['form', 'upload', 'layer', 'laydate'], function () {
var form = layui.form,
layer = layui.layer,
upload = layui.upload,
laydate = layui.laydate,
$ = layui.jquery;
// 初始化日期选择器
laydate.render({
elem: '#publish_time',
type: 'datetime',
value: new Date()
});
// 上传封面图
upload.render({
elem: '#uploadCover',
accept: "file",
url: '/admin/picture',
done: function (res) {
if (res.status == 1) {
layer.msg("上传成功", { icon: 1, time: 1000 }, function () {
$("#coverPreview").attr("src", res.data.path);
$("#cover_image").val(res.data.imgurl);
});
} else {
layer.msg(res.msg, { icon: 2, anim: 6, time: 1500 });
}
},
error: function () {
layer.msg('服务繁忙,请稍后再试', { icon: 2, anim: 6, time: 1500 });
}
});
// 表单提交
form.on('submit(saveBtn)', function (data) {
// 同步富文本编辑器内容
data.field.content = editor.getHtml();
if (!data.field.title) {
layer.msg('标题不能为空', { icon: 2 });
return false;
}
// 如果发布状态为"发布"且未设置发布时间,则设置为当前时间
if (data.field.status == 1 && !data.field.publish_time) {
data.field.publish_time = layui.util.toDateString(new Date(), 'yyyy-MM-dd HH:mm:ss');
}
$.ajax({
url: '{:url("/admin/news_edit")}',
type: 'POST',
data: data.field,
success: function (res) {
if (res.status) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
parent.layui.table.reload('tableList');
var iframeIndex = parent.layer.getFrameIndex(window.name);
parent.layer.close(iframeIndex);
});
} else {
layer.msg(res.msg, { icon: 2 });
}
}
});
return false;
});
});
</script>

View File

@ -0,0 +1,245 @@
{include file="Public:header3"/}
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-header">资讯管理</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
<div class="layui-form-item">
<div class="layui-inline">
<input type="text" id="searchTitle" placeholder="请输入标题关键词" class="layui-input">
</div>
<div class="layui-inline">
<select id="searchStatus">
<option value="">全部状态</option>
<option value="0">草稿</option>
<option value="1">已发布</option>
</select>
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm" id="btnSearch"><i
class="layui-icon">&#xe615;</i>搜索</button>
<button class="layui-btn layui-btn-sm" id="btnAdd"><i class="layui-icon">&#xe654;</i>添加</button>
</div>
</div>
</div>
<table id="tableList" lay-filter="tableList"></table>
</div>
</div>
</div>
<!-- 表格操作列 -->
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
{{# if(d.status == 0){ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="publish">发布</a>
{{# }else{ }}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="draft">下架</a>
{{# } }}
{{# if(d.is_hot == 0){ }}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="setHot">设为热榜</a>
{{# }else{ }}
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="cancelHot">取消热榜</a>
{{# } }}
{{# if(d.is_featured == 0){ }}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="setFeatured">设为精选</a>
{{# }else{ }}
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="cancelFeatured">取消精选</a>
{{# } }}
</script>
<!-- 状态模板 -->
<script type="text/html" id="statusTpl">
{{# if(d.status == 1){ }}
<span class="layui-badge layui-bg-green">已发布</span>
{{# }else{ }}
<span class="layui-badge">草稿</span>
{{# } }}
</script>
<!-- 热榜模板 -->
<script type="text/html" id="hotTpl">
{{# if(d.is_hot == 1){ }}
<span class="layui-badge layui-bg-orange"></span>
{{# }else{ }}
<span></span>
{{# } }}
</script>
<!-- 精选模板 -->
<script type="text/html" id="featuredTpl">
{{# if(d.is_featured == 1){ }}
<span class="layui-badge layui-bg-blue"></span>
{{# }else{ }}
<span></span>
{{# } }}
</script>
{include file="Public/footer3" /}
<script>
layui.use(['table', 'form', 'jquery', 'layer', 'laydate'], function () {
var $ = layui.jquery;
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
// 渲染表格
var tableIns = table.render({
elem: '#tableList',
url: '{:url("/admin/news")}',
page: true,
cols: [[
{ type: 'numbers', title: '序号', width: 60 },
{ field: 'title', title: '标题', width: 200 },
{
field: 'cover_image', title: '封面图', width: 100, templet: function (d) {
return d.cover_image ? '<img src="' + d.cover_image + '" style="max-height: 50px;">' : '';
}
},
{ field: 'author_name', title: '作者', width: 100 },
{
field: 'publish_time', title: '发布时间', width: 160, templet: function (d) {
return d.publish_time ? layui.util.toDateString(new Date(d.publish_time).getTime(), 'yyyy-MM-dd HH:mm:ss') : '';
}
},
{ field: 'is_hot', title: '热榜', width: 80, templet: '#hotTpl' },
{ field: 'is_featured', title: '精选', width: 80, templet: '#featuredTpl' },
{ field: 'status', title: '状态', width: 80, templet: '#statusTpl' },
{
field: 'create_time', title: '创建时间', width: 160, templet: function (d) {
return layui.util.toDateString(new Date(d.create_time).getTime(), 'yyyy-MM-dd HH:mm:ss');
}
},
{ title: '操作', toolbar: '#tableBar', width: 380 }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
text: {
none: '暂无相关数据'
}
});
// 搜索按钮点击事件
$('#btnSearch').click(function () {
tableIns.reload({
where: {
title: $('#searchTitle').val(),
status: $('#searchStatus').val()
},
page: {
curr: 1
}
});
});
// 添加按钮点击事件
$('#btnAdd').click(function () {
layer.open({
type: 2,
title: '添加资讯',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: true,
content: '{:url("/admin/news_add")}'
});
});
// 表格工具条点击事件
table.on('tool(tableList)', function (obj) {
var data = obj.data;
var layEvent = obj.event;
if (layEvent === 'edit') {
layer.open({
type: 2,
title: '编辑资讯',
area: ['90%', '90%'],
shade: 0.4,
shadeClose: true,
content: '{:url("/admin/news_edit")}?id=' + data.id
});
} else if (layEvent === 'del') {
layer.confirm('确定要删除该资讯吗?', function (i) {
layer.close(i);
layer.load(2);
$.post('{:url("/admin/news_del")}', { id: data.id }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
});
} else if (layEvent === 'publish') {
layer.load(2);
$.post('{:url("/admin/news_status")}', { id: data.id, status: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'draft') {
layer.load(2);
$.post('{:url("/admin/news_status")}', { id: data.id, status: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'setHot') {
layer.load(2);
$.post('{:url("/admin/news_hot")}', { id: data.id, is_hot: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'cancelHot') {
layer.load(2);
$.post('{:url("/admin/news_hot")}', { id: data.id, is_hot: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'setFeatured') {
layer.load(2);
$.post('{:url("/admin/news_featured")}', { id: data.id, is_featured: 1 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
} else if (layEvent === 'cancelFeatured') {
layer.load(2);
$.post('{:url("/admin/news_featured")}', { id: data.id, is_featured: 0 }, function (res) {
layer.closeAll('loading');
if (res.status) {
layer.msg(res.msg, { icon: 1 });
tableIns.reload();
} else {
layer.msg(res.msg, { icon: 2 });
}
}, 'json');
}
});
});
</script>

View File

@ -1,5 +1,5 @@
<?php
declare (strict_types = 1);
declare(strict_types=1);
namespace app\api\controller;
use app\api\controller\Base;
@ -18,7 +18,7 @@ use \think\Request;
class Coupon extends Base
{
/**
/**
* 首页优惠券列表
* @param Request $request [description]
* @param [type] 类型 1 推荐 2 预售 3 现货 4 一番赏 5 双随机 6售罄
@ -26,72 +26,74 @@ class Coupon extends Base
public function index(Request $request)
{
$is_use_coupon = $this->getUserid1();
if(!$is_use_coupon){
#领过,之后不再弹出
$data['status'] = 2;
return $this->renderSuccess("",$data);
if (!$is_use_coupon) {
#领过,之后不再弹出
$data['status'] = 2;
return $this->renderSuccess("", $data);
}
$whe = [];
$whe[]=['status','=',0];
$whe[]=['type','=',1];
$whe[] = ['status', '=', 0];
$whe[] = ['type', '=', 1];
$field = "id,title,price,man_price,effective_day";
$order = "id desc";
$goods = Couponmodel::getList($whe,$field,$order,1000);
return $this->renderSuccess('请求成功',compact('goods'));
$goods = Couponmodel::getList($whe, $field, $order, 1000);
return $this->renderSuccess('请求成功', compact('goods'));
}
/*
一键领取
*/
public function receive(Request $request){
$user = $this->getUser();
$coupon_id = $request->param('coupon_id');
if(empty($coupon_id)){
public function receive(Request $request)
{
$user = $this->getUser();
$coupon_id = $request->param('coupon_id');
if (empty($coupon_id)) {
return $this->renderError("缺少必要参数");
}
$is_find = CouponReceivemodel::where(['user_id'=>$user->id])->whereIn('coupon_id',$coupon_id)->find();
if(!empty($is_find)){
return $this->renderError("已经领取过了,无法在领取");
}
$coupon_id = explode(',',$coupon_id);
$coupon_id = array_filter($coupon_id);
$num = count($coupon_id);
for($i=0;$i<$num;$i++){
$coupon_info = Couponmodel::find($coupon_id[$i]);
if(!empty($coupon_info)){
}
$is_find = CouponReceivemodel::where(['user_id' => $user->id])->whereIn('coupon_id', $coupon_id)->find();
if (!empty($is_find)) {
return $this->renderError("已经领取过了,无法在领取");
}
$coupon_id = explode(',', $coupon_id);
$coupon_id = array_filter($coupon_id);
$num = count($coupon_id);
for ($i = 0; $i < $num; $i++) {
$coupon_info = Couponmodel::find($coupon_id[$i]);
if (!empty($coupon_info)) {
$res[] = CouponReceivemodel::insert(
[
'user_id'=>$user->id,
'title'=>$coupon_info['title'],
'price'=>$coupon_info['price'],
'man_price'=>$coupon_info['man_price'],
'end_time'=>$coupon_info['effective_day']*86400 + time(),
'addtime'=>time(),
'coupon_id'=>$coupon_info['id'],
'state'=> $coupon_info['ttype']
]
[
'user_id' => $user->id,
'title' => $coupon_info['title'],
'price' => $coupon_info['price'],
'man_price' => $coupon_info['man_price'],
'end_time' => $coupon_info['effective_day'] * 86400 + time(),
'addtime' => time(),
'coupon_id' => $coupon_info['id'],
'state' => $coupon_info['ttype']
]
);
}
}
#user表里is_use_coupon 值为1说明是领过优惠券
$res[] = User::where(['id'=>$user['id'],'is_use_coupon'=>0])->update(['is_use_coupon'=>1]);
if(resCheck($res)){
return $this->renderSuccess("领取成功");
}else{
return $this->renderError("购买失败,请刷新重试");
}
}
}
#user表里is_use_coupon 值为1说明是领过优惠券
$res[] = User::where(['id' => $user['id'], 'is_use_coupon' => 0])->update(['is_use_coupon' => 1]);
if (resCheck($res)) {
return $this->renderSuccess("领取成功");
} else {
return $this->renderError("购买失败,请刷新重试");
}
}
//可使用的优惠券
public function used(Request $request){
public function used(Request $request)
{
$user = $this->getUser();
$total_price = $request->param('total_price');
$type = $request->param('type');
@ -99,69 +101,134 @@ class Coupon extends Base
$status = $request->param('status');
$state = $request->param('state');
$page = $request->param('page');
CouponReceivemodel::where(['user_id'=>$user->id,'status'=>0])->where('end_time','<=',time())->update(['status'=>2]);
CouponReceivemodel::where(['user_id' => $user->id, 'status' => 0])->where('end_time', '<=', time())->update(['status' => 2]);
#根据有效期时间改变一下状态
if($type == 1){
if ($type == 1) {
#从个人中心进
if($type1 == 1){
#可用
$whe[] = ['status', '=', $status];
}else{
#不可用
$whe[] = ['status', '>', 0];
if ($type1 == 1) {
#可用
$whe[] = ['status', '=', $status];
} else {
#不可用
$whe[] = ['status', '>', 0];
}
$coupon_receive = CouponReceivemodel::where(['user_id'=>$user->id])->where($whe)->paginate(10)->each(function ($itme) {
$itme['end_time'] = date('Y-m-d',$itme['end_time']);
if($itme['status']== 1){
$itme['mark']= "已使用";
}elseif($itme['status']== 2){
$itme['mark']= "已过期";
}elseif($itme['status']== 0){
$itme['mark']= "去使用";
$coupon_receive = CouponReceivemodel::where(['user_id' => $user->id])->where($whe)->paginate(10)->each(function ($itme) {
$itme['end_time'] = date('Y-m-d', $itme['end_time']);
if ($itme['status'] == 1) {
$itme['mark'] = "已使用";
} elseif ($itme['status'] == 2) {
$itme['mark'] = "已过期";
} elseif ($itme['status'] == 0) {
$itme['mark'] = "去使用";
}
return $itme;
return $itme;
});
}else{
} else {
#从计算金额里面进
if(empty($total_price)){
if (empty($total_price)) {
return $this->renderError("缺少必要参数");
}
if($type1 == 1){
$whe = 'user_id='.$user->id.' and status=0 and man_price<='.$total_price;
if ($type1 == 1) {
$whe = 'user_id=' . $user->id . ' and status=0 and man_price<=' . $total_price;
$whe1 = '';
}else{
$whe = 'user_id='.$user->id.' and status>0';
$whe1 = 'user_id='.$user->id.' and status=0 and man_price>'.$total_price;
} else {
$whe = 'user_id=' . $user->id . ' and status>0';
$whe1 = 'user_id=' . $user->id . ' and status=0 and man_price>' . $total_price;
}
#不可用(包括 已使用,未使用(金额不足,已过期))
$coupon_receive = CouponReceivemodel::where($whe)->whereOr($whe1)
->paginate(10)->each(function ($val) use ($total_price){
$val['end_time'] = date('Y-m-d',$val['end_time']);
if($val['status']== 1){
$val['mark']= "已使用";
}elseif($val['status']== 2){
$val['mark']= "已过期";
}elseif($val['status']== 0){
if($val['man_price'] > $total_price){
$val['mark']= "未满足";
}else{
$val['mark']= "去使用";
->paginate(10)->each(function ($val) use ($total_price) {
$val['end_time'] = date('Y-m-d', $val['end_time']);
if ($val['status'] == 1) {
$val['mark'] = "已使用";
} elseif ($val['status'] == 2) {
$val['mark'] = "已过期";
} elseif ($val['status'] == 0) {
if ($val['man_price'] > $total_price) {
$val['mark'] = "未满足";
} else {
$val['mark'] = "去使用";
}
}
}
return $val;
});
return $val;
});
}
$new_data = [
'data' => $coupon_receive->items(),
'last_page' => $coupon_receive->lastPage(),
];
return $this->renderSuccess('请求成功',$new_data);
return $this->renderSuccess('请求成功', $new_data);
}
public function get_coupon_list(Request $request)
{
$user = $this->getUser();
$total_price = $request->param('total_price');
$type = $request->param('type');
$status = $request->param('status');
$page = $request->param('page');
$limit = $this->request->param('limit', 10);
CouponReceivemodel::where(['user_id' => $user->id, 'status' => 0])->where('end_time', '<=', time())->update(['status' => 2]);
#根据有效期时间改变一下状态
if ($type == 1) {
#从个人中心进
$whe[] = ['status', '=', $status];
$coupon_receive = CouponReceivemodel::where(['user_id' => $user->id])->where($whe)
->field('id,title,price,man_price,status,end_time,coupon_id')
->paginate(['list_rows' => $limit, 'query' => request()->param()])->
each(function ($itme) {
$itme['end_time'] = date('Y-m-d', $itme['end_time']);
if ($itme['status'] == 1) {
$itme['mark'] = "已使用";
} elseif ($itme['status'] == 2) {
$itme['mark'] = "已过期";
} elseif ($itme['status'] == 0) {
$itme['mark'] = "去使用";
}
return $itme;
});
} else {
#从计算金额里面进
if (empty($total_price)) {
return $this->renderError("缺少必要参数");
}
$whe = 'user_id=' . $user->id . ' and status=0 and man_price<=' . $total_price;
$whe1 = '';
#不可用(包括 已使用,未使用(金额不足,已过期))
$coupon_receive = CouponReceivemodel::where($whe)->whereOr($whe1)
->paginate(10)->each(function ($val) use ($total_price) {
$val['end_time'] = date('Y-m-d', $val['end_time']);
if ($val['status'] == 1) {
$val['mark'] = "已使用";
} elseif ($val['status'] == 2) {
$val['mark'] = "已过期";
} elseif ($val['status'] == 0) {
if ($val['man_price'] > $total_price) {
$val['mark'] = "未满足";
} else {
$val['mark'] = "去使用";
}
}
return $val;
});
}
$new_data = [
'list' => $coupon_receive->items(),
'last_page' => $coupon_receive->lastPage(),
];
return $this->renderSuccess('请求成功', $new_data);
}
}

View File

@ -0,0 +1,707 @@
<?php
declare(strict_types=1);
namespace app\api\controller;
use app\api\controller\Base;
use app\common\model\FFProducts;
use app\common\model\UserAddress;
use app\common\model\CouponReceive;
use app\common\server\platform\PlatformFactory;
class FFOrdersController extends Base
{
public function createOrder()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$product_id = $this->request->param('product_id', 0);
$address_id = $this->request->param('address_id', 0);
$coupon_id = $this->request->param('coupon_id', 0);
// $total_price = $this->request->param('total_price', 0);
if (empty($product_id) || empty($address_id)) {
return $this->renderError('缺少必要参数');
}
$product = FFProducts::where('id', $product_id)->find();
if (!$product) {
return $this->renderError('商品不存在');
}
$address = UserAddress::where('id', $address_id)->find();
if (!$address) {
return $this->renderError('地址不存在');
}
$coupon = null;
if ($coupon_id > 0) {
$coupon = CouponReceive::where('id', $coupon_id)->find();
if (!$coupon) {
return $this->renderError('优惠券不存在');
}
}
//$user, $price, $title, $attach, $pre = "MH_", $pay_type = 1, $client = null
$total_price = $product['price'];
if ($coupon) {
$total_price = $total_price - $coupon['price'];
}
$user = $this->getUser();
$payRes = PlatformFactory::createPay($user, $total_price, $product['product_name'], 'order_product', 'YS_', 1);
if ($payRes['status'] !== 1) {
return $this->renderError("购买失败,请稍后再试");
}
//使用优惠卷
if ($coupon) {
$coupon['status'] = 1;
$coupon->save();
}
# 订单号
$order_num = $payRes['data']['order_no'];
$receiver_name = $address['receiver_name'];
$receiver_phone = $address['receiver_phone'];
$receiver_address = $address['detailed_address'];
# 保存到ff_orders 表
$orderData = [
'order_no' => $order_num,
'user_id' => $user_id,
'product_id' => $product_id,
'total_amount' => $product['price'],
'payment_amount' => $total_price,
'discount_amount' => $coupon ? $coupon['price'] : 0,
'payment_type' => 1, // 假设这里是微信支付
'order_status' => 0, // 待支付
'pay_status' => 0, // 未支付
'shipping_status' => 0, // 未发货
'receiver_name' => $receiver_name,
'receiver_phone' => $receiver_phone,
'receiver_address' => $receiver_address,
'source' => 2, // APP来源
'create_time' => date('Y-m-d H:i:s')
];
// 将该用户的所有未支付订单状态变成已取消
\app\common\model\FFOrders::where([
'user_id' => $user_id,
'order_status' => 0, // 待支付
'pay_status' => 0 // 未支付
])->update([
'order_status' => 5, // 已取消
'cancel_time' => date('Y-m-d H:i:s') // 取消时间
]);
// 创建订单
$order = new \app\common\model\FFOrders();
$result = $order->save($orderData);
if (!$result) {
return $this->renderError('订单创建失败');
}
return $this->renderSuccess('订单创建成功', [
'order_no' => $order_num,
'user_info' => ['is_test' => $user['istest']],
'payment_data' => $payRes['data']['res']
]);
}
public function orderPaySuccess()
{
$order_no = $this->request->param('order_no', '');
if (empty($order_no)) {
return $this->renderError('订单号不能为空');
}
// 根据订单号查询订单
$order = \app\common\model\FFOrders::where('order_no', $order_no)->find();
if (!$order) {
return $this->renderError('订单不存在');
}
// 判断订单状态,避免重复处理
if ($order['pay_status'] == 2) {
return $this->renderSuccess('订单已支付', ['order_no' => $order_no]);
}
// 查询订单对应的商品信息
$product_id = $order['product_id'];
$product = FFProducts::where('id', $product_id)->find();
if (!$product) {
return $this->renderError('商品不存在');
}
// 开启事务
\think\facade\Db::startTrans();
try {
// 扣减库存
if ($product['stock'] > 0) {
$product->sales = $product['sales'] - 1; // 增加销量
$product->save();
} else {
throw new \Exception('商品库存不足');
}
// 更新订单状态
$order->order_status = 2; // 已支付待发货
$order->pay_status = 2; // 已支付
$order->shipping_status = 1; // 未发货
$order->shipping_company = '京东快递'; // 快递公司
$order->shipping_no = "TEST_" . time();//TEST_开头
$order->shipping_time = date('Y-m-d H:i:s'); // 发货时间
$order->payment_time = date('Y-m-d H:i:s'); // 支付时间
$order->payment_no = $this->request->param('payment_no', ''); // 支付流水号
// 保存订单
if (!$order->save()) {
throw new \Exception('订单状态更新失败');
}
// 提交事务
\think\facade\Db::commit();
return $this->renderSuccess('购买成功', [
'order_no' => $order_no,
'order_status' => $order->order_status,
'pay_status' => $order->pay_status
]);
} catch (\Exception $e) {
// 回滚事务
\think\facade\Db::rollback();
return $this->renderError('支付处理失败:' . $e->getMessage());
}
}
/**
* 获取订单列表
* @return \think\Response
*/
public function getOrderList()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收参数
$status = $this->request->param('status', 0); // 订单状态0表示全部
$keyword = $this->request->param('keyword', ''); // 商品标题搜索关键词
$page = (int) $this->request->param('page', 1);
$limit = (int) $this->request->param('limit', 10);
// 构建查询条件
$where = [
'user_id' => $user_id,
'delete_status' => 0
];
// 初始化查询对象
$query = \app\common\model\FFOrders::alias('o');
// 根据状态筛选
if ($status > 0) {
if ($status == 4) {
// 当status为4时查询状态为6和7的订单申请售后和退款售后成功
$query = $query->where($where)
->where('o.order_status', 'in', [6, 7]);
} else {
// 其他状态正常查询
$query = $query->where($where)
->where('o.order_status', $status);
}
} else {
// status为0时查询所有订单
$query = $query->where($where);
}
// 如果有搜索关键词,则需要联表查询
if (!empty($keyword)) {
// 通过product_id关联FFProducts表
$query = $query->join('ff_products p', 'o.product_id = p.id')
->where('p.product_name', 'like', "%{$keyword}%");
}
// 排序方式 - 最新订单在前
$query = $query->order('o.create_time desc');
// 分页查询
$count = $query->count();
$list = $query->page($page, $limit)->select();
// 处理结果
$result = [];
foreach ($list as $order) {
// 获取商品信息
$product = \app\common\model\FFProducts::where('id', $order['product_id'])->find();
$item = [
'order_id' => $order['order_id'],
'order_no' => $order['order_no'],
'product_id' => $product ? $product['id'] : '', //
'product_cover' => $product ? $product['cover_image'] : '', // 商品封面图
'product_title' => $product ? $product['product_name'] : '', // 商品标题
'payment_amount' => $order['payment_amount'], // 支付金额
'payment_time' => $order['payment_time'] ?: '', // 支付时间
'order_status' => $order['order_status'], // 订单状态
'order_status_text' => $this->getOrderStatusText($order['order_status']), // 订单状态文本
'create_time' => $order['create_time'], // 创建时间
'receive_time' => $order['receive_time'] ?: '', // 收货时间
'is_invoice' => $order['invoice_title'] == '' ? 0 : 1, // 是否开票
];
$result[] = $item;
}
return $this->renderSuccess('获取成功', [
'total' => $count,
'page' => $page,
'limit' => $limit,
'list' => $result
]);
}
/**
* 获取订单状态文本
* @param int $status 订单状态
* @return string 状态文本
*/
private function getOrderStatusText($status)
{
$statusArr = [
0 => '待支付',
1 => '已支付待发货',
2 => '已发货',
3 => '已完成',
4 => '已关闭',
5 => '已取消',
6 => '申请售后',
7 => '售后结束'
];
return isset($statusArr[$status]) ? $statusArr[$status] : '未知状态';
}
/**
* 订单收货接口
* @return \think\Response
*/
public function orderReceive()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收订单编号参数
$order_no = $this->request->param('order_no', '');
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 判断订单状态是否为已发货
if ($order['order_status'] != 2) {
return $this->renderError('只有已发货的订单才能确认收货');
}
// 更新订单状态和收货时间
$order->order_status = 3; // 已完成
$order->receive_time = date('Y-m-d H:i:s'); // 收货时间
// 保存订单
if ($order->save()) {
return $this->renderSuccess('确认收货成功', [
'order_no' => $order_no,
'order_status' => $order->order_status,
'order_status_text' => $this->getOrderStatusText($order->order_status),
'receive_time' => $order->receive_time
]);
} else {
return $this->renderError('确认收货失败');
}
}
/**
* 申请售后接口
* @return \think\Response
*/
public function applyRefund()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收参数
$order_no = $this->request->param('order_no', '');
$extend_info = $this->request->param('extend_info', '');
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 判断订单状态是否可申请售后
if ($order['order_status'] == 0 || $order['order_status'] == 4 || $order['order_status'] == 5 || $order['order_status'] == 6 || $order['order_status'] == 7) {
return $this->renderError('当前订单状态不可申请售后');
}
try {
// 将当前订单状态保存到扩展信息中
$extendData = json_decode($extend_info, true) ?: [];
$extendData['original_status'] = $order['order_status'];
// 更新订单状态和扩展信息
$order->order_status = 6; // 申请退款
$order->extend_info = json_encode($extendData);
// 保存订单
if ($order->save()) {
return $this->renderSuccess('申请售后成功', [
'order_no' => $order_no,
'order_status' => $order->order_status,
'order_status_text' => $this->getOrderStatusText($order->order_status)
]);
} else {
return $this->renderError('申请售后失败');
}
} catch (\Exception $e) {
return $this->renderError('申请售后失败:' . $e->getMessage());
}
}
/**
* 取消售后接口
* @return \think\Response
*/
public function cancelRefund()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收参数
$order_no = $this->request->param('order_no', '');
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 判断订单状态是否为申请退款
if ($order['order_status'] != 6) {
return $this->renderError('只有申请退款状态的订单才能取消售后');
}
try {
// 从扩展信息中读取原始状态
$extendInfo = $order['extend_info'] ? json_decode($order['extend_info'], true) : [];
$originalStatus = isset($extendInfo['original_status']) ? $extendInfo['original_status'] : 3; // 默认为已完成
// 移除原始状态信息
if (isset($extendInfo['original_status'])) {
unset($extendInfo['original_status']);
}
// 更新订单状态和扩展信息
$order->order_status = $originalStatus;
$order->extend_info = !empty($extendInfo) ? json_encode($extendInfo) : '';
// 保存订单
if ($order->save()) {
return $this->renderSuccess('取消售后成功', [
'order_no' => $order_no,
'order_status' => $order->order_status,
'order_status_text' => $this->getOrderStatusText($order->order_status)
]);
} else {
return $this->renderError('取消售后失败');
}
} catch (\Exception $e) {
return $this->renderError('取消售后失败:' . $e->getMessage());
}
}
/**
* 删除订单接口
* @return \think\Response
*/
public function deleteOrder()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收订单编号参数
$order_no = $this->request->param('order_no', '');
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id,
'delete_status' => 0 // 未删除的订单
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 判断订单状态是否可删除
// 通常只有已完成(3)、已关闭(4)、已取消(5)、退款成功(7)的订单可以删除
$allowDeleteStatus = [3, 4, 5, 7];
if (!in_array($order['order_status'], $allowDeleteStatus)) {
return $this->renderError('当前订单状态不允许删除');
}
try {
// 更新订单删除状态
$order->delete_status = 1; // 标记为已删除
// 保存订单
if ($order->save()) {
return $this->renderSuccess('订单删除成功');
} else {
return $this->renderError('订单删除失败');
}
} catch (\Exception $e) {
return $this->renderError('订单删除失败:' . $e->getMessage());
}
}
/**
* 获取订单详情接口
* @return \think\Response
*/
public function getOrderDetail()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收订单编号参数
$order_no = $this->request->param('order_no', '');
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id,
'delete_status' => 0 // 未删除的订单
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 查询关联商品
$product = \app\common\model\FFProducts::where('id', $order['product_id'])->find();
// 组装订单详情数据
$orderDetail = [
// 商品信息
'product_id' => $product ? $product['id'] : '',
'product_cover' => $product ? $product['cover_image'] : '',
'product_title' => $product ? $product['product_name'] : '',
'product_price' => $product ? $product['price'] : 0.00,
// 订单信息
'order_id' => $order['order_id'],
'order_no' => $order['order_no'],
'total_amount' => $order['total_amount'], // 订单总金额
'payment_amount' => $order['payment_amount'], // 实际支付金额
'discount_amount' => $order['discount_amount'], // 优惠金额
'shipping_fee' => $order['shipping_fee'], // 运费
'order_status' => $order['order_status'],
'order_status_text' => $this->getOrderStatusText($order['order_status']),
'pay_status' => $order['pay_status'],
'payment_type' => $order['payment_type'], // 支付方式
// 物流信息
'shipping_company' => $order['shipping_company'] ?: '',
'shipping_no' => $order['shipping_no'] ?: '',
'create_time' => $order['create_time'], // 下单时间
'shipping_time' => $order['shipping_time'] ?: '', // 发货时间
'receive_time' => $order['receive_time'] ?: '', // 收货时间
'payment_time' => $order['payment_time'] ?: '', // 支付时间
// 收货人信息
'receiver_name' => $order['receiver_name'],
'receiver_phone' => $order['receiver_phone'],
'receiver_address' => $order['receiver_address'],
// 发票信息
'invoice_title' => $order['invoice_title'] ?: '',
'invoice_content' => $order['invoice_content'] ?: '',
'invoice_type' => $order['invoice_type'],
'invoice_type_text' => $order['invoice_type'] == 1 ? '个人' : ($order['invoice_type'] == 2 ? '企业' : ''),
// 扩展信息
'extend_info' => $order['extend_info'] ? json_decode($order['extend_info'], true) : []
];
return $this->renderSuccess('获取成功', $orderDetail);
}
/**
* 申请发票接口
* @return \think\Response
*/
public function applyInvoice()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
// 接收参数
$order_no = $this->request->param('order_no', '');
$invoice_title = $this->request->param('invoice_title', '');
$invoice_content = $this->request->param('invoice_content', '');
$invoice_type = (int) $this->request->param('invoice_type', 1); // 默认个人
$user_email = $this->request->param('user_email', ''); // 用户邮箱,不存储
// 参数验证
if (empty($order_no)) {
return $this->renderError('订单编号不能为空');
}
if (empty($invoice_title)) {
return $this->renderError('发票抬头不能为空');
}
if (empty($invoice_content)) {
return $this->renderError('发票内容不能为空');
}
if (!in_array($invoice_type, [1, 2])) {
return $this->renderError('发票类型不正确');
}
if (empty($user_email)) {
return $this->renderError('用户邮箱不能为空');
}
// 邮箱格式验证
if (!filter_var($user_email, FILTER_VALIDATE_EMAIL)) {
return $this->renderError('邮箱格式不正确');
}
// 查询订单
$order = \app\common\model\FFOrders::where([
'order_no' => $order_no,
'user_id' => $user_id,
'delete_status' => 0 // 未删除的订单
])->find();
if (!$order) {
return $this->renderError('订单不存在或不属于当前用户');
}
// 验证订单状态,通常只有已支付的订单才能申请发票
if ($order['pay_status'] != 2) { // 2表示已支付
return $this->renderError('只有已支付的订单才能申请发票');
}
try {
// 更新订单发票信息
$order->invoice_title = $invoice_title;
$order->invoice_content = $invoice_content;
$order->invoice_type = $invoice_type;
// 保存订单
if ($order->save()) {
return $this->renderSuccess('发票申请成功', true);
} else {
return $this->renderError('发票申请失败');
}
} catch (\Exception $e) {
return $this->renderError('发票申请失败:' . $e->getMessage());
}
}
/**
* 获取用户订单统计数据
* @return \think\Response
*/
public function getOrderStatistics()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
try {
// 查询条件 - 用户ID和未删除
$where = [
'user_id' => $user_id,
'delete_status' => 0
];
// 查询待发货订单数量 - 订单状态为1已支付待发货
$waitingShipCount = \app\common\model\FFOrders::where($where)
->where('order_status', 1)
->count();
// 查询待收货订单数量 - 订单状态为2已发货
$waitingReceiveCount = \app\common\model\FFOrders::where($where)
->where('order_status', 2)
->count();
// 查询已收货订单数量 - 订单状态为3已完成
$receivedCount = \app\common\model\FFOrders::where($where)
->where('order_status', 3)
->count();
// 查询申请售后订单数量 - 订单状态为6申请售后和7售后结束
$afterSalesCount = \app\common\model\FFOrders::where($where)
->where('order_status', 'in', [6])
->count();
// 返回统计结果
return $this->renderSuccess('获取成功', [
'waiting_ship_count' => $waitingShipCount, // 待发货数量
'waiting_receive_count' => $waitingReceiveCount, // 待收货数量
'received_count' => $receivedCount, // 已收货数量
'after_sales_count' => $afterSalesCount // 申请售后数量
]);
} catch (\Exception $e) {
return $this->renderError('获取订单统计数据失败:' . $e->getMessage());
}
}
}

View File

@ -0,0 +1,260 @@
<?php
declare(strict_types=1);
namespace app\api\controller;
use app\api\controller\Base;
use app\common\model\FFProducts;
use app\common\model\UserAddress;
use app\common\model\CouponReceive;
use app\common\model\FFFavorites;
class FFProductsController extends Base
{
/**
* 获取精选新闻列表
* @return \think\Response
*/
public function getBannerList()
{
$bannerList = FFProducts::where('is_hot', '=', 1)->
field('id,product_name as title,cover_image as image,price,stock,sales')
->select()->toArray();
return $this->renderSuccess('', $bannerList);
}
public function getProductList()
{
$page = intval($this->request->param('page', 1));
$limit = intval($this->request->param('limit', 10));
$title = $this->request->param('title', '');
$productData = FFProducts::where('is_hot', '=', 0);
if ($title) {
$productData->where('product_name', 'like', '%' . $title . '%');
}
$list = $productData->
field('id,product_name as title,cover_image as image,price,stock,sales')
->order(['is_new' => 'desc', 'id' => 'desc'])
->page($page, $limit)
->select()->toArray();
return $this->renderSuccess('', $list);
}
public function getProductDetail()
{
$id = $this->request->param('id', 0);
$productDetail = FFProducts::where('id', '=', $id)
->field('id,product_name as title,cover_image as image,price,stock,sales,product_desc,detail_image1,detail_image2,detail_image3,detail_image4,detail_html,is_hot,is_new,is_recommend')->find();
if (!$productDetail) {
return $this->renderError('商品不存在');
}
$productDetail['detail_image'] = [
$productDetail['detail_image1'],
$productDetail['detail_image2'],
$productDetail['detail_image3'],
$productDetail['detail_image4']
];
$productDetail['detail_image'] = array_filter($productDetail['detail_image'], function ($value) {
return !empty($value);
});
unset(
$productDetail['detail_image1'],
$productDetail['detail_image2'],
$productDetail['detail_image3'],
$productDetail['detail_image4']
);
if ($this->getUserId() > 0) {
$productDetail['is_favorite'] = FFFavorites::isFavorite($this->getUserId(), $id);
}
return $this->renderSuccess('', $productDetail);
}
public function PayByOrder()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$productId = $this->request->param('product_id', 0);
$productDetail = FFProducts::where('id', '=', $productId)->find();
if (!$productDetail) {
return $this->renderError('商品不存在');
}
if ($productDetail['sales'] <= 0) {
return $this->renderError('库存不足');
}
// 查询默认地址
$address = UserAddress::where('user_id', $user_id)
->where('is_default', 1)
->where('is_deleted', 0)
->field('id,receiver_name,receiver_phone,detailed_address,is_default')
->find();
if (!$address) {
// 如果没有默认地址,返回最新添加的一条
$address = UserAddress::where('user_id', $user_id)
->where('is_deleted', 0)
->field('id,receiver_name,receiver_phone,detailed_address,is_default')
->order('id', 'desc')
->find();
}
$whe = 'user_id=' . $user_id . ' and status=0 and man_price<=' . $productDetail['price'];
$coupon = CouponReceive::where($whe)
->field('id,title,man_price,price,end_time,status')
->select()->toArray();
$order = [
'product_id' => $productId,
'title' => $productDetail['product_name'],
'image' => $productDetail['cover_image'],
'price' => $productDetail['price'],
'coupon' => $coupon,
'default_address' => $address,
];
return $this->renderSuccess('', $order);
}
/**
* 获取用户收藏商品列表
* @return \think\Response
*/
public function getFavoriteList()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$page = intval($this->request->param('page', 1));
$limit = intval($this->request->param('limit', 10));
// 使用模型静态方法获取收藏列表
$favoriteList = FFFavorites::getUserFavoriteList($user_id, $page, $limit);
// 格式化数据
$result = [];
foreach ($favoriteList as $item) {
if (isset($item['product']) && $item['product']) {
$result[] = [
'id' => $item['product']['id'],
'title' => $item['product']['product_name'],
'image' => $item['product']['cover_image'],
'price' => $item['product']['price'],
'stock' => $item['product']['stock'],
'sales' => $item['product']['sales'],
'favorite_time' => $item['create_time']
];
}
}
return $this->renderSuccess('', $result);
}
/**
* 添加商品收藏
* @return \think\Response
*/
public function addFavorite()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$product_id = intval($this->request->param('product_id', 0));
if (!$product_id) {
return $this->renderError('商品ID不能为空');
}
// 检查商品是否存在
$product = FFProducts::where('id', $product_id)->find();
if (!$product) {
return $this->renderError('商品不存在');
}
// 使用模型静态方法添加收藏
$result = FFFavorites::addFavorite($user_id, $product_id);
return $this->renderSuccess('收藏成功');
}
/**
* 取消商品收藏
* @return \think\Response
*/
public function cancelFavorite()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$product_id = intval($this->request->param('product_id', 0));
if (!$product_id) {
return $this->renderError('商品ID不能为空');
}
// 使用模型静态方法取消收藏
$result = FFFavorites::cancelFavorite($user_id, $product_id);
if ($result) {
return $this->renderSuccess('取消收藏成功');
} else {
return $this->renderError('取消收藏失败');
}
}
/**
* 批量取消收藏
* @return \think\Response
*/
public function batchCancelFavorite()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$product_ids = $this->request->param('product_ids');
if (empty($product_ids)) {
return $this->renderError('商品ID不能为空');
}
// 转换为数组
if (!is_array($product_ids)) {
$product_ids = explode(',', $product_ids);
}
// 批量取消收藏
$result = FFFavorites::batchCancelFavorite($user_id, $product_ids);
if ($result) {
return $this->renderSuccess('批量取消收藏成功');
} else {
return $this->renderError('批量取消收藏失败');
}
}
/**
* 检查商品是否已收藏
* @return \think\Response
*/
public function checkIsFavorite()
{
$user_id = $this->getUserId();
if (!$user_id) {
return $this->renderError('请先登录');
}
$product_id = intval($this->request->param('product_id', 0));
if (!$product_id) {
return $this->renderError('商品ID不能为空');
}
// 检查是否已收藏
$isFavorite = FFFavorites::isFavorite($user_id, $product_id);
return $this->renderSuccess('', ['is_favorite' => $isFavorite ? true : false]);
}
}

259
app/api/controller/News.php Normal file
View File

@ -0,0 +1,259 @@
<?php
declare(strict_types=1);
namespace app\api\controller;
use app\api\controller\Base;
use app\common\model\News as NewsModel;
use app\common\model\UserNewsFavorite;
class News extends Base
{
/**
* 获取精选新闻列表
* @return \think\Response
*/
public function getFeaturedNewsList()
{
$where = [];
$where['status'] = 1;
$where['is_featured'] = 1;
$limit = $this->request->param('limit', 10);
$title = $this->request->param('title', '');
if ($title) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
$newsList = NewsModel::getList($where, 'id,title,cover_image,publish_time', 'publish_time desc', $limit);
return $this->renderSuccess('', $newsList);
}
/**
* 获取热榜新闻列表
* @return \think\Response
*/
public function getHotNewsList()
{
$where = [];
$where['status'] = 1;
$where['is_hot'] = 1;
$title = $this->request->param('title', '');
if ($title) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
$limit = $this->request->param('limit', 10);
$newsList = NewsModel::getList($where, 'id,title,cover_image,publish_time,is_hot', 'publish_time desc', $limit);
return $this->renderSuccess('', $newsList);
}
/**
* 获取用户关注的新闻列表
* @return \think\Response
*/
public function getFollowNewsList()
{
$title = $this->request->param('title', '');
$limit = intval($this->request->param('limit', 10));
$page = intval($this->request->param('page', 1));
$userId = $this->getUserId();
if ($userId == 0) {
return $this->renderSuccess('', ['list' => [], 'count' => 0]);
}
// 构建查询
$model = NewsModel::alias('n')
->join('user_news_favorite u', 'n.id=u.news_id')
->where('u.user_id', '=', $userId)
->where('u.is_canceled', '=', 0)
->where('n.status', '=', 1);
// 如果有标题搜索条件
if ($title) {
$model = $model->where('n.title', 'like', '%' . $title . '%');
}
// 获取总数
$count = $model->count();
// 查询数据并分页
$list = $model->field('n.id, n.title, n.cover_image, n.publish_time, n.author_name')
->order('u.create_time', 'desc')
->page($page, $limit)
->select()
->toArray();
return $this->renderSuccess('', [
'list' => $list,
'count' => $count,
'limit' => $limit,
'page' => $page
]);
}
/**
* 获取新闻详情
* @return \think\Response
*/
public function getNewsDetail()
{
$id = $this->request->param('id', 0);
//来源 0: 热榜1精选2关注
$current = $this->request->param('current', 0);
$newsInfo = NewsModel::getInfo(['id' => $id], 'id,title,cover_image,publish_time,content,author_name');
if (!$newsInfo) {
return $this->renderError('新闻不存在');
}
$newsInfo['content'] = htmlspecialchars_decode($newsInfo['content']);
// 获取上下篇数据
$condition = $this->getCondition($current);
if ($condition) {
// 获取上一篇(发布时间小于当前文章)
$newsInfo['next_data'] = $this->getAdjacentNews($id, $newsInfo['publish_time'], $condition, '<', 'desc');
// 获取下一篇(发布时间大于当前文章)
$newsInfo['prev_data'] = $this->getAdjacentNews($id, $newsInfo['publish_time'], $condition, '>', 'asc');
} else {
$newsInfo['next_data'] = null;
$newsInfo['prev_data'] = null;
}
$newsInfo['user_follow'] = false;
$userId = $this->getUserId();
if ($userId > 0) {
$newsInfo['user_follow'] = UserNewsFavorite::isFavorite($userId, $id);
}
// 随机查询5条新闻数据
$re = NewsModel::where('status', 1)
->where($condition, '=', 1)
->where('cover_image', '!=', '')
->field('id,title,cover_image,publish_time,author_name,is_hot,is_featured')
->orderRaw('rand()')
->limit(5)
->select()
->toArray();
$newsInfo['recommend_news'] = $re;
// $newsInfo['publish_time'] = date('Y-m-d H:i:s', $newsInfo['publish_time']);
return $this->renderSuccess('', $newsInfo);
}
/**
* 根据来源类型获取条件
* @param int $current 来源类型 0: 热榜1精选2关注
* @return string|null 对应的条件字段
*/
private function getCondition($current)
{
switch ($current) {
case 0:
return 'is_hot';
case 1:
return 'is_featured';
case 2:
// 可以根据需求扩展
// return 'is_follow';
return null;
default:
return null;
}
}
/**
* 获取相邻的新闻
* @param int $id 当前新闻ID
* @param int $publishTime 当前发布时间
* @param string $condition 条件字段
* @param string $comparison 比较符号
* @param string $orderType 排序方式
* @return mixed 查询结果
*/
private function getAdjacentNews($id, $publishTime, $condition, $comparison, $orderType)
{
return NewsModel::where('id', '!=', $id)
->where($condition, '=', 1)
->where('status', '=', 1)
->where('publish_time', $comparison, $publishTime)
->field('id,title,cover_image,publish_time,is_hot,is_featured')
->order('publish_time ' . $orderType)
->find();
}
/**
* 收藏新闻
* @return \think\Response
*/
public function addFavorite()
{
$newsId = $this->request->param('news_id', 0);
if (empty($newsId)) {
return $this->renderError('参数错误');
}
// 检查新闻是否存在
$newsInfo = NewsModel::getInfo(['id' => $newsId], 'id');
if (!$newsInfo) {
return $this->renderError('新闻不存在');
}
// 获取当前用户ID
$userId = $this->getUserId();
if (!$userId) {
return $this->renderError('请先登录');
}
// 添加收藏
$result = UserNewsFavorite::addFavorite($userId, $newsId);
if ($result) {
return $this->renderSuccess('收藏成功');
}
return $this->renderError('收藏失败');
}
/**
* 取消收藏新闻
* @return \think\Response
*/
public function cancelFavorite()
{
$newsId = $this->request->param('news_id', 0);
if (empty($newsId)) {
return $this->renderError('参数错误');
}
// 获取当前用户ID
$userId = $this->getUserId();
if (!$userId) {
return $this->renderError('请先登录');
}
// 取消收藏
$result = UserNewsFavorite::cancelFavorite($userId, $newsId);
if ($result) {
return $this->renderSuccess('取消收藏成功');
}
return $this->renderError('取消收藏失败或未收藏该新闻');
}
/**
* 检查新闻是否已收藏
* @return \think\Response
*/
public function checkFavorite()
{
$newsId = $this->request->param('news_id', 0);
if (empty($newsId)) {
return $this->renderError('参数错误');
}
// 获取当前用户ID
$userId = $this->getUserId();
if (!$userId) {
return $this->renderError('请先登录');
}
// 检查是否已收藏
$favorite = UserNewsFavorite::isFavorite($userId, $newsId);
return $this->renderSuccess('', ['is_favorite' => $favorite ? true : false]);
}
}

View File

@ -959,7 +959,7 @@ class User extends Base
/*
海报生成器
*/
public function product_img()
{
@ -1274,10 +1274,43 @@ class User extends Base
return $this->renderError("用户不存在");
}
$userinfo['id'] = $user['id'];
$userinfo['ID'] = $user['id'];
$userinfo['mobile_is'] = $user['mobile'] ? 1 : 0;
$userinfo['username'] = $user['nickname'];
$userinfo['userIcon'] = imageUrl($user['headimg']);
$userinfo['mobile'] = $user['mobile'] ? substr_replace($user['mobile'], '****', 3, 4) : '';
$other = [
'uid' => $user['uid'] ? $user['uid'] : $user['id'],
'pid' => $user['pid'],
'a' => $user['money'],//钻石
'b' => $user['money2'],//达达券
'c' => $user['integral'],//UU币
];
$userinfo['other'] = $this->encryption($other);
$day = floor(abs(time() - $user['addtime']) / 86400);
$userinfo['days'] = $day;
return $this->renderSuccess("请求成功", $userinfo);
}
/**
* 我的
*/
public function userInfo2(Request $request)
{
$user_id = $this->getuserid();
if ($user_id == 0) {
return $this->renderError("未登录");
}
$user = Usermodel::where('id', '=', $user_id)->find();
if (!$user) {
return $this->renderError("用户不存在");
}
$userinfo['id'] = $user['id'];
$userinfo['mobile_is'] = $user['mobile'] ? 1 : 0;
$userinfo['nickname'] = $user['nickname'];
$userinfo['headimg'] = imageUrl($user['headimg']);
$userinfo['userIcon'] = imageUrl($user['headimg']);
$userinfo['mobile'] = $user['mobile'] ? substr_replace($user['mobile'], '****', 3, 4) : '';
$userinfo['money'] = $user['money'];//钻石
$userinfo['money2'] = $user['money2'];//达达券
@ -1289,6 +1322,7 @@ class User extends Base
return $this->renderSuccess("请求成功", $userinfo);
}
/**
* 绑定邀请码
*/

View File

@ -30,12 +30,13 @@ Route::any('user_yaoqing', 'Index/get_user_yaoqing');
// Route::any('yushourili', 'Index/yushourili');
Route::any('danye', 'Index/danye');
Route::any('getDanye', 'Index/getDanye');
Route::any('getAgreement', 'Index/getDanye');
#============================
#User.php个人中心
#============================
Route::any('user', 'User/user');
Route::any('userInfo', 'User/userInfo');
Route::any('userInfo', 'User/userInfo2');
Route::any('get_userInfo', 'User/userInfo');
Route::any('update_userinfo', 'User/update_userinfo');
Route::any('vip_list', 'User/vip_list');
Route::any('profitIntegral', 'User/profitIntegral');
@ -55,6 +56,7 @@ Route::any('recharge', 'User/recharge');
Route::any('item_card_list', 'User/item_card_list');
Route::any('bind_invite_code', 'User/bind_invite_code');
Route::any('user_log_off', 'User/user_log_off');
Route::any('deleteAccount', 'User/user_log_off');
#Rank.php排行榜
#============================
Route::any('rank_week', 'Rank/rank_week');
@ -90,7 +92,7 @@ Route::any('getGoodExtend', 'Goods/getGoodExtend');
Route::any('coupon', 'Coupon/index');
Route::any('receive', 'Coupon/receive');
Route::any('used', 'Coupon/used');
Route::any('get_coupon_list', 'Coupon/get_coupon_list');
#============================
#Infinite.php 无限赏管理
#============================
@ -230,6 +232,39 @@ Route::any('get_diamond_list', 'Mall/get_diamond_list');
Route::any('createOrderProducts', 'Mall/createOrderProducts');
Route::any('get_diamond_order_log', 'Mall/get_diamond_order_log');
#============================
# 新闻管理
#============================
Route::any('get_featured_news_list', 'News/getFeaturedNewsList');
Route::any('get_hot_news_list', 'News/getHotNewsList');
Route::any('get_news_detail', 'News/getNewsDetail');
Route::any('get_follow_news_list', 'News/getFollowNewsList');
Route::any('user_favorite_news', 'News/addFavorite');
Route::any('user_cancel_favorite_news', 'News/cancelFavorite');
#============================
# 商品管理
#============================
Route::any('get_banner_list', 'FFProductsController/getBannerList');
Route::any('get_product_list', 'FFProductsController/getProductList');
Route::any('get_product_detail', 'FFProductsController/getProductDetail');
Route::any('pay_by_order', 'FFProductsController/PayByOrder');
Route::any('get_favorite_list', 'FFProductsController/getFavoriteList');
Route::any('add_favorite', 'FFProductsController/addFavorite');
Route::any('cancel_favorite', 'FFProductsController/cancelFavorite');
Route::any('batch_cancel_favorite', 'FFProductsController/batchCancelFavorite');
Route::any('check_is_favorite', 'FFProductsController/checkIsFavorite');
Route::any('pay_by_create_order', 'FFOrdersController/createOrder');
Route::any('order_pay_success', 'FFOrdersController/orderPaySuccess');
Route::any('get_order_list', 'FFOrdersController/getOrderList');
Route::any('order_receive', 'FFOrdersController/orderReceive');
Route::any('apply_refund', 'FFOrdersController/applyRefund');
Route::any('cancel_refund', 'FFOrdersController/cancelRefund');
Route::any('delete_order', 'FFOrdersController/deleteOrder');
Route::any('get_order_detail', 'FFOrdersController/getOrderDetail');
Route::any('apply_invoice', 'FFOrdersController/applyInvoice');
Route::any('get_order_statistics', 'FFOrdersController/getOrderStatistics');
#============================APP使用的路由 ============================#
Route::any('V5Vx6qHOM5Ks9HqH', 'Login/login');

View File

@ -0,0 +1,104 @@
<?php
namespace app\common\model;
use app\common\model\Base;
use think\Model;
class FFCategories extends Base{
// 设置当前模型对应的完整数据表名称
protected $table = 'ff_categories';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
/**
* 获取分页列表
* @param array $where 查询条件
* @param string $field 查询字段
* @param string $order 排序规则
* @param string $pageSize 每页数量
* @return array
*/
public static function getList($where = [], $field = '*', $order = 'sort_order asc', $pageSize = "15")
{
$list = self::where($where)
->field($field)
->order($order)
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
$page = $list->render();
$data['list'] = $list->toArray()['data'];
$data['count'] = $list->total();
$data['page'] = $page;
return $data;
}
/**
* 获取所有列表(不分页)
* @param array $where 查询条件
* @param string $field 查询字段
* @param string $order 排序规则
* @param string $limit 限制条数
* @return \think\Collection
*/
public static function getAllList($where = [], $field = '*', $order = 'sort_order asc', $limit = '0')
{
$data = self::where($where)
->field($field)
->order($order)
->limit($limit)
->select();
return $data;
}
/**
* 获取单条数据
* @param array $where 查询条件
* @param string $field 查询字段
* @return array|Model|null
*/
public static function getInfo($where = [], $field = '*')
{
$data = self::where($where)
->field($field)
->find();
return $data;
}
/**
* 获取树形结构分类数据
* @param int $parentId 父级ID
* @param array $where 额外查询条件
* @return array
*/
public static function getTreeList($parentId = 0, $where = [])
{
$where[] = ['status', '=', 1];
$allCategories = self::getAllList($where)->toArray();
return self::buildTree($allCategories, $parentId);
}
/**
* 构建树形结构
* @param array $elements 所有元素
* @param int $parentId 父级ID
* @return array
*/
protected static function buildTree(array $elements, $parentId = 0)
{
$branch = [];
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = self::buildTree($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
}

View File

@ -0,0 +1,145 @@
<?php
declare(strict_types=1);
namespace app\common\model;
use think\Model;
/**
* 用户商品收藏模型
* Class FFFavorites
* @package app\common\model
*/
class FFFavorites extends Model
{
// 设置表名
protected $name = 'ff_favorites';
// 设置主键
protected $pk = 'favorite_id';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
// 关联商品
public function product()
{
return $this->belongsTo('FFProducts', 'product_id', 'id');
}
/**
* 查询用户是否收藏了指定商品
* @param int $userId 用户ID
* @param int $productId 商品ID
* @return bool|array false表示未收藏array表示收藏信息
*/
public static function isFavorite($userId, $productId)
{
$where = [
'user_id' => $userId,
'product_id' => $productId,
];
$favorite = self::where($where)->find();
return $favorite ? $favorite->toArray() : false;
}
/**
* 添加收藏
* @param int $userId 用户ID
* @param int $productId 商品ID
* @return bool|array 收藏结果
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function addFavorite($userId, $productId)
{
// 检查是否已收藏
$favorite = self::where([
'user_id' => $userId,
'product_id' => $productId,
])->find();
if ($favorite) {
// 已收藏,返回已存在
return $favorite->toArray();
}
// 新增收藏
$model = new self();
$model->user_id = $userId;
$model->product_id = $productId;
$model->save();
return $model->toArray();
}
/**
* 取消收藏
* @param int $userId 用户ID
* @param int $productId 商品ID
* @return bool 取消结果
*/
public static function cancelFavorite($userId, $productId)
{
return self::where([
'user_id' => $userId,
'product_id' => $productId,
])->delete();
}
/**
* 获取用户收藏列表
* @param int $userId 用户ID
* @param int $page 页码
* @param int $limit 每页条数
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getUserFavoriteList($userId, $page = 1, $limit = 10)
{
$list = self::where('user_id', $userId)
->with(['product'])
->page($page, $limit)
->order('create_time', 'desc')
->select();
return $list ? $list->toArray() : [];
}
/**
* 获取商品收藏数量
* @param int $productId 商品ID
* @return int 收藏数量
*/
public static function getProductFavoriteCount($productId)
{
return self::where('product_id', $productId)->count();
}
/**
* 批量取消收藏
* @param int $userId 用户ID
* @param array $productIds 商品ID数组
* @return int 影响行数
*/
public static function batchCancelFavorite($userId, $productIds)
{
return self::where('user_id', $userId)
->whereIn('product_id', $productIds)
->delete();
}
/**
* 关联用户表
* @return \think\model\relation\HasOne
*/
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace app\common\model;
use app\common\model\Base;
use app\common\model\User;
use think\Model;
class FFOrders extends Base
{
// 设置当前模型对应的完整数据表名称
protected $table = 'ff_orders';
// 设置主键
protected $pk = 'order_id';
/**
* 获取列表
*/
public static function getList($where = [], $field = '*', $order = 'order_id desc', $pageSize = "15")
{
$list = self::where($where)
->field($field)
->order($order)
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
$page = $list->render();
$data['list'] = $list->toArray()['data'];
$data['count'] = $list->total();
$data['last_page'] = $list->toArray()['last_page'];
$data['page'] = $page;
return $data;
}
/**
* 获取列表 不分页
*/
public static function getAllList($where = [], $field = '*', $order = 'order_id desc', $limit = '0')
{
$data = self::where($where)
->field($field)
->order($order)
->limit($limit)
->select();
return $data;
}
/**
* 获取单条数据
*/
public static function getInfo($where = [], $field = '*')
{
$data = self::where($where)
->field($field)
->find();
return $data;
}
/**
* 获取关联用户信息
*/
public function getUserInfoAttr($value, $data)
{
$user_info = User::field('nickname,headimg,mobile')->where(['id' => $data['user_id']])->find();
return $user_info;
}
/**
* 订单状态获取器
*/
public function getOrderStatusTextAttr($value, $data)
{
$status = [
0 => '待支付',
1 => '已支付待发货',
2 => '已发货',
3 => '已完成',
4 => '已关闭',
5 => '已取消'
];
return isset($status[$data['order_status']]) ? $status[$data['order_status']] : '未知状态';
}
/**
* 支付状态获取器
*/
public function getPayStatusTextAttr($value, $data)
{
$status = [
0 => '未支付',
1 => '支付中',
2 => '已支付'
];
return isset($status[$data['pay_status']]) ? $status[$data['pay_status']] : '未知状态';
}
/**
* 配送状态获取器
*/
public function getShippingStatusTextAttr($value, $data)
{
$status = [
0 => '未发货',
1 => '已发货',
2 => '已收货'
];
return isset($status[$data['shipping_status']]) ? $status[$data['shipping_status']] : '未知状态';
}
/**
* 支付方式获取器
*/
public function getPaymentTypeTextAttr($value, $data)
{
$types = [
1 => '支付宝',
2 => '微信',
3 => '银联'
];
return isset($types[$data['payment_type']]) ? $types[$data['payment_type']] : '未知方式';
}
/**
* 订单来源获取器
*/
public function getSourceTextAttr($value, $data)
{
$sources = [
1 => 'PC',
2 => 'APP',
3 => '小程序',
4 => 'H5'
];
return isset($sources[$data['source']]) ? $sources[$data['source']] : '未知来源';
}
/**
* 发票类型获取器
*/
public function getInvoiceTypeTextAttr($value, $data)
{
if (empty($data['invoice_type'])) {
return '';
}
$types = [
1 => '个人',
2 => '企业'
];
return isset($types[$data['invoice_type']]) ? $types[$data['invoice_type']] : '未知类型';
}
}

View File

@ -0,0 +1,170 @@
<?php
namespace app\common\model;
use app\common\model\Base;
use think\Model;
class FFProducts extends Base{
// 设置当前模型对应的完整数据表名称
protected $table = 'ff_products';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
/**
* 获取分页列表
* @param array $where 查询条件
* @param string $field 查询字段
* @param string $order 排序规则
* @param string $pageSize 每页数量
* @return array
*/
public static function getList($where = [], $field = '*', $order = 'create_time desc', $pageSize = "15")
{
$list = self::where($where)
->field($field)
->order($order)
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
$page = $list->render();
$data['list'] = $list->toArray()['data'];
$data['count'] = $list->total();
$data['page'] = $page;
return $data;
}
/**
* 获取所有列表(不分页)
* @param array $where 查询条件
* @param string $field 查询字段
* @param string $order 排序规则
* @param string $limit 限制条数
* @return \think\Collection
*/
public static function getAllList($where = [], $field = '*', $order = 'create_time desc', $limit = '0')
{
$data = self::where($where)
->field($field)
->order($order)
->limit($limit)
->select();
return $data;
}
/**
* 获取单条数据
* @param array $where 查询条件
* @param string $field 查询字段
* @return array|Model|null
*/
public static function getInfo($where = [], $field = '*')
{
$data = self::where($where)
->field($field)
->find();
return $data;
}
/**
* 获取热销商品
*/
public static function getHotProducts($limit = 10, $field = '*')
{
return self::where('status', 1)
->where('is_hot', 1)
->field($field)
->order('sales desc')
->limit($limit)
->select();
}
/**
* 获取新品商品
*/
public static function getNewProducts($limit = 10, $field = '*')
{
return self::where('status', 1)
->where('is_new', 1)
->field($field)
->order('create_time desc')
->limit($limit)
->select();
}
/**
* 获取推荐商品
*/
public static function getRecommendProducts($limit = 10, $field = '*')
{
return self::where('status', 1)
->where('is_recommend', 1)
->field($field)
->order('create_time desc')
->limit($limit)
->select();
}
/**
* 根据分类名称获取商品
* @param string $categoryName 分类名称
* @param int $limit 限制条数
* @param string $field 查询字段
* @return \think\Collection
*/
public static function getProductsByCategory($categoryName, $limit = 10, $field = '*')
{
return self::where('status', 1)
->where('category_name', 'like', "%{$categoryName}%")
->field($field)
->order('create_time desc')
->limit($limit)
->select();
}
/**
* 搜索商品
*/
public static function searchProducts($keyword, $field = '*', $pageSize = 15)
{
return self::where('status', 1)
->where(function ($query) use ($keyword) {
$query->where('product_name', 'like', "%{$keyword}%")
->whereOr('product_desc', 'like', "%{$keyword}%")
->whereOr('category_name', 'like', "%{$keyword}%");
})
->field($field)
->order('create_time desc')
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
}
/**
* 更新库存
* @param int $id 商品ID
* @param int $num 减少的数量
* @return bool
*/
public static function updateStock($id, $num)
{
return self::where('id', $id)
->where('stock', '>=', $num)
->dec('stock', $num)
->inc('sales', $num)
->update();
}
/**
* 根据条件获取商品列表并按价格排序
* @param array $where 查询条件
* @param string $order 排序规则 asc-升序 desc-降序
* @param int $pageSize 每页数量
* @return array
*/
public static function getListByPrice($where = [], $order = 'asc', $pageSize = 15)
{
$orderRule = $order == 'asc' ? 'price asc' : 'price desc';
return self::getList($where, '*', $orderRule, $pageSize);
}
}

110
app/common/model/News.php Normal file
View File

@ -0,0 +1,110 @@
<?php
namespace app\common\model;
use think\Model;
class News extends Base
{
// 设置当前模型对应的完整数据表名称
protected $table = 'news';
// 设置字段自动写入时间戳
protected $autoWriteTimestamp = true;
// 定义时间戳字段名
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
/**
* 获取列表(分页)
*/
public static function getList($where, $field = '*', $order = 'publish_time desc', $pageSize = "15")
{
$list = self::where($where)
->field($field)
->order($order)
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
$page = $list->render();
$data['list'] = $list->toArray()['data'];
$data['count'] = $list->total();
$data['last_page'] = $list->toArray()['last_page'];
// $data['page'] = $page;
return $data;
}
/**
* 获取全部列表(不分页)
*/
public static function getAllList($where = [], $field = '*', $order = 'publish_time desc', $limit = '0')
{
$data = self::where($where)
->field($field)
->order($order)
->limit($limit)
->select();
return $data;
}
/**
* 获取单条数据
*/
public static function getInfo($where = [], $field = '*')
{
$data = self::where($where)
->field($field)
->find();
return $data;
}
/**
* 获取热榜资讯
*/
public static function getHotNews($limit = 10, $field = '*')
{
return self::where('status', 1)
->where('is_hot', 1)
->field($field)
->order('publish_time desc')
->limit($limit)
->select();
}
/**
* 获取精选资讯
*/
public static function getFeaturedNews($limit = 10, $field = '*')
{
return self::where('status', 1)
->where('is_featured', 1)
->field($field)
->order('publish_time desc')
->limit($limit)
->select();
}
/**
* 根据作者ID获取资讯
*/
public static function getNewsByAuthor($authorId, $limit = 10, $field = '*')
{
return self::where('status', 1)
->where('author_id', $authorId)
->field($field)
->order('publish_time desc')
->limit($limit)
->select();
}
/**
* 搜索资讯
*/
public static function searchNews($keyword, $field = '*', $pageSize = 15)
{
return self::where('status', 1)
->where('title', 'like', '%' . $keyword . '%')
->field($field)
->order('publish_time desc')
->paginate(['list_rows' => $pageSize, 'query' => request()->param()]);
}
}

View File

@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
namespace app\common\model;
use think\Model;
/**
* 用户收藏资讯模型
* Class UserNewsFavorite
* @package app\common\model
*/
class UserNewsFavorite extends Model
{
// 设置表名
protected $name = 'user_news_favorite';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳字段
protected $autoWriteTimestamp = true;
// 定义时间戳字段名
protected $createTime = 'create_time';
protected $updateTime = false; // 不使用更新时间
/**
* 查询用户是否收藏了指定新闻
* @param int $userId 用户ID
* @param int $newsId 新闻ID
* @return bool|array false表示未收藏array表示收藏信息
*/
public static function isFavorite($userId, $newsId)
{
$where = [
'user_id' => $userId,
'news_id' => $newsId,
'is_canceled' => 0, // 未取消收藏
];
$favorite = self::where($where)->find();
return $favorite ? $favorite->toArray() : false;
}
/**
* 添加收藏
* @param int $userId 用户ID
* @param int $newsId 新闻ID
* @return bool|array 收藏结果
*/
public static function addFavorite($userId, $newsId)
{
// 检查是否已收藏
$favorite = self::where([
'user_id' => $userId,
'news_id' => $newsId,
])->find();
if ($favorite) {
// 已收藏但被取消,则恢复收藏
if ($favorite['is_canceled'] == 1) {
$favorite->is_canceled = 0;
$favorite->cancel_time = null;
$favorite->create_time = date('Y-m-d H:i:s');
$favorite->save();
return $favorite->toArray();
}
// 已收藏未取消,返回已存在
return $favorite->toArray();
}
// 新增收藏
$model = new self();
$model->user_id = $userId;
$model->news_id = $newsId;
$model->is_canceled = 0;
$model->save();
return $model->toArray();
}
/**
* 取消收藏
* @param int $userId 用户ID
* @param int $newsId 新闻ID
* @return bool 取消结果
*/
public static function cancelFavorite($userId, $newsId)
{
$favorite = self::where([
'user_id' => $userId,
'news_id' => $newsId,
'is_canceled' => 0,
])->find();
if (!$favorite) {
return false;
}
$favorite->is_canceled = 1;
$favorite->cancel_time = date('Y-m-d H:i:s');
return $favorite->save() !== false;
}
/**
* 获取用户收藏列表
* @param int $userId 用户ID
* @param int $page 页码
* @param int $limit 每页条数
* @return array 收藏列表
*/
public static function getUserFavoriteList($userId, $page = 1, $limit = 10)
{
$where = [
'user_id' => $userId,
'is_canceled' => 0,
];
$list = self::where($where)
->with(['news' => function ($query) {
$query->field('id,title,cover_image,publish_time,author_name');
}])
->page($page, $limit)
->order('create_time', 'desc')
->select()
->toArray();
return $list;
}
/**
* 关联新闻表
* @return \think\model\relation\HasOne
*/
public function news()
{
return $this->hasOne(News::class, 'id', 'news_id');
}
}

View File

@ -35,12 +35,19 @@ class AppPlatform extends BasePlatform
$versionNumber = (int) preg_replace('/[^0-9]/', '', $version);
$config = [
'isWebPay' => false,
'isCheck' => false,
'buildVersion' => '106',
'version' => '1.0.0',
'userAgreement' => "https://zfunbox.cn?_p=cb20xad0e35094521ae46a1d1fb0ddd1&time=" . time()
];
$is_env_test = EnvHelper::getIsTest();
if ($is_env_test) {
$config['userAgreement'] = "https://testweb.zfunbox.cn?_p=cb20xad0e35094521ae46a1d1fb0ddd1&time=" . time();
}
$configVersion = (int) preg_replace('/[^0-9]/', '', $config['version']);
if ($versionNumber >= $configVersion) {
$config['isCheck'] = true;
$config['buildVersion'] = '105';
// $config['isCheck'] = true;
$config['userAgreement'] = "https://zfunbox.cn/pages/guize/guize?type=4";
}
return $config;
}

View File

@ -25,7 +25,7 @@ class PlatformFactory
if ($client == "WEB_APP") {
return new H5Platform();
}
if ($client == "APP_ANDROID") {
if ($client == "APP_ANDROID" || $client == "WEB_APP_ANDROID") {
return new AppPlatform();
}
if ($client == "APP_IOS") {

View File

@ -36,7 +36,7 @@ return [
'url' => '/admin/sign_config',
'name' => '用户签到设置',
],
// [
// 'url' => '/admin/user_loginStat',
// 'name' => '用户登录统计',
@ -96,7 +96,7 @@ return [
'url' => '/admin/diamond',
'name' => '钻石商品配置',
],
],
],
[
@ -217,6 +217,23 @@ return [
],
],
],
[
'name' => '审核页面管理',
'son' => [
[
'url' => '/admin/news',
'name' => '新闻列表',
],
[
'url' => '/admin/ff_categories',
'name' => '商品分类管理',
],
[
'url' => '/admin/ff_products',
'name' => '商品列表',
],
],
],
[
'name' => '管理员管理',
'son' => [
@ -277,7 +294,7 @@ return [
// 'url' => '/admin/wechatofficialaccount',
// 'name' => '公众号设置',
// ],
],
],

3
public/js/quill/quill.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long