反馈更改

master
lion 4 weeks ago
commit 7935e54b06

@ -87,7 +87,7 @@ class UpdateCompany extends Command
'logo' => $result['logo'],
'company_legal_representative' => $result['operName'],
'company_province' => $result['province'],
'company_industry' => $result['qccIndustry'],
'company_industry' => combineKeyValue($result['qccIndustry']),
'regist_amount' => $result['registAmount'],
'regist_capi_type' => $result['registCapiType'],
'company_date' => $result['startDate'],
@ -96,7 +96,7 @@ class UpdateCompany extends Command
'currency_type' => $result['currencyType'],
'stock_number' => $result['stockNumber'],
'stock_type' => $result['stockType'],
'company_tag' => $result['tagList'],
'company_tag' => implode(',', $result['tagList']),
];
$company = Company::updateOrCreate($where, $data);
// 更新用户关联

@ -55,18 +55,18 @@ class UpdateUserNo extends Command
$courses = Course::with(['courseSigns' => function ($query) {
$query->where('status', 1);
}])->where('start_date', $date)
->whereNotNull('student_prefix')
->orderBy('start_date')
->get();
$i = 1;
// 编号前缀
$prefix = date('Ymd', strtotime($date));
foreach ($courses as $course) {
foreach ($course->courseSigns as $sign) {
$user = User::find($sign->user_id);
if ($user->no) {
continue;
}
$no = $prefix . str_pad($i, 3, '0', STR_PAD_LEFT);
$no = $course->student_prefix . str_pad($i, 3, '0', STR_PAD_LEFT);
// 更新用户编号
$user->no = $no;
$user->save();

@ -138,7 +138,7 @@ class CourseContentController extends BaseController
if ($validator->fails()) {
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
}
$detail = $this->model->with('courseContentEvaluation.courseContentEvaluationAsks', 'teacher', 'directionDetail')->find($all['id']);
$detail = $this->model->with('courseContentEvaluation.courseContentEvaluationAsks', 'teacher')->find($all['id']);
return $this->success($detail);
}
@ -162,6 +162,8 @@ class CourseContentController extends BaseController
* @OA\Parameter(name="file_ids", in="query", @OA\Schema(type="string"), description="文件id数组"),
* @OA\Parameter(name="direction", in="query", @OA\Schema(type="string"), description="课程方向"),
* @OA\Parameter(name="remark", in="query", @OA\Schema(type="string"), description="备注"),
* @OA\Parameter(name="salary", in="query", @OA\Schema(type="string"), description="课酬"),
* @OA\Parameter(name="tutor", in="query", @OA\Schema(type="string"), description="导师"),
* @OA\Response(
* response=200,
* description="操作成功"
@ -290,9 +292,9 @@ class CourseContentController extends BaseController
if (!in_array('课程主题', $keyList)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '课程主题字段不存在']);
}
if (!in_array('主题方向', $keyList)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '主题方向字段不存在']);
}
// if (!in_array('主题方向', $keyList)) {
// return $this->fail([ResponseCode::ERROR_BUSINESS, '主题方向字段不存在']);
// }
// if (!in_array('上课地点', $keyList)) {
// return $this->fail([ResponseCode::ERROR_BUSINESS, '上课地点字段不存在']);
// }

@ -78,7 +78,7 @@ class CourseSignController extends BaseController
$clear = request('clear', 1);
$list = $this->model->with(['course.typeDetail', 'user' => function ($query) use ($all, $clear) {
if ($clear) {
$query->with(['courseSigns' => function ($q) {
$query->with(['company', 'courseSigns' => function ($q) {
$q->where('status', 1)->with('course');
}]);
}

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin;
use App\Helpers\ResponseCode;
use App\Jobs\CancelAppointMeet;
use App\Models\Admin;
use App\Models\Appointment;
use App\Models\AppointmentConfig;
@ -133,6 +134,8 @@ class OtherController extends CommonController
->where('start_date', '<=', $end_date)
->whereIn('type', $course_type_id)
->get();
// 被投企业数
$list['course_signs_invested'] = CourseSign::yhInvested($start_date, $end_date);
// 报名人数
$list['course_signs_total'] = CourseSign::courseSignsTotal($start_date, $end_date);
// 审核通过人数
@ -300,9 +303,9 @@ class OtherController extends CommonController
public function test()
{
$door = new DoorRepository();
$result = $door->getAllDoorInfo();
dd($result);
$model = Appointment::find(293);
// 取消预约
dispatch((new CancelAppointMeet($model, 'a0f75f36213a48f59ce860e679a77c5b')));
}

@ -3,6 +3,7 @@
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;
@ -101,12 +102,8 @@ class SupplyDemandController extends BaseController
}
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
if (isset($all['is_export']) && !empty($all['is_export'])) {
$list = $list->get()->toArray();
$export_fields = $all['export_fields'] ?? [];
// 导出文件名字
$tableName = $this->model->getTable();
$filename = (new CustomForm())->getTableComment($tableName);
return Excel::download(new BaseExport($export_fields, $list, $tableName), $filename . date('YmdHis') . '.xlsx');
$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);

@ -48,7 +48,7 @@ class TeacherController extends BaseController
public function index()
{
$all = request()->all();
$list = $this->model->with('courseContents.course', 'courseContents.directionDetail')->where(function ($query) use ($all) {
$list = $this->model->with('courseContents.course', 'courseContents')->where(function ($query) use ($all) {
if (isset($all['filter']) && !empty($all['filter'])) {
foreach ($all['filter'] as $condition) {
$key = $condition['key'] ?? null;

@ -180,6 +180,8 @@ class UserController extends BaseController
* @OA\Parameter(name="has_openid", in="query", @OA\Schema(type="string"), required=true, description="是否绑定小程序0否1是"),
* @OA\Parameter(name="year", in="query", @OA\Schema(type="string"), required=true, description="年份"),
* @OA\Parameter(name="is_black", in="query", @OA\Schema(type="string"), required=true, description="是否黑名单0否1是"),
* @OA\Parameter(name="is_yh_invested", in="query", @OA\Schema(type="string"), required=true, description="是否元和已投企业0否1是"),
* @OA\Parameter(name="company_tag", in="query", @OA\Schema(type="string"), required=true, description="企业标签"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
@ -195,12 +197,27 @@ class UserController extends BaseController
$end_date = $year . '-12-31';
$list = $this->model->with('appointments', 'companyIndustryDetail',
'companyPositionDetail', 'companyAreaDetail')
'companyPositionDetail', 'companyAreaDetail', 'company')
->with(['courseSigns' => function ($query) {
$query->with('course.typeDetail')->orderBy('fee_status', 'desc');
}])->withCount(['appointments' => function ($query) {
$query->whereIn('status', [0, 1]);
}]);
// 是否被投企业
if (isset($all['is_yh_invested'])) {
$list = $list->whereHas('company', function ($query) use ($all) {
if ($all['is_yh_invested'] == 1) {
$query->where('is_yh_invested', 1);
} else {
$query->where('is_yh_invested', 0);
}
});
}
if (isset($all['company_tag'])) {
$list = $list->whereHas('company', function ($query) use ($all) {
$query->where('company_tag', 'like', '%' . $all['company_tag'] . '%');
});
}
$list = $list->whereHas('courseSigns', function ($query) use ($all) {
if (isset($all['course_id'])) {
$query->where('course_id', $all['course_id']);

@ -17,6 +17,7 @@ use App\Models\CourseContentCheck;
use App\Models\CourseContentEvaluation;
use App\Models\CourseContentEvaluationForm;
use App\Models\CourseSign;
use App\Models\CourseType;
use App\Models\Notice;
use App\Models\Order;
use App\Models\User;
@ -798,11 +799,32 @@ class CourseController extends CommonController
}
});
if (isset($all['type']) && $all['type'] == 2) {
$list = $list->orderBy('letter')
->paginate(10);
$list = $list->orderBy('letter')->paginate(10);
} else {
$list = $list->orderBy('letter')->paginate(20);
}
// 获取当前用户参与报名
$userCourseSigns = CourseSign::where('user_id',$this->getUserId())->where('status', 1)->get();
// 获取当前用户允许的课程体系
$open_course_types = explode(',', $this->getUser()->open_course_types);
foreach ($list as $user) {
$user->open_mobile = false;
// 只对开放的课程体系和本班人员开放手机号
// 获取本班的课程
$courseIds = $user->courseSigns->where('status', 1)->pluck('course_id')->toArray();
// 判断当前用户和$user课程是否存在交集
if (count(array_intersect($courseIds, $userCourseSigns->pluck('course_id')->toArray())) > 0) {
$user->open_mobile = true;
continue;
}
// 获取用户的课程体系
$coursesTypeIds = Course::whereIn('id', $userCourseSigns->pluck('course_id'))->pluck('type')->toArray();
// 判断当前用户和$user课程体系是否存在交集
if (count(array_intersect($coursesTypeIds, $open_course_types)) > 0) {
$user->open_mobile = true;
}
}
$teacher = [];
if (isset($all['type']) && $all['type'] == 2) {
$course = Course::find($all['course_id']);

@ -11,6 +11,7 @@ use App\Models\AppointmentType;
use App\Models\Banner;
use App\Models\Company;
use App\Models\Config;
use App\Models\CourseType;
use App\Repositories\YuanheRepository;
use Illuminate\Support\Facades\Validator;
@ -40,7 +41,9 @@ class OtherController extends CommonController
})->where('show_front', 1)->get();
// 场地类型
$appointment_type = AppointmentType::get();
return $this->success(compact('config', 'appointment', 'appointment_type'));
// 获取开放手机号的课程体系
$course_types_open_mobile = CourseType::where('open_mobile', 1)->get();
return $this->success(compact('config', 'appointment', 'appointment_type', 'course_types_open_mobile'));
}
/**

@ -136,6 +136,7 @@ class SupplyDemandController extends CommonController
* @OA\Parameter(name="file_ids", in="query", @OA\Schema(type="string"), required=false, description="文件id数组"),
* @OA\Parameter(name="contact_name", 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\Parameter(name="tags", in="query", @OA\Schema(type="integer"), required=false, description="标签,多个英文逗号分隔"),
* @OA\Response(
* response="200",
* description="暂无"

@ -154,6 +154,7 @@ class UserController extends CommonController
* @OA\Parameter(name="idcard", in="query", @OA\Schema(type="string"), description="身份证号码"),
* @OA\Parameter(name="plate", in="query", @OA\Schema(type="string"), description="车牌号多个英文逗号分隔"),
* @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), description="人才类型"),
* @OA\Parameter(name="open_course_types", in="query", @OA\Schema(type="string"), description="开放手机号的课程体系多个英文逗号分隔"),
* @OA\Response(
* response=200,
* description="操作成功"
@ -171,7 +172,9 @@ class UserController extends CommonController
}
$model->password = Hash::make($all['password']);
}
if (isset($all['username']) && !empty($all['username'])) {
$all['name'] = $all['username'];
}
if (isset($all['name']) && !empty($all['name'])) {
$all['letter'] = strtoupper(Pinyin::abbr(mb_substr($all['name'], 0, 1))[0]);
}

@ -718,3 +718,31 @@ function getDates($start, $end)
}
return $temp; // 返回data型数据
}
/**
* 将JSON字符串或数组的键值对组合成"键:值,键:值"格式的字符串
*
* @param string|array $data 可以是JSON字符串或关联数组
* @return string 组合后的字符串
*/
function combineKeyValue($data)
{
// 如果输入是JSON字符串则解析为数组
if (is_string($data)) {
$data = json_decode($data, true);
}
// 验证是否为数组
if (!is_array($data)) {
return '';
}
// 拼接键值对
$parts = [];
foreach ($data as $key => $value) {
$parts[] = "{$value}";
}
// 用逗号连接
return implode(',', $parts);
}

@ -276,8 +276,8 @@ class Course extends SoftDeletesModel
$app = Factory::miniProgram($config);
$tmp = $app->app_code->get('packages/surveyFill/index?id=' . $id, [
// todo:: 版本切换
// 'env_version' => "release" // 正式版
'env_version' => "trial" // 体验版
'env_version' => "release" // 正式版
// 'env_version' => "trial" // 体验版
]);
$dir = dirname($path);
$fileSys->ensureDirectoryExists($dir, 0755, true);

@ -65,10 +65,10 @@ class CourseContent extends SoftDeletesModel
return $this->hasMany(CourseContentEvaluationAsk::class, 'course_content_id', 'id');
}
public function directionDetail()
{
return $this->hasOne(ParameterDetail::class, 'id', 'direction');
}
// public function directionDetail()
// {
// return $this->hasOne(ParameterDetail::class, 'id', 'direction');
// }
/**
* 获取课程详情小程序码

@ -112,5 +112,26 @@ class CourseSign extends SoftDeletesModel
return User::whereIn('id', $courseSignByType->pluck('user_id'))->distinct('mobile')->count();
}
/**
* 指定时间内的被投企业
*/
public static function yhInvested($start_date, $end_date, $status = null, $course_ids = null)
{
$courseSignByType = CourseSign::whereDate('created_at', '>=', $start_date)
->whereDate('created_at', '<=', $end_date)
->where(function ($query) use ($status, $course_ids) {
if (isset($status)) {
$query->where('status', $status);
}
if (isset($course_ids)) {
$query->whereIn('course_id', $course_ids);
}
})->whereNotIn('status', [4, 5])
->get();
return Company::whereHas('users', function ($query) use ($courseSignByType) {
$query->whereIn('id', $courseSignByType->pluck('user_id'));
})->count();
}
}

@ -24,6 +24,8 @@ class EmailRecordUser extends SoftDeletesModel
public static function template($template, $var_data)
{
foreach ($var_data as $key => $var) {
$key = trim($key);
$var = trim($var);
$template = str_replace('{' . $key . '}', $var, $template);
}
return $template;

@ -73,7 +73,8 @@ class User extends Authenticatable implements Auditable
'company_date',
'deleted_at',
'no',
'from'
'from',
'open_course_types'
];
protected $appends = ['is_vip_text', 'is_schoolmate_text', 'appointment_total', 'name'];

@ -85,48 +85,84 @@ class MeetRepository
*/
public function appointment($model, $appointmentConfig, &$out)
{
$startDateTime = new \DateTime($model->start_time);
$endDateTime = new \DateTime($model->end_time);
$meetOther = json_decode($appointmentConfig->room, true);
$url = $this->baseUrl . '/services/api/BookingService.aspx';
$header[] = 'Content-Type: application/json';
$allMeetIds = [];
$allResults = [];
$currentDate = clone $startDateTime;
while ($currentDate->format('Y-m-d') <= $endDateTime->format('Y-m-d')) {
$dayStart = clone $currentDate;
$dayStart->setTime(5, 0, 0);
$dayEnd = clone $currentDate;
$dayEnd->setTime(23, 0, 0);
if ($currentDate->format('Y-m-d') === $startDateTime->format('Y-m-d')) {
$dayStart = clone $startDateTime;
}
if ($currentDate->format('Y-m-d') === $endDateTime->format('Y-m-d')) {
$dayEnd = clone $endDateTime;
}
$params = [
'account' => $this->account,
'password' => md5($this->password),
'roomName' => $appointmentConfig->name,
'roomCode' => $meetOther['code'],
'roomAddress' => $meetOther['address'],
'beginTime' => $model->start_time,
'endTime' => $model->end_time,
'beginTime' => $dayStart->format('Y-m-d H:i:s'),
'endTime' => $dayEnd->format('Y-m-d H:i:s'),
'speaker' => $model->name,
'subject' => empty($model->content) ? '预约会议室' : $model->content,
'booker' => "{$model->name};{$model->mobile};",
'attendance' => "{$model->name};{$model->mobile};",
'signUrl' => ''
];
$result = [];
$finally = 0;
try {
$resultJson = httpCurl($url, 'GET', $params, $header);
$out = $resultJson;
$result = json_decode($resultJson, true);
if ($result['success']) {
$finally = 1;
$meetIds = explode(',', $model->meet_id);
array_push($meetIds, $result['data']);
$meetIds = array_filter($meetIds);
$model->meet_id = implode(',', $meetIds);
$model->save();
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约');
return true;
$allMeetIds[] = $result['data'];
$allResults[] = $result;
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约-' . $currentDate->format('Y-m-d'));
} else {
$out = $resultJson;
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约');
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约-' . $currentDate->format('Y-m-d'));
return false;
}
} catch (\Exception $e) {
$out = $e->getMessage();
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约');
ThirdAppointmentLog::add($model->id, 0, $model->user_id, $url, $params, $result, $finally, '会议室预约-' . $currentDate->format('Y-m-d'));
return false;
}
$currentDate->modify('+1 day');
}
if (!empty($allMeetIds)) {
$meetIds = explode(',', $model->meet_id);
$meetIds = array_merge($meetIds, $allMeetIds);
$meetIds = array_filter($meetIds);
$model->meet_id = implode(',', $meetIds);
$model->save();
$out = json_encode($allResults, JSON_UNESCAPED_UNICODE);
return true;
}
return false;
}
/**

@ -18,10 +18,9 @@ class YuanheRepository
public function __construct()
{
// 测试地址
$this->baseUrl = 'https://uat.oriza.com';
$this->customerId = '1947941625517604864';
$this->authKey = '59C8ED8584EE4BA7BC22FC63BE45C73D';
$this->baseUrl = env('YUANHE_BASE_URL');
$this->customerId = env('YUANHE_CUSTOMERID');
$this->authKey = env('YUANHE_AUTHKEY');
}

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('course_contents', function (Blueprint $table) {
// 课酬
$table->string('salary')->nullable()->comment('课酬');
// 导师
$table->string('tutor')->nullable()->comment('导师');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('teachers', function (Blueprint $table) {
//
});
}
};

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('course_types', function (Blueprint $table) {
// 是否开放手机号
$table->boolean('open_mobile')->default(false)->nullable()->comment('是否开放手机号');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('course_types', function (Blueprint $table) {
//
});
}
};

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('open_course_types')->nullable()->comment('开放手机号的课程体系');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('courses', function (Blueprint $table) {
// 学生编号前缀
$table->string('student_prefix')->nullable()->comment('学生编号前缀');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('courses', function (Blueprint $table) {
//
});
}
};

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('supply_demands', function (Blueprint $table) {
// 资金类型
$table->string('fund_type')->after('type')->default('')->comment('资金类型');
// 金额
$table->decimal('amount', 20, 2)->after('fund_type')->default(0.00)->comment('金额');
// 融资阶段
$table->string('fund_stage')->after('amount')->default('')->comment('融资阶段');
// 期望资金属性
$table->string('expect_fund_attr')->after('fund_stage')->default('')->comment('期望资金属性');
// 行业类型
$table->string('industry_type')->after('expect_fund_attr')->default('')->comment('行业类型');
// 主要产品
$table->string('product')->after('industry_type')->default('')->comment('主要产品');
// 简要描述
$table->string('desc')->after('product')->default('')->comment('简要描述');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('supply_demands', function (Blueprint $table) {
//
});
}
};

@ -1,96 +0,0 @@
### 供需发布模块数据结构与功能分析
#### 一、数据结构
- **表:`supply_demands`(供需主表)**
- 字段:`id`, `user_id`, `title`, `type`(1=供应,2=需求), `content`, `tag`, `wechat`, `mobile`, `email`, `status`(0待审核/1通过/2拒绝/3退回修改/4永久隐藏), `view_count`, `contact_count`, `expire_time`, `public_way`(布尔实际业务含义为1/2/3), `file_ids`(JSON), `contact_name`, `timestamps`, `deleted_at`
- 关系:
- `user`: 发布者(`hasOne User(id=user_id)`
- `keeps`: 收藏(`hasMany SupplyDemandKeep(supply_demand_id=id)`
- 虚拟属性:`files`(根据 `file_ids` 关联 `Upload` 列表)
- **表:`supply_demand_keeps`(收藏表)**
- 字段:`id`, `user_id`, `supply_demand_id`, `timestamps`, `deleted_at`
- 关系:
- `user`: 收藏者(`hasOne User(id=user_id)`
- `supplyDemand`: 被收藏的供需(`hasOne SupplyDemand(id=supply_demand_id)`
- **表:`dialogues`(会话表)**
- 字段:`id`, `user_id`, `to_user_id`, `supply_demand_id`, `last_content`, `last_datetime`, `timestamps`, `deleted_at`
- 关系:
- `user`: 会话发起方(`hasOne User(id=user_id)`
- `toUser`: 会话接收方(`hasOne User(id=to_user_id)`
- `supplyDemand`: 关联供需(`hasOne SupplyDemand(id=supply_demand_id)`
- **表:`messages`(消息表)**
- 字段:`id`, `dialogue_id`, `user_id`, `to_user_id`, `supply_demand_id`, `content`, `is_read`, `timestamps`, `deleted_at`
- 关系:
- `user`/`toUser`: 发送方/接收方(`hasOne User`
- `dialogue`: 所属会话(`hasOne Dialogue(id=dialogue_id)`
- `supplyDemand`: 关联供需(`hasOne SupplyDemand(id=supply_demand_id)`
- **表:`uploads`(附件表)**
- 字段:`id`, `belongs_type`, `belongs_id`, `original_name`, `folder`, `name`, `extension`, `size`, `creator_type`, `creator_id`, `timestamps`, `deleted_at`
- 用途:`supply_demands.file_ids` 存放附件 `id` 列表,模型通过 `files` 访问器取回 `Upload` 集合
说明:`public_way` 迁移中为 boolean但注释为 1/2/3 三种模式1直接公开/2私信后公开/3不公开。当前以 0/1 存储,若需完整三态应在后续迁移中改为 tinyInteger。
#### 二、功能说明(`SupplyDemandController`
- **列表 `index`**:按类型、状态、关键词、是否只看自己、有效期(有效/失效)筛选,分页排序;关联返回 `user` 基本信息。
- **详情 `detail`**:按 `id` 查询,返回 `user`,并自增 `view_count`;附带当前用户对该供需的已发私信次数。
- **保存 `save`**:新增或更新(新增时绑定当前用户并短信通知管理员),使用事务保存,支持 `file_ids`、`expire_time`、`contact_name` 等字段。
- **删除 `destroy`**:按 `id` 软删除。
- **发私信 `sendMessage`**
- 若带 `supply_demand_id` 则自增浏览量;
- 无会话则创建会话;
- 限流:每天发送条数不超过配置 `message_limit`
- 反骚扰:自己连续发送后需等待对方回复;
- 保存消息并更新会话最后内容与时间。
- **消息列表 `messageList`**:按 `to_user_id` 定位当前和对方的会话,分页返回消息(含双方用户信息)。
- **会话列表 `dialogues`**:返回与当前用户相关的会话(发起或接收),含双方用户与关联供需。
- **收藏相关**
- `keepIndex`:我的收藏列表;
- `keepSupplyDemand`:收藏,去重创建;
- `unKeepSupplyDemand`:取消收藏。
#### 三、核心业务要点
- 审核机制:多状态闭环(待审/通过/拒绝/退回/隐藏)。
- 私信策略:限流 + 反骚扰(需对方回复后再发)。
- 有效期:支持有效/失效筛选。
- 公开模式当前存储为布尔0/1业务含义为三态后续建议迁移调整。
- 数据统计:浏览数 `view_count`、联系数 `contact_count`(可按消息交互推导)。
- 附件:`file_ids` JSON + `files` 访问器联表读取。
#### 四、测试数据生成目标
`supply_demands` 为起点,为每条主记录自动生成:
- 合理的 `uploads` 附件0~3 个),`file_ids` 同步写入;
- 真实的会话 `dialogues`0~2 个),双方用户随机;
- 合法的消息序列 `messages`1~5 条),严格交替往来确保不违反“需对方回复”约束;
- 合理的收藏 `supply_demand_keeps`0~5 条,去重);
- 统计字段:`view_count` ≥ 消息条数,`contact_count` 依据消息往来推导。
#### 五、两种生成方式对比
- **方式A数据库填充Seeder**
- 优点:
- 一次性执行、可集成到 CI 或初始化流程;
- 可与 `DatabaseSeeder` 串联;
- 便于多环境批量重置数据。
- 缺点:
- 运行参数(数量、用户规模)固定或需改代码;
- 无交互,临时性需求需改代码或 env。
- **方式BArtisan 命令Console Command**
- 优点:
- 支持运行参数(如 `--count`、`--users`),灵活生成规模;
- 可多次按需执行,便于演示或局部补数;
- 缺点:
- 需要单独维护命令逻辑;
- 不会被自动纳入 `db:seed` 的全局流程。
推荐:开发/演示期使用命令B灵活试验集成测试或初始化环境使用 SeederA
Loading…
Cancel
Save