feat: 【工作报告】功能
This commit is contained in:
parent
3602acd187
commit
d48ed18102
379
app/Http/Controllers/Api/ReportController.php
Executable file
379
app/Http/Controllers/Api/ReportController.php
Executable file
@ -0,0 +1,379 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\ProjectTask;
|
||||
use App\Models\Report;
|
||||
use App\Models\ReportReceive;
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* @apiDefine report
|
||||
*
|
||||
* 汇报
|
||||
*/
|
||||
class ReportController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @api {get} api/report/my 01. 我发送的汇报
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName my
|
||||
*
|
||||
* @apiParam {Number} [user] 会员ID
|
||||
* @apiParam {String} [type] 汇报类型,weekly:周报,daily:日报
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function my(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
// 搜索当前用户
|
||||
$builder = Report::query()->whereUserid($user->userid);
|
||||
$type = trim(Request::input('type'));
|
||||
$createAt = Request::input('created_at');
|
||||
in_array($type, [Report::WEEKLY, Report::DAILY]) && $builder->whereType($type);
|
||||
$whereArray = [];
|
||||
if (is_array($createAt)) {
|
||||
if ($createAt[0] > 0) $whereArray[] = ['created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($createAt[0]))];
|
||||
if ($createAt[1] > 0) $whereArray[] = ['created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($createAt[1]))];
|
||||
}
|
||||
$list = $builder->where($whereArray)->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
if ($list->items()) {
|
||||
foreach ($list->items() as $item) {
|
||||
$item->receivesUser;
|
||||
$item->receives = empty($item->receivesUser) ? [] : array_column($item->receivesUser->toArray(), "userid");
|
||||
}
|
||||
}
|
||||
|
||||
return Base::retSuccess('success', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 我接收的汇报
|
||||
* @return array
|
||||
*/
|
||||
public function receive(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$builder = Report::query();
|
||||
$builder->whereHas("receivesUser", function ($query) use ($user) {
|
||||
$query->where("report_receives.userid", $user->userid);
|
||||
});
|
||||
$type = trim(Request::input('type'));
|
||||
$createAt = Request::input('created_at');
|
||||
$username = trim(Request::input('username', ''));
|
||||
$builder->whereHas('sendUser', function ($query) use ($username) {
|
||||
if (!empty($username)) {
|
||||
$query->where('users.email', 'LIKE', '%' . $username . '%');
|
||||
}
|
||||
});
|
||||
in_array($type, [Report::WEEKLY, Report::DAILY]) && $builder->whereType($type);
|
||||
$whereArray = [];
|
||||
if (is_array($createAt)) {
|
||||
if ($createAt[0] > 0) $whereArray[] = ['created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($createAt[0]))];
|
||||
if ($createAt[1] > 0) $whereArray[] = ['created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($createAt[1]))];
|
||||
}
|
||||
$list = $builder->where($whereArray)->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
if ($list->items()) {
|
||||
foreach ($list->items() as $item) {
|
||||
$item["receive_time"] = ReportReceive::query()->whereRid($item["id"])->whereUserid($user->userid)->value("receive_time");
|
||||
$item->receivesUser;
|
||||
$item->receives = empty($item->receivesUser) ? [] : array_column($item->receivesUser->toArray(), "userid");
|
||||
}
|
||||
}
|
||||
return Base::retSuccess('success', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存并发送工作汇报
|
||||
* @return array
|
||||
*/
|
||||
public function store(): array
|
||||
{
|
||||
$input = [
|
||||
"id" => Base::getPostValue("id", 0),
|
||||
"title" => Base::getPostValue("title"),
|
||||
"type" => Base::getPostValue("type"),
|
||||
"content" => Base::getPostValue("content"),
|
||||
"receive" => Base::getPostValue("receive"),
|
||||
// 以当前日期为基础的周期偏移量。例如选择了上一周那么就是 -1,上一天同理。
|
||||
"offset" => Base::getPostValue("offset", 0),
|
||||
];
|
||||
$validator = Validator::make($input, [
|
||||
'id' => 'numeric',
|
||||
'title' => 'required',
|
||||
'type' => ['required', Rule::in([Report::WEEKLY, Report::DAILY])],
|
||||
'content' => 'required',
|
||||
'receive' => 'required',
|
||||
'offset' => ['numeric', 'max:0'],
|
||||
], [
|
||||
'id.numeric' => 'ID只能是数字',
|
||||
'title.required' => '请填写标题',
|
||||
'type.required' => '请选择汇报类型',
|
||||
'type.in' => '汇报类型错误',
|
||||
'content.required' => '请填写汇报内容',
|
||||
'receive.required' => '请选择接收人',
|
||||
'offset.numeric' => '工作汇报周期格式错误,只能是数字',
|
||||
'offset.max' => '只能提交当天/本周或者之前的的工作汇报',
|
||||
]);
|
||||
if ($validator->fails())
|
||||
return Base::retError($validator->errors()->first());
|
||||
|
||||
$user = User::auth();
|
||||
// 接收人
|
||||
if ( is_array($input["receive"]) ) {
|
||||
// 删除当前登录人
|
||||
$input["receive"] = array_diff($input["receive"], [$user->userid]);
|
||||
|
||||
// 查询用户是否存在
|
||||
if ( count($input["receive"]) !== User::whereIn("userid", $input["receive"])->count() )
|
||||
return Base::retError("用户不存在");
|
||||
|
||||
foreach ($input["receive"] as $userid) {
|
||||
$input["receive_content"][] = [
|
||||
"receive_time" => Carbon::now()->toDateTimeString(),
|
||||
"userid" => $userid,
|
||||
"read" => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 在事务中运行
|
||||
Report::transaction( function () use ($input, $user) {
|
||||
$id = $input["id"];
|
||||
if ($id) {
|
||||
// 编辑
|
||||
$report = Report::getOne($id);
|
||||
$report->updateInstance([
|
||||
"title" => $input["title"],
|
||||
"type" => $input["type"],
|
||||
"content" => htmlspecialchars($input["content"]),
|
||||
]);
|
||||
} else {
|
||||
// 生成唯一标识
|
||||
$sign = Report::generateSign($input["type"], $input["offset"]);
|
||||
// 检查唯一标识是否存在
|
||||
if (empty($input["id"])) {
|
||||
if (Report::query()->whereSign($sign)->count() > 0)
|
||||
throw new ApiException("请勿重复提交工作汇报");
|
||||
}
|
||||
$report = Report::createInstance([
|
||||
"title" => $input["title"],
|
||||
"type" => $input["type"],
|
||||
"content" => htmlspecialchars($input["content"]),
|
||||
"userid" => $user->userid,
|
||||
"sign" => $sign,
|
||||
]);
|
||||
}
|
||||
|
||||
$report->save();
|
||||
if (!empty($input["receive_content"])) {
|
||||
// 删除关联
|
||||
$report->Receives()->delete();
|
||||
// 保存接收人
|
||||
$report->Receives()->createMany($input["receive_content"]);
|
||||
}
|
||||
|
||||
} );
|
||||
return Base::retSuccess('success');
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成汇报模板
|
||||
* @return array
|
||||
*/
|
||||
public function template(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$type = trim( Request::input("type") );
|
||||
$offset = abs( intval( Request::input("offset", 0) ) );
|
||||
$now_dt = trim( Request::input("date") ) ? Carbon::parse( Request::input("date") ) : Carbon::now();
|
||||
// 获取开始时间
|
||||
if ($type === Report::DAILY) {
|
||||
$start_time = Carbon::today();
|
||||
if ( $offset > 0 ) {
|
||||
// 将当前时间调整为偏移量当天结束
|
||||
$now_dt->subDays( $offset )->endOfDay();
|
||||
// 开始时间偏移量计算
|
||||
$start_time->subDays( $offset );
|
||||
}
|
||||
$end_time = Carbon::instance($start_time)->endOfDay();
|
||||
} else {
|
||||
$start_time = Carbon::now();
|
||||
if ( $offset > 0 ) {
|
||||
// 将当前时间调整为偏移量当周结束
|
||||
$now_dt->subWeeks( $offset )->endOfDay();
|
||||
// 开始时间偏移量计算
|
||||
$start_time->subWeeks( $offset );
|
||||
}
|
||||
$start_time->startOfWeek();
|
||||
$end_time = Carbon::instance($start_time)->endOfWeek();
|
||||
}
|
||||
// 生成唯一标识
|
||||
$sign = Report::generateSign($type, 0, Carbon::instance($start_time));
|
||||
$one = Report::query()->whereSign($sign)->first();
|
||||
// 如果已经提交了相关汇报
|
||||
if ($one) {
|
||||
return Base::retSuccess('success', [
|
||||
"content" => $one->content,
|
||||
"title" => $one->title,
|
||||
"id" => $one->id,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// 已完成的任务
|
||||
$completeContent = "";
|
||||
$complete_task = ProjectTask::query()
|
||||
->whereNotNull("complete_at")
|
||||
->whereBetween("complete_at", [$start_time->toDateTimeString(), $end_time->toDateTimeString()])
|
||||
->whereHas("taskUser", function ($query) use ($user) {
|
||||
$query->where("userid", $user->userid);
|
||||
})
|
||||
->orderByDesc("id")
|
||||
->get();
|
||||
if ($complete_task->isNotEmpty()) {
|
||||
foreach ($complete_task as $task) {
|
||||
$complete_at = Carbon::parse($task->complete_at);
|
||||
$pre = $type == Report::WEEKLY ? ('<span>[' . Base::Lang('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . ']</span> ') : '';
|
||||
$completeContent .= '<li>' . $pre . $task->name . '</li>';
|
||||
}
|
||||
} else {
|
||||
$completeContent = '<li> </li>';
|
||||
}
|
||||
|
||||
// 未完成的任务
|
||||
$unfinishedContent = "";
|
||||
$unfinished_task = ProjectTask::query()
|
||||
->whereNull("complete_at")
|
||||
->whereNotNull("start_at")
|
||||
->where("end_at", "<", $end_time->toDateTimeString())
|
||||
->whereHas("taskUser", function ($query) use ($user) {
|
||||
$query->where("userid", $user->userid);
|
||||
})
|
||||
->orderByDesc("id")
|
||||
->get();
|
||||
if ($unfinished_task->isNotEmpty()) {
|
||||
foreach ($unfinished_task as $task) {
|
||||
empty($task->end_at) || $end_at = Carbon::parse($task->end_at);
|
||||
$pre = ( !empty( $end_at ) && $end_at->lt($now_dt) ) ? '<span style="color:#ff0000;">[' . Base::Lang('超期') . ']</span> ' : '';
|
||||
$unfinishedContent .= '<li>' . $pre . $task->name . '</li>';
|
||||
}
|
||||
} else {
|
||||
$unfinishedContent = '<li> </li>';
|
||||
}
|
||||
// 生成标题
|
||||
if ( $type === Report::WEEKLY ) {
|
||||
$title = $user->nickname . "的周报[" . $start_time->format("m/d") . "-" . $end_time->format("m/d") . "]";
|
||||
$title .= "[" . $start_time->month . "月第" . $start_time->weekOfMonth . "周]";
|
||||
} else {
|
||||
$title = $user->nickname . "的日报[" . $start_time->format("Y/m/d") . "]";
|
||||
}
|
||||
return Base::retSuccess('success', [
|
||||
"time" => $start_time->toDateTimeString(),
|
||||
"complete_task" => $complete_task,
|
||||
"unfinished_task" => $unfinished_task,
|
||||
"content" => '<h2>' . Base::Lang('已完成工作') . '</h2><ol>' .
|
||||
$completeContent . '</ol><h2>' .
|
||||
Base::Lang('未完成的工作') . '</h2><ol>' .
|
||||
$unfinishedContent . '</ol>',
|
||||
"title" => $title,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function detail(): array
|
||||
{
|
||||
$id = intval( trim( Request::input("id") ) );
|
||||
if (empty( $id ))
|
||||
return Base::retError("缺少ID参数");
|
||||
|
||||
$one = Report::getOne($id);
|
||||
$one["type_val"] = $one->getRawOriginal("type");
|
||||
|
||||
$user = User::auth();
|
||||
// 标记为已读
|
||||
if ( !empty( $one->receivesUser ) ) {
|
||||
foreach ($one->receivesUser as $item) {
|
||||
if ($item->userid === $user->userid && $item->pivot->read === 0) {
|
||||
$one->receivesUser()->updateExistingPivot($user->userid, [
|
||||
"read" => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Base::retSuccess("success", $one);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一次提交的接收人
|
||||
* @return array
|
||||
*/
|
||||
public function last_submitter(): array
|
||||
{
|
||||
$one = Report::getLastOne();
|
||||
return Base::retSuccess("success", empty( $one["receives"] ) ? [] : $one["receives"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未读
|
||||
* @return array
|
||||
*/
|
||||
public function unread(): array
|
||||
{
|
||||
$userid = intval( trim( Request::input("userid") ) );
|
||||
$user = empty($userid) ? User::auth() : User::find($userid);
|
||||
|
||||
$data = Report::whereHas("Receives", function (Builder $query) use ($user) {
|
||||
$query->where("userid", $user->userid)->where("read", 0);
|
||||
})->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
return Base::retSuccess("success", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记汇报已读,可批量
|
||||
* @return array
|
||||
*/
|
||||
public function read(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$ids = Request::input("ids");
|
||||
if ( !is_array($ids) && !is_string($ids) ) {
|
||||
return Base::retError("请传入正确的工作汇报Id");
|
||||
}
|
||||
|
||||
if ( is_string($ids) ) {
|
||||
$ids = explode(",", $ids);
|
||||
}
|
||||
|
||||
$data = Report::with(["receivesUser" => function (BelongsToMany $query) use ($user) {
|
||||
$query->where("report_receives.userid", $user->userid)->where("read", 0);
|
||||
}])->whereIn("id", $ids)->get();
|
||||
|
||||
if ( $data->isNotEmpty() ) {
|
||||
foreach ($data as $item) {
|
||||
(!empty($item->receivesUser) && $item->receivesUser->isNotEmpty()) && $item->receivesUser()->updateExistingPivot($user->userid, [
|
||||
"read" => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
return Base::retSuccess("success", $data);
|
||||
}
|
||||
}
|
@ -44,5 +44,8 @@ class VerifyCsrfToken extends Middleware
|
||||
|
||||
// 保存文件内容(上传)
|
||||
'api/file/content/upload/',
|
||||
|
||||
// 保存汇报
|
||||
'api/report/store/',
|
||||
];
|
||||
}
|
||||
|
156
app/Models/Report.php
Normal file
156
app/Models/Report.php
Normal file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\Traits\Creator;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
/**
|
||||
* App\Models\Report
|
||||
*
|
||||
* @property int $id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property string $title 标题
|
||||
* @property string $type 汇报类型
|
||||
* @property int $userid
|
||||
* @property string|null $content
|
||||
* @method static Builder|Report newModelQuery()
|
||||
* @method static Builder|Report newQuery()
|
||||
* @method static Builder|Report query()
|
||||
* @method static Builder|Report whereContent($value)
|
||||
* @method static Builder|Report whereCreatedAt($value)
|
||||
* @method static Builder|Report whereId($value)
|
||||
* @method static Builder|Report whereTitle($value)
|
||||
* @method static Builder|Report whereType($value)
|
||||
* @method static Builder|Report whereUpdatedAt($value)
|
||||
* @method static Builder|Report whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
* @property string $sign 汇报唯一标识
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ReportReceive[] $Receives
|
||||
* @property-read int|null $receives_count
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\User[] $receivesUser
|
||||
* @property-read int|null $receives_user_count
|
||||
* @method static Builder|Report whereSign($value)
|
||||
*/
|
||||
class Report extends AbstractModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
const WEEKLY = "weekly";
|
||||
const DAILY = "daily";
|
||||
|
||||
protected $fillable = [
|
||||
"title",
|
||||
"type",
|
||||
"userid",
|
||||
"content",
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'receives',
|
||||
];
|
||||
|
||||
public function Receives(): HasMany
|
||||
{
|
||||
return $this->hasMany(ReportReceive::class, "rid");
|
||||
}
|
||||
|
||||
public function receivesUser(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, ReportReceive::class, "rid", "userid")
|
||||
->withPivot("receive_time", "read");
|
||||
}
|
||||
|
||||
public function sendUser()
|
||||
{
|
||||
return $this->hasOne(User::class, "userid", "userid");
|
||||
}
|
||||
|
||||
public function getTypeAttribute($value): string
|
||||
{
|
||||
return match ($value) {
|
||||
Report::WEEKLY => "周报",
|
||||
Report::DAILY => "日报",
|
||||
default => "",
|
||||
};
|
||||
}
|
||||
|
||||
public function getContentAttribute($value): string
|
||||
{
|
||||
return htmlspecialchars_decode($value);
|
||||
}
|
||||
|
||||
public function getReceivesAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['receives'])) {
|
||||
$this->appendattrs['receives'] = empty( $this->receivesUser ) ? [] : array_column($this->receivesUser->toArray(), "userid");
|
||||
}
|
||||
return $this->appendattrs['receives'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条记录
|
||||
* @param $id
|
||||
* @param User|null $user
|
||||
* @return Report|Builder|Model|object|null
|
||||
* @throw ApiException
|
||||
*/
|
||||
public static function getOne($id, User $user = null)
|
||||
{
|
||||
$user === null && $user = User::auth();
|
||||
$one = self::whereUserid($user->userid)->whereId($id)->first();
|
||||
if ( empty($one) )
|
||||
throw new ApiException("记录不存在");
|
||||
return $one;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一条提交记录
|
||||
* @param User|null $user
|
||||
* @return Builder|Model|\Illuminate\Database\Query\Builder|object
|
||||
*/
|
||||
public static function getLastOne(User $user = null)
|
||||
{
|
||||
$user === null && $user = User::auth();
|
||||
$one = self::whereUserid($user->userid)->orderByDesc("created_at")->first();
|
||||
if ( empty($one) )
|
||||
throw new ApiException("记录不存在");
|
||||
return $one;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一标识
|
||||
* @param $type
|
||||
* @param $offset
|
||||
* @param Carbon|null $time
|
||||
* @return string
|
||||
*/
|
||||
public static function generateSign($type, $offset, Carbon $time = null): string
|
||||
{
|
||||
$user = User::auth();
|
||||
$now_dt = $time === null ? Carbon::now() : $time;
|
||||
$time_s = match ($type) {
|
||||
Report::WEEKLY => function() use ($now_dt, $offset) {
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subWeeks( abs( $offset ) );
|
||||
$now_dt->startOfWeek(); // 设置为当周第一天
|
||||
return $now_dt->year . $now_dt->weekOfYear . $now_dt->month . $now_dt->weekOfMonth;
|
||||
},
|
||||
Report::DAILY => function() use ($now_dt, $offset) {
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subDays( abs( $offset ) );
|
||||
return $now_dt->year . $now_dt->dayOfYear . $now_dt->month . $now_dt->daysInMonth;
|
||||
},
|
||||
default => "",
|
||||
};
|
||||
return md5( $user->userid . ( is_callable($time_s) ? $time_s() : "" ) . $type );
|
||||
}
|
||||
}
|
39
app/Models/ReportReceive.php
Normal file
39
app/Models/ReportReceive.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* App\Models\ReportReceive
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $rid
|
||||
* @property string|null $receive_time 接收时间
|
||||
* @property int $userid 接收人
|
||||
* @property int $read 是否已读
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRead($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereReceiveTime($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ReportReceive extends AbstractModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
// 关闭时间戳自动写入
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
"rid",
|
||||
"receive_time",
|
||||
"userid",
|
||||
"read",
|
||||
];
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateReportsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( Schema::hasTable('reports') )
|
||||
return;
|
||||
|
||||
Schema::create('reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamps();
|
||||
$table->string("title")->default("")->comment("标题");
|
||||
$table->enum("type", ["weekly", "daily"])->default("daily")->comment("汇报类型");
|
||||
$table->unsignedBigInteger("userid")->default(0);
|
||||
$table->longText("content")->nullable();
|
||||
$table->index(["userid", "created_at"], "default");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('reports');
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateReportReceivesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( Schema::hasTable('report_receives') )
|
||||
return;
|
||||
|
||||
Schema::create('report_receives', function (Blueprint $table) {
|
||||
$table->bigIncrements("id");
|
||||
$table->unsignedInteger("rid")->default(0);
|
||||
$table->timestamp("receive_time")->nullable()->comment("接收时间");
|
||||
$table->unsignedBigInteger("userid")->default(0)->comment("接收人");
|
||||
$table->unsignedTinyInteger("read")->default(0)->comment("是否已读");
|
||||
$table->index(["userid", "receive_time"], "default");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('report_receives');
|
||||
}
|
||||
}
|
32
database/migrations/2022_01_04_111739_add_report_sign.php
Normal file
32
database/migrations/2022_01_04_111739_add_report_sign.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddReportSign extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('reports', function (Blueprint $table) {
|
||||
$table->string("sign")->default("")->comment("汇报唯一标识");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('reports', function (Blueprint $table) {
|
||||
$table->dropColumn("sign");
|
||||
});
|
||||
}
|
||||
}
|
@ -21,7 +21,10 @@
|
||||
v-for="(item, key) in menu"
|
||||
:key="key"
|
||||
:divided="!!item.divided"
|
||||
:name="item.path">{{$L(item.name)}}</DropdownItem>
|
||||
:name="item.path">
|
||||
{{$L(item.name)}}
|
||||
<Badge v-if="item.path === 'workReport'" :count="reportUnreadNumber"/>
|
||||
</DropdownItem>
|
||||
<Dropdown placement="right-start" @on-click="setLanguage">
|
||||
<DropdownItem divided>
|
||||
<div class="manage-menu-language">
|
||||
@ -160,6 +163,14 @@
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!--工作报告-->
|
||||
<DrawerOverlay
|
||||
v-model="workReportShow"
|
||||
placement="right"
|
||||
:size="900">
|
||||
<Report v-if="workReportShow" @read="reportUnread" />
|
||||
</DrawerOverlay>
|
||||
|
||||
<!--查看所有团队-->
|
||||
<DrawerOverlay
|
||||
v-model="allUserShow"
|
||||
@ -206,11 +217,13 @@ import ProjectManagement from "./manage/components/ProjectManagement";
|
||||
import DrawerOverlay from "../components/DrawerOverlay";
|
||||
import DragBallComponent from "../components/DragBallComponent";
|
||||
import TaskAdd from "./manage/components/TaskAdd";
|
||||
import Report from "./manage/components/Report";
|
||||
import {Store} from "le5le-store";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TaskAdd,
|
||||
Report,
|
||||
DragBallComponent, DrawerOverlay, ProjectManagement, TeamManagement, ProjectArchived, TaskDetail},
|
||||
data() {
|
||||
return {
|
||||
@ -242,6 +255,7 @@ export default {
|
||||
show768Menu: false,
|
||||
innerHeight: window.innerHeight,
|
||||
|
||||
workReportShow: false,
|
||||
allUserShow: false,
|
||||
allProjectShow: false,
|
||||
archivedProjectShow: false,
|
||||
@ -249,6 +263,7 @@ export default {
|
||||
natificationHidden: false,
|
||||
natificationReady: false,
|
||||
notificationClass: null,
|
||||
reportUnreadNumber: 0,
|
||||
}
|
||||
},
|
||||
|
||||
@ -273,6 +288,9 @@ export default {
|
||||
if (this.$Electron) {
|
||||
this.$Electron.ipcRenderer.send('setDockBadge', 0);
|
||||
}
|
||||
|
||||
// 工作汇报未读标记
|
||||
this.reportUnread();
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
@ -334,7 +352,8 @@ export default {
|
||||
{path: 'clearCache', name: '清除缓存'},
|
||||
{path: 'system', name: '系统设置', divided: true},
|
||||
{path: 'priority', name: '任务等级'},
|
||||
{path: 'allUser', name: '团队管理', divided: true},
|
||||
{path: 'workReport', name: '工作报告', divided: true},
|
||||
{path: 'allUser', name: '团队管理'},
|
||||
{path: 'allProject', name: '所有项目'},
|
||||
{path: 'archivedProject', name: '已归档的项目'}
|
||||
]
|
||||
@ -343,7 +362,8 @@ export default {
|
||||
{path: 'personal', name: '个人设置'},
|
||||
{path: 'password', name: '密码设置'},
|
||||
{path: 'clearCache', name: '清除缓存'},
|
||||
{path: 'archivedProject', name: '已归档的项目', divided: true}
|
||||
{path: 'workReport', name: '工作报告', divided: true},
|
||||
{path: 'archivedProject', name: '已归档的项目'}
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -474,6 +494,9 @@ export default {
|
||||
case 'archivedProject':
|
||||
this.archivedProjectShow = true;
|
||||
return;
|
||||
case 'workReport':
|
||||
this.workReportShow = true;
|
||||
return;
|
||||
case 'clearCache':
|
||||
this.$store.dispatch("handleClearCache", null).then(() => {
|
||||
$A.setStorage("clearCache", $A.randomString(6))
|
||||
@ -683,6 +706,17 @@ export default {
|
||||
this.natificationHidden = !!document[hiddenProperty]
|
||||
}
|
||||
document.addEventListener(visibilityChangeEvent, visibilityChangeListener);
|
||||
},
|
||||
|
||||
reportUnread() {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/unread',
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.reportUnreadNumber = data.total ? data.total : 0;
|
||||
// msg 结果描述
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
resources/assets/js/pages/manage/components/Report.vue
Normal file
65
resources/assets/js/pages/manage/components/Report.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="report">
|
||||
<Tabs v-model="reportTabs">
|
||||
<TabPane label="填写" name="edit" icon="md-create">
|
||||
<ReportEdit :id="reportId" @saveSuccess="saveSuccess">填写</ReportEdit>
|
||||
</TabPane>
|
||||
<TabPane label="我的汇报" name="my" icon="ios-paper-plane-outline">
|
||||
<ReportMy v-if="reportTabs === 'my'" @detail="showDetail" @edit="editReport">我的汇报</ReportMy>
|
||||
</TabPane>
|
||||
<TabPane label="收到的汇报" name="receive" icon="ios-paper-outline">
|
||||
<ReportReceive v-if="reportTabs === 'receive'" @detail="showDetail">收到的汇报</ReportReceive>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
<Drawer v-model="showDetailDrawer" width="900px" :closable="false">
|
||||
<ReportDetail :data="detailData" @closeDrawer="closeDrawer"/>
|
||||
</Drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ReportEdit from "./ReportEdit"
|
||||
import ReportMy from "./ReportMy"
|
||||
import ReportReceive from "./ReportReceive"
|
||||
import ReportDetail from "./ReportDetail"
|
||||
|
||||
export default {
|
||||
name: "Report",
|
||||
components: {
|
||||
ReportEdit, ReportMy, ReportReceive,ReportDetail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reportTabs: "my",
|
||||
showDetailDrawer: false,
|
||||
detailData: {},
|
||||
reportId: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeDrawer(){
|
||||
this.showDetailDrawer = false
|
||||
},
|
||||
showDetail(row) {
|
||||
this.showDetailDrawer = true;
|
||||
this.detailData = row;
|
||||
//1.5秒后执行
|
||||
setTimeout(() => {
|
||||
this.$emit("read");
|
||||
}, 1500);
|
||||
},
|
||||
editReport(id) {
|
||||
this.reportId = id;
|
||||
this.reportTabs = "edit";
|
||||
},
|
||||
saveSuccess() {
|
||||
this.reportId = 0;
|
||||
this.reportTabs = "my";
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
87
resources/assets/js/pages/manage/components/ReportDetail.vue
Normal file
87
resources/assets/js/pages/manage/components/ReportDetail.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
|
||||
<div class="report-detail">
|
||||
|
||||
<p class="report-title"><Icon type="ios-arrow-back" class="report-title-icon" @click="closeDrawer"/> {{ data.title }}</p>
|
||||
<Divider />
|
||||
<div class="report-profile">
|
||||
<Row>
|
||||
<Col span="2">
|
||||
<div class="report-submitter"><p>{{ $L('汇报人') }} </p></div>
|
||||
</Col>
|
||||
<Col span="6">
|
||||
<div class="report-submitter">
|
||||
<UserAvatar :userid="data.userid" :size="28"/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="2">
|
||||
<div class="report-submitter"> <p>{{ $L('提交时间') }}</p></div>
|
||||
</Col>
|
||||
<Col span="6">
|
||||
<div class="report-submitter">
|
||||
<div>{{ data.created_at }}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="2">
|
||||
<div class="report-submitter"><p>{{ $L('汇报对象') }}</p></div>
|
||||
</Col>
|
||||
<Col span="6">
|
||||
<div class="report-submitter">
|
||||
<UserAvatar v-for="item in data.receives" :key="item" :userid="item" :size="28"/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row class="report-main">
|
||||
<Col span="2">
|
||||
<div class="report-submitter"><p>{{ $L('汇报内容') }}</p></div>
|
||||
</Col>
|
||||
<Col span="22">
|
||||
<div class="report-content" v-html="data.content">
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ReportDetail",
|
||||
props: {
|
||||
data: {
|
||||
default: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.data.id > 0) this.sendRead();
|
||||
console.log(this.data)
|
||||
},
|
||||
watch: {
|
||||
data() {
|
||||
if (this.data.id > 0) this.sendRead();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sendRead() {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/read',
|
||||
data: {ids: [this.data.id]},
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
});
|
||||
},
|
||||
closeDrawer(){
|
||||
this.$emit('closeDrawer')
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
236
resources/assets/js/pages/manage/components/ReportEdit.vue
Normal file
236
resources/assets/js/pages/manage/components/ReportEdit.vue
Normal file
@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<Form class="report-box" label-position="top" @submit.native.prevent>
|
||||
<Row class="report-row report-row-header" >
|
||||
<Col span="2"><p class="report-titles">{{ $L("汇报类型") }}</p></Col>
|
||||
<Col span="6">
|
||||
<RadioGroup type="button" button-style="solid" v-model="reportData.type" @on-change="typeChange" class="report-radiogroup">
|
||||
<Radio label="weekly">{{ $L("周报") }}</Radio>
|
||||
<Radio label="daily">{{ $L("日报") }}</Radio>
|
||||
</RadioGroup>
|
||||
</Col>
|
||||
<Col span="6">
|
||||
<ButtonGroup class="report-buttongroup">
|
||||
<Tooltip class="report-poptip" trigger="hover" :content="prevCycleText" placement="bottom">
|
||||
<Button type="primary" @click="prevCycle">
|
||||
<Icon type="ios-arrow-back" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<div class="report-buttongroup-shu"></div>
|
||||
<Tooltip class="report-poptip" trigger="hover" :content="nextCycleText" placement="bottom">
|
||||
<Button type="primary" @click="nextCycle" :disabled="reportData.offset >= 0">
|
||||
<Icon type="ios-arrow-forward" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row class="report-row report-row-header">
|
||||
<Col span="2"><p class="report-titles">{{ $L("汇报名称") }}</p></Col>
|
||||
<Col span="22">
|
||||
<Input v-model="reportData.title" disabled placeholder=""></Input>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row class="report-row report-row-header">
|
||||
<Col span="2"><p class="report-titles">{{ $L("汇报对象") }}</p></Col>
|
||||
<Col span="16">
|
||||
<UserInput
|
||||
v-if="userInputShow"
|
||||
v-model="reportData.receive"
|
||||
:placeholder="$L('选择接收人')" />
|
||||
</Col>
|
||||
<Col span="6"><a class="report-row-a" href="javascript:void(0);" @click="getLastSubmitter"><Icon class="report-row-a-icon" type="ios-share-outline" />{{ $L("使用上一次提交的接收人") }}</a></Col>
|
||||
</Row>
|
||||
<Row class="report-row report-row-content">
|
||||
<Col span="2"><p class="report-titles">{{ $L("汇报内容") }}</p></Col>
|
||||
<Col span="22">
|
||||
<FormItem>
|
||||
<TEditor v-model="reportData.content" height="550px"/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row class="report-row report-row-foot">
|
||||
<Col span="2"></Col>
|
||||
<Col span="4">
|
||||
<FormItem>
|
||||
<Button type="primary" @click="handleSubmit" class="report-bottom">提交</Button>
|
||||
<!-- <Button type="primary" @click="prevCycle">{{ prevCycleText }}</Button>-->
|
||||
<!-- <Button type="primary" @click="nextCycle" :disabled="reportData.offset >= 0">{{ nextCycleText }}</Button>-->
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="4">
|
||||
<FormItem>
|
||||
<Button type="primary" class="report-bottom-save">保存</Button>
|
||||
<!-- <Button type="primary" @click="prevCycle">{{ prevCycleText }}</Button>-->
|
||||
<!-- <Button type="primary" @click="nextCycle" :disabled="reportData.offset >= 0">{{ nextCycleText }}</Button>-->
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserInput from "../../../components/UserInput"
|
||||
|
||||
const TEditor = () => import('../../../components/TEditor');
|
||||
export default {
|
||||
name: "ReportEdit",
|
||||
components: {
|
||||
TEditor, UserInput
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reportData: {
|
||||
title: ""
|
||||
, content: ""
|
||||
, type: "weekly"
|
||||
, receive: []
|
||||
, id: 0
|
||||
, offset: 0 // 以当前日期为基础的周期偏移量。例如选择了上一周那么就是 -1,上一天同理。
|
||||
},
|
||||
disabledType: false,
|
||||
userInputShow: true,
|
||||
prevCycleText: "",
|
||||
nextCycleText: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
id(val) {
|
||||
if (this.id > 0) this.getDetail(val);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getTemplate();
|
||||
},
|
||||
methods: {
|
||||
initLanguage () {
|
||||
this.prevCycleText = this.$L("上一周");
|
||||
this.nextCycleText = this.$L("下一周");
|
||||
},
|
||||
handleSubmit: function () {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/store',
|
||||
data: this.reportData,
|
||||
method: 'post',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.reportData.content = "";
|
||||
this.reportData.receive = [];
|
||||
this.disabledType = false;
|
||||
// msg 结果描述
|
||||
$A.messageSuccess(msg);
|
||||
this.$emit("saveSuccess");
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
});
|
||||
},
|
||||
getTemplate() {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/template',
|
||||
data: {
|
||||
type: this.reportData.type,
|
||||
offset: this.reportData.offset
|
||||
},
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
if (data.id) {
|
||||
this.getDetail(data.id);
|
||||
} else {
|
||||
this.reportData.title = data.title;
|
||||
this.reportData.content = data.content;
|
||||
}
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
});
|
||||
},
|
||||
typeChange(value) {
|
||||
// 切换汇报类型后偏移量归零
|
||||
this.reportData.offset = 0;
|
||||
if ( value === "weekly" ) {
|
||||
this.prevCycleText = this.$L("上一周");
|
||||
this.nextCycleText = this.$L("下一周");
|
||||
} else {
|
||||
this.prevCycleText = this.$L("上一天");
|
||||
this.nextCycleText = this.$L("下一天");
|
||||
}
|
||||
|
||||
if (this.id <= 0)
|
||||
this.getTemplate();
|
||||
},
|
||||
getDetail(reportId) {
|
||||
this.userInputShow = false;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/detail',
|
||||
data: {
|
||||
id: reportId
|
||||
},
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.reportData.title = data.title;
|
||||
this.reportData.content = data.content;
|
||||
this.reportData.receive = data.receives;
|
||||
this.reportData.type = data.type_val;
|
||||
this.reportData.id = reportId;
|
||||
this.disabledType = true;
|
||||
this.userInputShow = true;
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
this.userInputShow = true;
|
||||
});
|
||||
},
|
||||
prevCycle() {
|
||||
this.reportData.offset -= 1;
|
||||
this.disabledType = false;
|
||||
this.reReportData();
|
||||
this.getTemplate();
|
||||
},
|
||||
nextCycle() {
|
||||
// 周期偏移量不允许大于0
|
||||
if ( this.reportData.offset < 0 ) {
|
||||
this.reportData.offset += 1;
|
||||
}
|
||||
this.disabledType = false;
|
||||
this.reReportData();
|
||||
this.getTemplate();
|
||||
},
|
||||
// 获取上一次接收人
|
||||
getLastSubmitter() {
|
||||
this.userInputShow = false;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/last_submitter',
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.reportData.receive = data;
|
||||
this.userInputShow = true;
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
this.userInputShow = true;
|
||||
});
|
||||
},
|
||||
reReportData() {
|
||||
this.reportData.title = "";
|
||||
this.reportData.content = "";
|
||||
this.reportData.receive = [];
|
||||
this.reportData.id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
172
resources/assets/js/pages/manage/components/ReportMy.vue
Normal file
172
resources/assets/js/pages/manage/components/ReportMy.vue
Normal file
@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="report-list-wrap">
|
||||
<Row class="reportmy-row report-row-header">
|
||||
<Col span="2"><p class="reportmy-titles">{{ $L("汇报类型") }}</p></Col>
|
||||
<Col span="6">
|
||||
<Select
|
||||
v-model="reportType"
|
||||
style="width:95%"
|
||||
:placeholder="this.$L('全部')"
|
||||
@on-change="typePick"
|
||||
>
|
||||
<Option v-for="item in reportTypeList" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span="1"></Col>
|
||||
<Col span="2"><p class="reportmy-titles">{{ $L("汇报时间") }}</p></Col>
|
||||
<Col span="6">
|
||||
<DatePicker
|
||||
type="daterange"
|
||||
split-panels
|
||||
:placeholder="this.$L('请选择时间')"
|
||||
style="width: 95%;"
|
||||
@on-change="timePick"
|
||||
></DatePicker>
|
||||
</Col>
|
||||
<Col span="1"></Col>
|
||||
<Col span="4"><Button type="primary" icon="ios-search" @click="searchTab">{{ $L("搜索") }}</Button></Col>
|
||||
</Row>
|
||||
<Table class="tableFill report-row-content" ref="tableRef"
|
||||
:columns="columns" :data="lists"
|
||||
:loading="loadIng > 0"
|
||||
:no-data-text="$L(noDataText)" stripe></Table>
|
||||
<Page class="page-box report-row-foot" :total="listTotal" :current="listPage" :disabled="loadIng > 0"
|
||||
@on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]"
|
||||
placement="top" show-elevator show-sizer show-total transfer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ReportMy",
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
columns: [],
|
||||
lists: [],
|
||||
listPage: 1,
|
||||
listTotal: 0,
|
||||
listPageSize: 10,
|
||||
noDataText: "",
|
||||
createAt: [],
|
||||
reportType:'',
|
||||
reportTypeList:[
|
||||
{value:"weekly",label:'周报' },
|
||||
{value:"daily",label:'日报' },
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getLists();
|
||||
},
|
||||
methods: {
|
||||
initLanguage() {
|
||||
this.noDataText = this.noDataText || "数据加载中.....";
|
||||
this.columns = [{
|
||||
"title": this.$L("名称"),
|
||||
"key": 'title',
|
||||
sortable: true,
|
||||
"minWidth": 120,
|
||||
}, {
|
||||
"title": this.$L("类型"),
|
||||
"key": 'type',
|
||||
"align": 'center',
|
||||
sortable: true,
|
||||
"maxWidth": 80,
|
||||
}, {
|
||||
"title": this.$L("汇报时间"),
|
||||
"key": 'created_at',
|
||||
"align": 'center',
|
||||
sortable: true,
|
||||
"maxWidth": 180,
|
||||
}, {
|
||||
"title": "操作",
|
||||
"key": 'action',
|
||||
"align": 'right',
|
||||
"width": 80,
|
||||
render: (h, params) => {
|
||||
if (!params.row.id) {
|
||||
return null;
|
||||
}
|
||||
let arr = [
|
||||
h('ETooltip', {
|
||||
props: { content: this.$L('编辑'), transfer: true, delay: 600 }
|
||||
}, [h('Icon', {
|
||||
props: { type: 'md-create', size: 16 },
|
||||
style: { margin: '0 3px', cursor: 'pointer' },
|
||||
on: {
|
||||
click: () => {
|
||||
this.$emit("edit", params.row.id);
|
||||
}
|
||||
}
|
||||
})]),
|
||||
h('ETooltip', {
|
||||
props: { content: this.$L('查看'), transfer: true, delay: 600 },
|
||||
style: { position: 'relative' },
|
||||
}, [h('Icon', {
|
||||
props: { type: 'md-eye', size: 16 },
|
||||
style: { margin: '0 3px', cursor: 'pointer' },
|
||||
on: {
|
||||
click: () => {
|
||||
this.$emit("detail", params.row);
|
||||
}
|
||||
}
|
||||
})]),
|
||||
];
|
||||
return h('div', arr);
|
||||
},
|
||||
}];
|
||||
},
|
||||
getLists() {
|
||||
this.loadIng = 1;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/my',
|
||||
data: {
|
||||
page: this.listPage,
|
||||
created_at: this.createAt,
|
||||
type: this.reportType
|
||||
},
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.lists = data.data;
|
||||
this.listTotal = data.total;
|
||||
if ( this.lists.length <= 0 ) {
|
||||
this.noDataText = this.$L("无数据");
|
||||
}
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
}).finally( () => {
|
||||
this.loadIng = 0;
|
||||
} );
|
||||
},
|
||||
setPage(page) {
|
||||
this.listPage = page;
|
||||
this.getLists();
|
||||
},
|
||||
setPageSize(size) {
|
||||
if (Math.max($A.runNum(this.listPageSize), 10) !== size) {
|
||||
this.listPageSize = size;
|
||||
this.getLists();
|
||||
}
|
||||
},
|
||||
timePick(e){
|
||||
// console.log(e)
|
||||
this.createAt = e;
|
||||
},
|
||||
typePick(e){
|
||||
// console.log(e)
|
||||
},
|
||||
|
||||
searchTab() {
|
||||
this.getLists();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
194
resources/assets/js/pages/manage/components/ReportReceive.vue
Normal file
194
resources/assets/js/pages/manage/components/ReportReceive.vue
Normal file
@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="report-list-wrap">
|
||||
<Row class="reportmy-row report-row-header">
|
||||
<Col span="2"><p class="reportmy-titles">{{ $L("汇报人") }}</p></Col>
|
||||
<Col span="4">
|
||||
<Input style="width:100%" v-model="username" :placeholder="$L('请输入用户名')"/>
|
||||
</Col>
|
||||
<Col span="1"></Col>
|
||||
<Col span="2"><p class="reportmy-titles">{{ $L("汇报类型") }}</p></Col>
|
||||
<Col span="4">
|
||||
<Select
|
||||
v-model="reportType"
|
||||
style="width:100%"
|
||||
:placeholder="this.$L('全部')"
|
||||
@on-change="typePick"
|
||||
>
|
||||
<Option v-for="item in reportTypeList" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span="1"></Col>
|
||||
<Col span="2"><p class="reportmy-titles">{{ $L("汇报时间") }}</p></Col>
|
||||
<Col span='4'>
|
||||
<DatePicker
|
||||
type="daterange"
|
||||
split-panels
|
||||
:placeholder="this.$L('请选择时间')"
|
||||
style="width: 100%;"
|
||||
@on-change="timePick"
|
||||
></DatePicker>
|
||||
</Col>
|
||||
<Col span="1"></Col>
|
||||
<Col span="3"><Button type="primary" icon="ios-search" @click="searchTab">{{ $L("搜索") }}</Button></Col>
|
||||
</Row>
|
||||
<Table class="tableFill report-row-content" ref="tableRef"
|
||||
:columns="columns" :data="lists"
|
||||
:loading="loadIng > 0"
|
||||
:no-data-text="$L(noDataText)" stripe></Table>
|
||||
<Page class="page-box report-row-foot" :total="listTotal" :current="listPage" :disabled="loadIng > 0"
|
||||
@on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]"
|
||||
placement="top" show-elevator show-sizer show-total transfer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ReportReceive",
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
columns: [],
|
||||
lists: [],
|
||||
listPage: 1,
|
||||
listTotal: 0,
|
||||
listPageSize: 10,
|
||||
noDataText: "",
|
||||
|
||||
username:'',
|
||||
reportType:'',
|
||||
createAt: [],
|
||||
reportTypeList:[
|
||||
{value:"weekly",label:'周报' },
|
||||
{value:"daily",label:'日报' },
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getLists();
|
||||
},
|
||||
methods: {
|
||||
initLanguage() {
|
||||
this.noDataText = this.noDataText || "数据加载中.....";
|
||||
this.columns = [{
|
||||
"title": this.$L("标题"),
|
||||
"key": 'title',
|
||||
"sortable": true,
|
||||
"minWidth": 120,
|
||||
render: (h, params) => {
|
||||
let arr = []
|
||||
if(params.row.receives_user[0].pivot.read==0){
|
||||
arr.push(
|
||||
h('Tag', {
|
||||
props: { //传递参数
|
||||
color: "orange",
|
||||
}
|
||||
}, this.$L("未读")),
|
||||
h('span',params.row.title)
|
||||
)
|
||||
}else {
|
||||
arr.push(
|
||||
h('Tag', {
|
||||
props: { //传递参数
|
||||
color: "lime",
|
||||
}
|
||||
}, this.$L("已读")),
|
||||
h('span',params.row.title)
|
||||
)
|
||||
}
|
||||
|
||||
return h('div',arr)
|
||||
}
|
||||
}, {
|
||||
"title": this.$L("类型"),
|
||||
"key": 'type',
|
||||
"align": 'center',
|
||||
"sortable": true,
|
||||
"maxWidth": 80,
|
||||
}, {
|
||||
"title": this.$L("接收时间"),
|
||||
"key": 'receive_time',
|
||||
"align": 'center',
|
||||
"sortable": true,
|
||||
"maxWidth": 180,
|
||||
}, {
|
||||
"title": " ",
|
||||
"key": 'action',
|
||||
"align": 'right',
|
||||
"width": 40,
|
||||
render: (h, params) => {
|
||||
if (!params.row.id) {
|
||||
return null;
|
||||
}
|
||||
let arr = [
|
||||
h('ETooltip', {
|
||||
props: { content: this.$L('查看'), transfer: true, delay: 600 },
|
||||
style: { position: 'relative' },
|
||||
}, [h('Icon', {
|
||||
props: { type: 'md-eye', size: 16 },
|
||||
style: { margin: '0 3px', cursor: 'pointer' },
|
||||
on: {
|
||||
click: () => {
|
||||
this.$emit("detail", params.row)
|
||||
this.lists[params.index].receives_user[0].pivot.read = 1
|
||||
}
|
||||
}
|
||||
})])
|
||||
];
|
||||
return h('div', arr);
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
getLists() {
|
||||
this.loadIng = 1;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'report/receive',
|
||||
data: {
|
||||
page: this.listPage,
|
||||
username: this.username,
|
||||
created_at: this.createAt,
|
||||
type: this.reportType
|
||||
},
|
||||
method: 'get',
|
||||
}).then(({data, msg}) => {
|
||||
// data 结果数据
|
||||
this.lists = data.data;
|
||||
this.listTotal = data.total;
|
||||
if ( this.lists.length <= 0 ) {
|
||||
this.noDataText = this.$L("无数据");
|
||||
}
|
||||
// msg 结果描述
|
||||
}).catch(({msg}) => {
|
||||
// msg 错误原因
|
||||
$A.messageError(msg);
|
||||
}).finally( () => {
|
||||
this.loadIng = 0;
|
||||
} );
|
||||
},
|
||||
setPage(page) {
|
||||
this.listPage = page;
|
||||
this.getLists();
|
||||
},
|
||||
setPageSize(size) {
|
||||
if (Math.max($A.runNum(this.listPageSize), 10) !== size) {
|
||||
this.listPageSize = size;
|
||||
this.getLists();
|
||||
}
|
||||
},
|
||||
|
||||
timePick(e){
|
||||
this.createAt = e;
|
||||
},
|
||||
typePick(e){
|
||||
// console.log(e)
|
||||
},
|
||||
searchTab() {
|
||||
this.getLists();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
14
resources/assets/sass/_.scss
vendored
Normal file
14
resources/assets/sass/_.scss
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
@import "app-down";
|
||||
@import "auto-tip";
|
||||
@import "circle";
|
||||
@import "drawer-overlay";
|
||||
@import "img-update";
|
||||
@import "loading";
|
||||
@import "scroller-y";
|
||||
@import "spinner";
|
||||
@import "t-editor";
|
||||
@import "quick-edit";
|
||||
@import "tag-input";
|
||||
@import "user-avatar";
|
||||
@import "user-input";
|
||||
@import "report";
|
74
resources/assets/sass/app-down.scss
vendored
Normal file
74
resources/assets/sass/app-down.scss
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
.common-app-down {
|
||||
position: absolute;
|
||||
bottom: 26px;
|
||||
right: 26px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: bottom 0.3s;
|
||||
&.on-client {
|
||||
&[data-route=login] {
|
||||
bottom: 75px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.common-app-down-notification {
|
||||
.notification-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.notification-title {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 18px;
|
||||
color: #17233d;
|
||||
font-weight: 500;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.notification-body {
|
||||
max-height: 210px;
|
||||
overflow: auto;
|
||||
margin: 18px 0;
|
||||
.markdown-preview {
|
||||
margin: -20px -12px;
|
||||
h2 {
|
||||
font-size: 18px !important;
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
ul {
|
||||
li {
|
||||
padding: 2px 0 2px 2px !important;
|
||||
&:after {
|
||||
top: 10px !important;
|
||||
width: 6px !important;
|
||||
height: 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.notification-link {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
> button + button {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.common-app-down-link {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
background-color: #8bcf70;
|
||||
border-color: #8bcf70;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
6
resources/assets/sass/auto-tip.scss
vendored
Normal file
6
resources/assets/sass/auto-tip.scss
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.common-auto-tip {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap
|
||||
}
|
14
resources/assets/sass/circle.scss
vendored
Normal file
14
resources/assets/sass/circle.scss
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
.common-circle {
|
||||
border-radius: 50%;
|
||||
.common-circle-path {
|
||||
fill: transparent;
|
||||
}
|
||||
.common-circle-g-path-ring {
|
||||
stroke: $primary-color;
|
||||
}
|
||||
.common-circle-g-path-core {
|
||||
fill: $primary-color;
|
||||
transform: scale(0.56);
|
||||
transform-origin: 50%;
|
||||
}
|
||||
}
|
1
resources/assets/sass/components/_.scss
vendored
1
resources/assets/sass/components/_.scss
vendored
@ -11,3 +11,4 @@
|
||||
@import "tag-input";
|
||||
@import "user-avatar";
|
||||
@import "user-input";
|
||||
@import "report";
|
||||
|
218
resources/assets/sass/components/report.scss
vendored
Normal file
218
resources/assets/sass/components/report.scss
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
.report {
|
||||
height: 100%;
|
||||
padding: 10px 20px;
|
||||
.report-list-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
top: 0;
|
||||
padding-top: 53px;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
.report-row-header,.report-row-foot{
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.report-row-content{
|
||||
flex:1 1 auto;
|
||||
.ivu-table{
|
||||
.ivu-table-body{
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-box {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.ivu-tabs{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.ivu-tabs-bar{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
}
|
||||
.ivu-tabs-content{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin-top: -53px;
|
||||
padding-top: 53px;
|
||||
}
|
||||
.ivu-tabs-tabpane{
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.report-detail {
|
||||
.report-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
padding-top: 20px;
|
||||
.report-title-icon{
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-profile {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.report-submitter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
p{
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: justify;
|
||||
padding-right: 12px;
|
||||
&:after{
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
& > div {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-col{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.report-content {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
h2{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
ol{
|
||||
margin-bottom: 20px;
|
||||
padding-left: 18px;
|
||||
li{
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.report-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.report-row-header,.report-row-foot{
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.report-row-content{
|
||||
flex:1 1 auto;
|
||||
}
|
||||
.report-row-foot{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.report-row{
|
||||
margin-bottom: 20px;
|
||||
.report-row-a{
|
||||
float: right;
|
||||
line-height: 32px;
|
||||
.report-row-a-icon{
|
||||
transform: rotate(-90deg);
|
||||
font-size: 16px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
.report-bottom{
|
||||
width: 120px;
|
||||
}
|
||||
.report-bottom-save{
|
||||
width: 120px;
|
||||
background: #F4F5F7 ;
|
||||
color: #515A6E;
|
||||
border-color: #F4F5F7 ;
|
||||
}
|
||||
}
|
||||
.report-titles{
|
||||
line-height: 32px;
|
||||
}
|
||||
.report-radiogroup{
|
||||
background: #F4F5F7 !important;
|
||||
padding: 2px !important;
|
||||
border-radius: 4px!important;
|
||||
.ivu-radio-wrapper{
|
||||
padding: 0 30px !important;
|
||||
background: #F4F5F7 !important;
|
||||
color: #515A6E !important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
&:before{
|
||||
width: 0!important;
|
||||
}
|
||||
&:after{
|
||||
width: 0!important;
|
||||
}
|
||||
}
|
||||
.ivu-radio-focus{
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
&:after{
|
||||
background: none!important;
|
||||
}
|
||||
}
|
||||
.ivu-radio-wrapper-checked:not(.ivu-radio-wrapper-disabled){
|
||||
background: #fff !important;
|
||||
color: #8BCF70 !important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
border-radius: 4px!important;
|
||||
}
|
||||
|
||||
}
|
||||
.report-buttongroup{
|
||||
margin-top: 2px;
|
||||
background: #F4F5F7!important;
|
||||
border-radius: 4px;
|
||||
.report-buttongroup-shu{
|
||||
position: absolute;
|
||||
left: 47px;
|
||||
width: 1px;
|
||||
height: 23px;
|
||||
background-color: #E5E5E5;
|
||||
top: 5px;
|
||||
}
|
||||
.ivu-btn-primary{
|
||||
background: #F4F5F7!important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
color: #8BCF70 !important;
|
||||
&[disabled]{
|
||||
color: #515A6E !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.report-poptip{
|
||||
.ivu-tooltip-inner{
|
||||
min-width: 60px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
.reportmy-row{
|
||||
margin-bottom: 20px;
|
||||
.reportmy-titles{
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.report-main{
|
||||
.report-submitter{
|
||||
padding-top: 13px;
|
||||
}
|
||||
}
|
136
resources/assets/sass/drawer-overlay.scss
vendored
Normal file
136
resources/assets/sass/drawer-overlay.scss
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
background: rgba(0, 0, 0, 0.76);
|
||||
outline: none;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
.overlay-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.overlay-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
z-index: 2;
|
||||
|
||||
.overlay-close {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
> a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
color: #dbdbde;
|
||||
&:hover {
|
||||
color: #fff
|
||||
}
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-resize {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
margin-bottom: -5px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.overlay-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 18px 18px 0 0;
|
||||
transform: translate(0, 15%) scale(0.98);
|
||||
cursor: default;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.overlay-visible {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: opacity 0.2s ease;
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0) scale(1);
|
||||
transition: opacity 0.2s ease, transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.overlay-hide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: opacity 0.2s ease;
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(0, 15%) scale(0.98);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
.overlay-body {
|
||||
flex-direction: row;
|
||||
.overlay-close {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.overlay-resize {
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
margin-right: -5px;
|
||||
z-index: 1;
|
||||
}
|
||||
.overlay-content {
|
||||
transform: translate(15%, 0) scale(0.98);
|
||||
border-radius: 18px 0 0 18px;
|
||||
}
|
||||
}
|
||||
&.overlay-visible {
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(0, 0) scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.overlay-hide {
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(15%, 0) scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
255
resources/assets/sass/img-update.scss
vendored
Normal file
255
resources/assets/sass/img-update.scss
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
.img-upload-modal {
|
||||
.ivu-modal-mask {
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.ivu-modal-no-mask {
|
||||
background-color: rgba(55, 55, 55, .2);
|
||||
}
|
||||
|
||||
.ivu-modal-wrap {
|
||||
z-index: 1001;
|
||||
}
|
||||
}
|
||||
|
||||
.imgcomp-upload-list {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
|
||||
margin-right: 4px;
|
||||
vertical-align: top;
|
||||
|
||||
.imgcomp-upload-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.imgcomp-upload-list-cover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
}
|
||||
|
||||
.imgcomp-upload-list-cover i {
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
transition: all .2s;
|
||||
}
|
||||
|
||||
.imgcomp-upload-list-cover i:hover {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.ivu-progress {
|
||||
height: 100%;
|
||||
.ivu-progress-outer {
|
||||
background-color: rgba(0, 0, 0, 0.68);
|
||||
height: 100%;
|
||||
.ivu-progress-inner {
|
||||
width: 88%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imgcomp-upload-list:hover .imgcomp-upload-list-cover {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.img-upload-foot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.img-upload-foot-input {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.img-upload-foot-httptitle {
|
||||
cursor: pointer;
|
||||
padding-left: 3px;
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-box {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
display: inline-block;
|
||||
background: #fff;
|
||||
border: 1px dashed #dddee1;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
vertical-align: top;
|
||||
|
||||
.add-box-icon {
|
||||
i {
|
||||
vertical-align: middle;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-box-upload {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #ffffff;
|
||||
padding-top: 9px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
|
||||
.add-box-item {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
|
||||
.ivu-upload-drag, .ivu-upload-drag:hover {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
transition: all .2s;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-box-item:hover {
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.add-box:hover {
|
||||
border-color: rgba(0, 0, 0, .6);
|
||||
|
||||
.add-box-upload {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.callback-add-box {
|
||||
display: block;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
|
||||
.add-box-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.add-box-upload {
|
||||
display: block;
|
||||
width: auto;
|
||||
background: transparent;
|
||||
color: #333;
|
||||
padding: 0;
|
||||
|
||||
> div {
|
||||
display: inline-block;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.browse-load {
|
||||
margin: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.browse-list {
|
||||
max-height: 540px;
|
||||
overflow: auto;
|
||||
|
||||
.browse-item {
|
||||
margin: 10px 15px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
.browse-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAABxCAAAAABg5GeyAAACW0lEQVR4Ae3XVRLjMBAE0L3/rSwKM3OcSNPyLVYOLvM6UD0Bd03LVe9XH+RlhlRSSSWVVFJJJZVUUkkllVRSSSWVVFJJJZVUUkl9WyqppJJKKqmkkgpURP17xngOAR5NxW5wlJ9MaLQh83F4NHWmd/gZtdVBaOldfDB1bq5UpJFbFOC6LKnYrkRO209PAw+hIuzWB8Ep5es8HvYo4z4tE1X8UeRwlMM2D5Bzkc7kj6Bi3VTKDDwEeUcrMxrUvGDXTnHa6kK69SDN9sgq1clxKSbNHqqnYmdri81Q9QHf1JPt1Frncaib2XbiTKL2GkHaurnY9LOulMV0O7G6Kw+g9sw2ohhm62KezVJaaufjWC1TnOkr1exilJ7Ji0vxCCqO9V4UwV4PYr9+apouhGYLKfnahdpqegjmeoXOpXgANe70pKT6Zhu19qkY2nC0PZS527lQOyInqr8Uvc5jqfUb1X+PGh5IhW90S2quh3FQC2XRcF66TUkTXPcLKm5FtdR9RJq+2hWII7UpFtmsQLEyzsdJtkxxpr6gLotbUSlV9yeT0Trmzk2XPdUThLYarUbWOY9j04xXQ2u+pMZLYSumGmNUH3HbM9qOAwSHodN2Pks25F2j3aI7+IxqNsB+YLWb16ukSjiW4xNB0gMoMfApBS/XZQgi3p9/5RsiKNKZEOwYFVIF5VyTyD19sbyjIJiNJRZxpNbx2S8sGKvGZNHJBniBu9Wy5WxjGuQFqIAcBHiRGyt4ua5gSCWVVFJJJZVUUkkllVRSSSWVVFJJJZVUUkkllVRSSSWVVFI/AgO0SXIVYHeGAAAAAElFTkSuQmCC);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.browse-title {
|
||||
display: block;
|
||||
width: 64px;
|
||||
margin-top: 5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.browse-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
font-size: 36px;
|
||||
padding-top: 15px;
|
||||
color: #ffffff;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.browse-list-disabled {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.browse-list-disabled:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
z-index: 1;
|
||||
}
|
@ -180,6 +180,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.dialog-action {
|
||||
align-self: flex-start;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
height: 100%;
|
||||
|
||||
> * {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
}
|
||||
&.history {
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
|
11
resources/assets/sass/pages/page-login.scss
vendored
11
resources/assets/sass/pages/page-login.scss
vendored
@ -79,6 +79,17 @@
|
||||
.login-switch {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
.login-input-tips-box{
|
||||
position: relative;
|
||||
.login-input-tips{
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -20px;
|
||||
color: #c7c7c7;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.login-bottom {
|
||||
|
58
resources/assets/sass/quick-edit.scss
vendored
Executable file
58
resources/assets/sass/quick-edit.scss
vendored
Executable file
@ -0,0 +1,58 @@
|
||||
.quick-edit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
.quick-input {
|
||||
flex: 1;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
.quick-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.common-loading {
|
||||
margin: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.quick-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.quick-icon {
|
||||
display: none;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&.quick-always {
|
||||
.quick-icon {
|
||||
display: inline-block;
|
||||
opacity: 0.3;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.quick-icon {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ivu-table-row-hover {
|
||||
.quick-edit {
|
||||
.quick-icon {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
218
resources/assets/sass/report.scss
vendored
Normal file
218
resources/assets/sass/report.scss
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
.report {
|
||||
height: 100%;
|
||||
padding: 10px 20px;
|
||||
.report-list-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
top: 0;
|
||||
padding-top: 53px;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
.report-row-header,.report-row-foot{
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.report-row-content{
|
||||
flex:1 1 auto;
|
||||
.ivu-table{
|
||||
.ivu-table-body{
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-box {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.ivu-tabs{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.ivu-tabs-bar{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
}
|
||||
.ivu-tabs-content{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin-top: -53px;
|
||||
padding-top: 53px;
|
||||
}
|
||||
.ivu-tabs-tabpane{
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.report-detail {
|
||||
.report-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
padding-top: 20px;
|
||||
.report-title-icon{
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-profile {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.report-submitter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
p{
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: justify;
|
||||
padding-right: 12px;
|
||||
&:after{
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
& > div {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-col{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.report-content {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
h2{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
ol{
|
||||
margin-bottom: 20px;
|
||||
padding-left: 18px;
|
||||
li{
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.report-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.report-row-header,.report-row-foot{
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.report-row-content{
|
||||
flex:1 1 auto;
|
||||
}
|
||||
.report-row-foot{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.report-row{
|
||||
margin-bottom: 20px;
|
||||
.report-row-a{
|
||||
float: right;
|
||||
line-height: 32px;
|
||||
.report-row-a-icon{
|
||||
transform: rotate(-90deg);
|
||||
font-size: 16px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
.report-bottom{
|
||||
width: 120px;
|
||||
}
|
||||
.report-bottom-save{
|
||||
width: 120px;
|
||||
background: #F4F5F7 ;
|
||||
color: #515A6E;
|
||||
border-color: #F4F5F7 ;
|
||||
}
|
||||
}
|
||||
.report-titles{
|
||||
line-height: 32px;
|
||||
}
|
||||
.report-radiogroup{
|
||||
background: #F4F5F7 !important;
|
||||
padding: 2px !important;
|
||||
border-radius: 4px!important;
|
||||
.ivu-radio-wrapper{
|
||||
padding: 0 30px !important;
|
||||
background: #F4F5F7 !important;
|
||||
color: #515A6E !important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
&:before{
|
||||
width: 0!important;
|
||||
}
|
||||
&:after{
|
||||
width: 0!important;
|
||||
}
|
||||
}
|
||||
.ivu-radio-focus{
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
&:after{
|
||||
background: none!important;
|
||||
}
|
||||
}
|
||||
.ivu-radio-wrapper-checked:not(.ivu-radio-wrapper-disabled){
|
||||
background: #fff !important;
|
||||
color: #8BCF70 !important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
border-radius: 4px!important;
|
||||
}
|
||||
|
||||
}
|
||||
.report-buttongroup{
|
||||
margin-top: 2px;
|
||||
background: #F4F5F7!important;
|
||||
border-radius: 4px;
|
||||
.report-buttongroup-shu{
|
||||
position: absolute;
|
||||
left: 47px;
|
||||
width: 1px;
|
||||
height: 23px;
|
||||
background-color: #E5E5E5;
|
||||
top: 5px;
|
||||
}
|
||||
.ivu-btn-primary{
|
||||
background: #F4F5F7!important;
|
||||
box-shadow: none !important;
|
||||
border: none!important;
|
||||
color: #8BCF70 !important;
|
||||
&[disabled]{
|
||||
color: #515A6E !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.report-poptip{
|
||||
.ivu-tooltip-inner{
|
||||
min-width: 60px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
.reportmy-row{
|
||||
margin-bottom: 20px;
|
||||
.reportmy-titles{
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.report-main{
|
||||
.report-submitter{
|
||||
padding-top: 13px;
|
||||
}
|
||||
}
|
19
resources/assets/sass/scroller-y.scss
vendored
Executable file
19
resources/assets/sass/scroller-y.scss
vendored
Executable file
@ -0,0 +1,19 @@
|
||||
.app-scroller-y {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
.app-scroller-bottom {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
&.static {
|
||||
position: static;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
20
resources/assets/sass/spinner.scss
vendored
Normal file
20
resources/assets/sass/spinner.scss
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
.common-spinner {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
margin: 0 auto;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
.common-circular {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
118
resources/assets/sass/t-editor.scss
vendored
Executable file
118
resources/assets/sass/t-editor.scss
vendored
Executable file
@ -0,0 +1,118 @@
|
||||
.teditor-box,
|
||||
.teditor-transfer {
|
||||
.tox {
|
||||
&.tox-silver-sink {
|
||||
z-index: 13000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.teditor-box {
|
||||
position: relative;
|
||||
min-height: 22px;
|
||||
|
||||
.icon-inline {
|
||||
color: #bbbbbb;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tox-tinymce {
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
border-color: #dddee1;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.tox-statusbar {
|
||||
span.tox-statusbar__branding {
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tox-tbtn--bespoke {
|
||||
.tox-tbtn__select-label {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.teditor-transfer {
|
||||
background-color: #ffffff;
|
||||
|
||||
.tox-toolbar {
|
||||
> div:last-child {
|
||||
> button:last-child {
|
||||
margin-right: 64px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-modal-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ivu-modal-close {
|
||||
top: 7px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.teditor-transfer-body {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
textarea {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tox-tinymce {
|
||||
border: 0;
|
||||
|
||||
.tox-statusbar {
|
||||
span.tox-statusbar__branding {
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.teditor-loadstyle {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.teditor-loadedstyle {
|
||||
width: 100%;
|
||||
max-height: inherit;
|
||||
overflow: inherit;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-control {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tox-tinymce-inline {
|
||||
z-index: 100000;
|
||||
}
|
93
resources/assets/sass/tag-input.scss
vendored
Executable file
93
resources/assets/sass/tag-input.scss
vendored
Executable file
@ -0,0 +1,93 @@
|
||||
.common-tag-input {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
padding: 2px 7px;
|
||||
border: 1px solid #dddee1;
|
||||
border-radius: 4px;
|
||||
color: #495060;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
cursor: text;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
transition: all .2s;
|
||||
|
||||
&:hover {
|
||||
border-color: #a2d98d;
|
||||
}
|
||||
|
||||
&.focus {
|
||||
border-color: #a2d98d;
|
||||
box-shadow: 0 0 0 2px rgba(139,207,112,.2)
|
||||
}
|
||||
|
||||
.tags-item, .tags-input {
|
||||
position: relative;
|
||||
float: left;
|
||||
color: #495060;
|
||||
background-color: #f1f8ff;
|
||||
border-radius: 3px;
|
||||
line-height: 22px;
|
||||
margin: 2px 6px 2px 0;
|
||||
padding: 0 20px 0 6px;
|
||||
|
||||
.tags-content {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.tags-del {
|
||||
width: 20px;
|
||||
height: 22px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-input {
|
||||
max-width: 80%;
|
||||
padding: 0;
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
color: inherit;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tags-input::placeholder {
|
||||
color: #bbbbbb;
|
||||
}
|
||||
|
||||
.tags-placeholder {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
color: rgba(255, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
.common-tag-input::after {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
}
|
||||
.ivu-form-item-error {
|
||||
.common-tag-input {
|
||||
border-color: #ed4014;
|
||||
&:hover {
|
||||
border-color: #ed4014;
|
||||
}
|
||||
&.focus {
|
||||
border-color: #ed4014;
|
||||
box-shadow: 0 0 0 2px rgba(237,64,20,.2)
|
||||
}
|
||||
}
|
||||
}
|
73
resources/assets/sass/user-avatar.scss
vendored
Executable file
73
resources/assets/sass/user-avatar.scss
vendored
Executable file
@ -0,0 +1,73 @@
|
||||
.common-avatar {
|
||||
position: relative;
|
||||
&.avatar-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.avatar-box {
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.avatar-default {
|
||||
background-color: transparent;
|
||||
}
|
||||
.avatar-text {
|
||||
background-color: $primary-color;
|
||||
> span {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
> em {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #ff9900;
|
||||
border: 1px solid #ffffff;
|
||||
transform-origin: right bottom;
|
||||
z-index: 1;
|
||||
}
|
||||
&.online {
|
||||
> em {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.avatar-name {
|
||||
padding-left: 6px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
.common-avatar-transfer {
|
||||
padding: 4px 2px;
|
||||
line-height: 1.5;
|
||||
> p {
|
||||
padding: 1px 2px;
|
||||
}
|
||||
.avatar-icons {
|
||||
margin-top: 12px;
|
||||
border-top: 1px solid rgba(244, 244, 245, 0.5);
|
||||
padding: 8px 0 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> i {
|
||||
cursor: pointer;
|
||||
font-size: 22px;
|
||||
margin-right: 12px;
|
||||
color: #F4F4F5;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
resources/assets/sass/user-input.scss
vendored
Executable file
70
resources/assets/sass/user-input.scss
vendored
Executable file
@ -0,0 +1,70 @@
|
||||
.common-user {
|
||||
position: relative;
|
||||
white-space: normal;
|
||||
.common-user-loading {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
bottom: 0;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.common-loading {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
&.hidden-input {
|
||||
.ivu-select-selection {
|
||||
padding: 0 4px;
|
||||
.ivu-select-input {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.common-user-transfer {
|
||||
.user-input-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.user-input-avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.avatar {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
}
|
||||
}
|
||||
.user-input-nickname {
|
||||
margin-left: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
.user-input-userid {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
color: #cccccc;
|
||||
transition: margin 0.1s;
|
||||
}
|
||||
}
|
||||
.ivu-select-item {
|
||||
&.ivu-select-item-selected {
|
||||
&:after {
|
||||
top: 8px;
|
||||
}
|
||||
.user-input-option {
|
||||
.user-input-userid {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-drop-prepend {
|
||||
text-align: center;
|
||||
color: #c5c8ce;
|
||||
line-height: 20px;
|
||||
padding-bottom: 5px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
use App\Http\Controllers\Api\DialogController;
|
||||
use App\Http\Controllers\Api\FileController;
|
||||
use App\Http\Controllers\Api\ProjectController;
|
||||
use App\Http\Controllers\Api\ReportController;
|
||||
use App\Http\Controllers\Api\SystemController;
|
||||
use App\Http\Controllers\Api\UsersController;
|
||||
use App\Http\Controllers\IndexController;
|
||||
@ -39,6 +40,9 @@ Route::prefix('api')->middleware(['webapi'])->group(function () {
|
||||
// 文件
|
||||
Route::any('file/{method}', FileController::class);
|
||||
Route::any('file/{method}/{action}', FileController::class);
|
||||
// 报告
|
||||
Route::any('report/{method}', ReportController::class);
|
||||
Route::any('report/{method}/{action}', ReportController::class);
|
||||
});
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user