You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers\Admin;
use App\Exports\BaseExport;
use App\Exports\CommonExport;
use App\Helpers\ResponseCode;
use App\Models\AppointmentType;
use App\Models\CustomForm;
use App\Models\Dialogue;
use App\Models\Message;
use App\Models\SupplyDemand;
use App\Models\SupplyDemandType;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Facades\Excel;
class SupplyDemandController extends BaseController
{
/**
* 构造函数
*/
public function __construct()
{
parent::__construct(new SupplyDemand());
}
/**
* @OA\Get(
* path="/api/admin/supply-demand/index",
* tags={"供需信息管理"},
* summary="列表",
* description="",
* @OA\Parameter(name="is_export", in="query", @OA\Schema(type="string"), required=false, description="是否导出0否1是"),
* @OA\Parameter(name="export_fields", in="query", @OA\Schema(type="string"), required=false, description="需要导出的字段数组"),
* @OA\Parameter(name="filter", in="query", @OA\Schema(type="string"), required=false, description="查询条件。数组"),
* @OA\Parameter(name="show_relation", in="query", @OA\Schema(type="string"), required=false, description="需要输出的关联关系数组,包括:teacher,courseSettings,coursePeriods"),
* @OA\Parameter(name="page_size", in="query", @OA\Schema(type="string"), required=false, description="每页显示的条数"),
* @OA\Parameter(name="page", in="query", @OA\Schema(type="string"), required=false, description="页码"),
* @OA\Parameter(name="sort_name", in="query", @OA\Schema(type="string"), required=false, description="排序字段名字"),
* @OA\Parameter(name="sort_type", in="query", @OA\Schema(type="string"), required=false, description="排序类型"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function index()
{
$all = request()->all();
$list = $this->model->with('user')->where(function ($query) use ($all) {
if (isset($all['filter']) && !empty($all['filter'])) {
foreach ($all['filter'] as $condition) {
$key = $condition['key'] ?? null;
$op = $condition['op'] ?? null;
$value = $condition['value'] ?? null;
if (!isset($key) || !isset($op) || !isset($value)) {
continue;
}
// 等于
if ($op == 'eq') {
$query->where($key, $value);
}
// 不等于
if ($op == 'neq') {
$query->where($key, '!=', $value);
}
// 大于
if ($op == 'gt') {
$query->where($key, '>', $value);
}
// 大于等于
if ($op == 'egt') {
$query->where($key, '>=', $value);
}
// 小于
if ($op == 'lt') {
$query->where($key, '<', $value);
}
// 小于等于
if ($op == 'elt') {
$query->where($key, '<=', $value);
}
// 模糊搜索
if ($op == 'like') {
$query->where($key, 'like', '%' . $value . '%');
}
// 否定模糊搜索
if ($op == 'notlike') {
$query->where($key, 'not like', '%' . $value . '%');
}
// 范围搜索
if ($op == 'range') {
list($from, $to) = explode(',', $value);
if (empty($from) || empty($to)) {
continue;
}
$query->whereBetween($key, [$from, $to]);
}
}
}
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
if (isset($all['is_export']) && !empty($all['is_export'])) {
$list = $list->limit(5000)->get()->toArray();
return Excel::download(new CommonExport($list, $all['export_fields'] ?? ''), $all['file_name'] ?? '' . date('YmdHis') . '.xlsx');
} else {
// 输出
$list = $list->paginate($all['page_size'] ?? 20);
}
return $this->success($list);
}
/**
* @OA\Get(
* path="/api/admin/supply-demand/show",
* tags={"供需信息管理"},
* summary="详情",
* description="",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"),
* @OA\Parameter(name="show_relation", in="query", @OA\Schema(type="string"), required=false, description="需要输出的关联关系数组,填写输出指定数据"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function show()
{
$all = \request()->all();
$messages = [
'id.required' => 'Id必填',
];
$validator = Validator::make($all, [
'id' => 'required'
], $messages);
if ($validator->fails()) {
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
}
$detail = $this->model->with('user')->find($all['id']);
return $this->success($detail);
}
/**
* @OA\Post(
* path="/api/admin/supply-demand/save",
* tags={"供需信息管理"},
* summary="更新或新增",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="integer"), required=false, description="需求供应表ID(存在则更新,不存在则新增)"),
* @OA\Parameter(name="title", in="query", @OA\Schema(type="string"), required=false, description="标题"),
* @OA\Parameter(name="supply_demand_type_id", in="query", @OA\Schema(type="integer"), required=false, description="分类ID"),
* @OA\Parameter(name="content", in="query", @OA\Schema(type="string"), required=false, description="内容"),
* @OA\Parameter(name="tag", in="query", @OA\Schema(type="string"), required=false, description="标签"),
* @OA\Parameter(name="wechat", in="query", @OA\Schema(type="string"), required=false, description="微信号"),
* @OA\Parameter(name="mobile", in="query", @OA\Schema(type="string"), required=false, description="电话"),
* @OA\Parameter(name="email", in="query", @OA\Schema(type="string"), required=false, description="邮箱"),
* @OA\Parameter(name="status", in="query", @OA\Schema(type="integer"), required=false, description="状态0待审核1通过2拒绝3退回修改4永久隐藏"),
* @OA\Response(
* response=200,
* description="操作成功"
* )
* )
*/
public function save()
{
return parent::save();
}
/**
* @OA\Get(
* path="/api/admin/supply-demand/destroy",
* tags={"供需信息管理"},
* summary="删除",
* description="",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function destroy()
{
return parent::destroy();
}
/**
* @OA\Get(
* path="/api/admin/supply-demand/chart",
* tags={"供需信息管理"},
* summary="交互统计",
* description="",
* @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string"), required=true, description="开始日期"),
* @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string"), required=true, description="结束日期"),
* @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="type类型"),
* @OA\Parameter(name="page_size", in="query", @OA\Schema(type="string"), required=false, description="每页显示的条数"),
* @OA\Parameter(name="page", in="query", @OA\Schema(type="string"), required=false, description="页码"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function chart()
{
$start = \Illuminate\Support\Carbon::parse(request('start_date', date('Y-m-d')))->startOfDay();
$end = \Illuminate\Support\Carbon::parse(request('end_date', date('Y-m-d')))->endOfDay();
if ($start->gt($end)) {
return $this->fail([ResponseCode::ERROR_PARAMETER, '开始日期不能晚于结束日期']);
}
$type = request('type');
$days = $start->diffInDays($end->copy()->startOfDay()) + 1;
$prevEnd = $start->copy()->subDay()->endOfDay();
$prevStart = $start->copy()->subDays($days);
$supplyQuery = function () use ($type) {
return SupplyDemand::when($type, function ($q) use ($type) {
$q->where('type', $type);
});
};
// 发布数按发布时间,私信与双向交互按消息发生时间统计。
$messageQuery = function ($from, $to) use ($type) {
return Message::whereBetween('created_at', [$from, $to])
->whereColumn('user_id', '<>', 'to_user_id')
->whereHas('supplyDemand', function ($q) use ($type) {
if ($type) $q->where('type', $type);
});
};
$supplyDemandCount = $supplyQuery()->whereBetween('created_at', [$start, $end])->count();
$prevSupplyDemandCount = $supplyQuery()->whereBetween('created_at', [$prevStart, $prevEnd])->count();
$messageCount = $messageQuery($start, $end)->count();
$prevMessageCount = $messageQuery($prevStart, $prevEnd)->count();
// 同一供需、同一会话中双方均有发言,计一次。
$interactionCount = $messageQuery($start, $end)->whereNotNull('dialogue_id')
->select('supply_demand_id', 'dialogue_id')->groupBy('supply_demand_id', 'dialogue_id')
->havingRaw('COUNT(DISTINCT user_id) >= 2')->get()->count();
$prevInteractionCount = $messageQuery($prevStart, $prevEnd)->whereNotNull('dialogue_id')
->select('supply_demand_id', 'dialogue_id')->groupBy('supply_demand_id', 'dialogue_id')
->havingRaw('COUNT(DISTINCT user_id) >= 2')->get()->count();
$supplyDemandGrowthRate = $this->calculateGrowthRate($supplyDemandCount, $prevSupplyDemandCount);
$messageGrowthRate = $this->calculateGrowthRate($messageCount, $prevMessageCount);
$interactionGrowthRate = $this->calculateGrowthRate($interactionCount, $prevInteractionCount);
// 包含本期发布的信息,以及历史发布但本期有咨询的信息。
$list = $supplyQuery()->with(['user', 'messages' => function ($q) use ($start, $end) {
$q->whereBetween('created_at', [$start, $end])
->whereColumn('user_id', '<>', 'to_user_id')
->with(['dialogue.user', 'dialogue.toUser'])->orderBy('created_at', 'desc');
}])->where(function ($q) use ($start, $end) {
$q->whereBetween('created_at', [$start, $end])->orWhereHas('messages', function ($m) use ($start, $end) {
$m->whereBetween('created_at', [$start, $end])->whereColumn('user_id', '<>', 'to_user_id');
});
})->orderBy('id', 'desc')->paginate(request('page_size', 20));
foreach ($list as $item) {
$dialogues = $item->messages->pluck('dialogue')->filter()->unique('id')->values();
$item->setRelation('dialogues', $dialogues);
$item->unsetRelation('messages');
}
return $this->success([
'list' => $list,
'supply_demand_count' => $supplyDemandCount,
'prev_supply_demand_count' => $prevSupplyDemandCount,
'supply_demand_growth_rate' => $supplyDemandGrowthRate,
'message_count' => $messageCount,
'prev_message_count' => $prevMessageCount,
'message_growth_rate' => $messageGrowthRate,
'interaction_count' => $interactionCount,
'prev_interaction_count' => $prevInteractionCount,
'interaction_growth_rate' => $interactionGrowthRate,
]);
}
/**
* 计算增长率
* @param int $current 当前数值
* @param int $previous 上期数值
* @return array 包含增长率和增长状态
*/
private function calculateGrowthRate($current, $previous)
{
if ($previous == 0) {
if ($current > 0) {
return [
'rate' => 100,
'status' => 'increase',
'display' => '+100%'
];
} else {
return [
'rate' => 0,
'status' => 'stable',
'display' => '0%'
];
}
}
$rate = round(($current - $previous) / $previous * 100, 2);
if ($rate > 0) {
$status = 'increase';
$display = '+' . $rate . '%';
} elseif ($rate < 0) {
$status = 'decrease';
$display = $rate . '%';
} else {
$status = 'stable';
$display = '0%';
}
return [
'rate' => $rate,
'status' => $status,
'display' => $display
];
}
/**
* @OA\Get(
* path="/api/admin/supply-demand/message-list",
* tags={"供需信息管理"},
* summary="消息列表",
* description="",
* @OA\Parameter(name="to_user_id", in="query", @OA\Schema(type="string"), required=true, description="接收人"),
* @OA\Parameter(name="user_id", in="query", @OA\Schema(type="string"), required=true, description="发起人"),
* @OA\Parameter(name="page_size", in="query", @OA\Schema(type="string"), required=false, description="每页显示的条数"),
* @OA\Parameter(name="page", in="query", @OA\Schema(type="string"), required=false, description="页码"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function messageList()
{
$all = \request()->all();
$messages = [
'to_user_id.required' => '接收人必填',
'user_id.required' => '接收人必填',
];
$validator = Validator::make($all, [
'user_id' => 'required',
'to_user_id' => 'required'
], $messages);
if ($validator->fails()) {
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
}
// 获取会话id
$dialogue = Dialogue::where(function ($query) use ($all) {
$query->where('user_id', $all['user_id'])->where('to_user_id', $all['to_user_id']);
})->orWhere(function ($query) use ($all) {
$query->where('user_id', $all['to_user_id'])->where('to_user_id', $all['user_id']);
})->first();
if (empty($dialogue)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '会话不存在']);
}
$message = Message::with([
'user' => function ($query) {
$query->select('id', 'nickname', 'name', 'headimgurl', 'username');
},
'toUser' => function ($query) {
$query->select('id', 'nickname', 'name', 'headimgurl', 'username');
}
])->where(function ($query) use ($dialogue) {
$query->where('dialogue_id', $dialogue->id);
if (request('supply_demand_id')) {
$query->where('supply_demand_id', request('supply_demand_id'));
}
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc')
->paginate($all['page_size'] ?? 20);
return $this->success(compact('message'));
}
}