From d48ed1810243032f86647871500b81c2f3f693d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9F=A6=E8=8D=A3=E8=B6=85?= <302645122@qq.com> Date: Fri, 14 Jan 2022 15:55:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=80=90=E5=B7=A5=E4=BD=9C=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E3=80=91=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Api/ReportController.php | 379 ++++++++++++++++++ app/Http/Middleware/VerifyCsrfToken.php | 3 + app/Models/Report.php | 156 +++++++ app/Models/ReportReceive.php | 39 ++ ...2021_12_30_155338_create_reports_table.php | 39 ++ ...30_162019_create_report_receives_table.php | 38 ++ .../2022_01_04_111739_add_report_sign.php | 32 ++ resources/assets/js/pages/manage.vue | 40 +- .../js/pages/manage/components/Report.vue | 65 +++ .../pages/manage/components/ReportDetail.vue | 87 ++++ .../js/pages/manage/components/ReportEdit.vue | 236 +++++++++++ .../js/pages/manage/components/ReportMy.vue | 172 ++++++++ .../pages/manage/components/ReportReceive.vue | 194 +++++++++ resources/assets/sass/_.scss | 14 + resources/assets/sass/app-down.scss | 74 ++++ resources/assets/sass/auto-tip.scss | 6 + resources/assets/sass/circle.scss | 14 + resources/assets/sass/components/_.scss | 1 + resources/assets/sass/components/report.scss | 218 ++++++++++ resources/assets/sass/drawer-overlay.scss | 136 +++++++ resources/assets/sass/img-update.scss | 255 ++++++++++++ .../sass/pages/components/dialog-wrapper.scss | 11 + resources/assets/sass/pages/page-login.scss | 11 + resources/assets/sass/quick-edit.scss | 58 +++ resources/assets/sass/report.scss | 218 ++++++++++ resources/assets/sass/scroller-y.scss | 19 + resources/assets/sass/spinner.scss | 20 + resources/assets/sass/t-editor.scss | 118 ++++++ resources/assets/sass/tag-input.scss | 93 +++++ resources/assets/sass/user-avatar.scss | 73 ++++ resources/assets/sass/user-input.scss | 70 ++++ routes/web.php | 4 + 32 files changed, 2890 insertions(+), 3 deletions(-) create mode 100755 app/Http/Controllers/Api/ReportController.php create mode 100644 app/Models/Report.php create mode 100644 app/Models/ReportReceive.php create mode 100644 database/migrations/2021_12_30_155338_create_reports_table.php create mode 100644 database/migrations/2021_12_30_162019_create_report_receives_table.php create mode 100644 database/migrations/2022_01_04_111739_add_report_sign.php create mode 100644 resources/assets/js/pages/manage/components/Report.vue create mode 100644 resources/assets/js/pages/manage/components/ReportDetail.vue create mode 100644 resources/assets/js/pages/manage/components/ReportEdit.vue create mode 100644 resources/assets/js/pages/manage/components/ReportMy.vue create mode 100644 resources/assets/js/pages/manage/components/ReportReceive.vue create mode 100644 resources/assets/sass/_.scss create mode 100644 resources/assets/sass/app-down.scss create mode 100644 resources/assets/sass/auto-tip.scss create mode 100644 resources/assets/sass/circle.scss create mode 100644 resources/assets/sass/components/report.scss create mode 100644 resources/assets/sass/drawer-overlay.scss create mode 100644 resources/assets/sass/img-update.scss create mode 100755 resources/assets/sass/quick-edit.scss create mode 100644 resources/assets/sass/report.scss create mode 100755 resources/assets/sass/scroller-y.scss create mode 100644 resources/assets/sass/spinner.scss create mode 100755 resources/assets/sass/t-editor.scss create mode 100755 resources/assets/sass/tag-input.scss create mode 100755 resources/assets/sass/user-avatar.scss create mode 100755 resources/assets/sass/user-input.scss diff --git a/app/Http/Controllers/Api/ReportController.php b/app/Http/Controllers/Api/ReportController.php new file mode 100755 index 00000000..472defcb --- /dev/null +++ b/app/Http/Controllers/Api/ReportController.php @@ -0,0 +1,379 @@ +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 ? ('[' . Base::Lang('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . '] ') : ''; + $completeContent .= '
  • ' . $pre . $task->name . '
  • '; + } + } else { + $completeContent = '
  •  
  • '; + } + + // 未完成的任务 + $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) ) ? '[' . Base::Lang('超期') . '] ' : ''; + $unfinishedContent .= '
  • ' . $pre . $task->name . '
  • '; + } + } else { + $unfinishedContent = '
  •  
  • '; + } + // 生成标题 + 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" => '

    ' . Base::Lang('已完成工作') . '

      ' . + $completeContent . '

    ' . + Base::Lang('未完成的工作') . '

      ' . + $unfinishedContent . '
    ', + "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); + } +} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index d2ec036e..9775ee86 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -44,5 +44,8 @@ class VerifyCsrfToken extends Middleware // 保存文件内容(上传) 'api/file/content/upload/', + + // 保存汇报 + 'api/report/store/', ]; } diff --git a/app/Models/Report.php b/app/Models/Report.php new file mode 100644 index 00000000..5b04efe8 --- /dev/null +++ b/app/Models/Report.php @@ -0,0 +1,156 @@ +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 ); + } +} diff --git a/app/Models/ReportReceive.php b/app/Models/ReportReceive.php new file mode 100644 index 00000000..43232e39 --- /dev/null +++ b/app/Models/ReportReceive.php @@ -0,0 +1,39 @@ +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'); + } +} diff --git a/database/migrations/2021_12_30_162019_create_report_receives_table.php b/database/migrations/2021_12_30_162019_create_report_receives_table.php new file mode 100644 index 00000000..7231e9d3 --- /dev/null +++ b/database/migrations/2021_12_30_162019_create_report_receives_table.php @@ -0,0 +1,38 @@ +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'); + } +} diff --git a/database/migrations/2022_01_04_111739_add_report_sign.php b/database/migrations/2022_01_04_111739_add_report_sign.php new file mode 100644 index 00000000..137d2497 --- /dev/null +++ b/database/migrations/2022_01_04_111739_add_report_sign.php @@ -0,0 +1,32 @@ +string("sign")->default("")->comment("汇报唯一标识"); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('reports', function (Blueprint $table) { + $table->dropColumn("sign"); + }); + } +} diff --git a/resources/assets/js/pages/manage.vue b/resources/assets/js/pages/manage.vue index f323825f..a54be022 100644 --- a/resources/assets/js/pages/manage.vue +++ b/resources/assets/js/pages/manage.vue @@ -21,7 +21,10 @@ v-for="(item, key) in menu" :key="key" :divided="!!item.divided" - :name="item.path">{{$L(item.name)}} + :name="item.path"> + {{$L(item.name)}} + +
    @@ -160,6 +163,14 @@
    + + + + + { $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 结果描述 + }); } } } diff --git a/resources/assets/js/pages/manage/components/Report.vue b/resources/assets/js/pages/manage/components/Report.vue new file mode 100644 index 00000000..b3e12e92 --- /dev/null +++ b/resources/assets/js/pages/manage/components/Report.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/resources/assets/js/pages/manage/components/ReportDetail.vue b/resources/assets/js/pages/manage/components/ReportDetail.vue new file mode 100644 index 00000000..3ac28cb5 --- /dev/null +++ b/resources/assets/js/pages/manage/components/ReportDetail.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/resources/assets/js/pages/manage/components/ReportEdit.vue b/resources/assets/js/pages/manage/components/ReportEdit.vue new file mode 100644 index 00000000..b742b2da --- /dev/null +++ b/resources/assets/js/pages/manage/components/ReportEdit.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/resources/assets/js/pages/manage/components/ReportMy.vue b/resources/assets/js/pages/manage/components/ReportMy.vue new file mode 100644 index 00000000..d50faf09 --- /dev/null +++ b/resources/assets/js/pages/manage/components/ReportMy.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/resources/assets/js/pages/manage/components/ReportReceive.vue b/resources/assets/js/pages/manage/components/ReportReceive.vue new file mode 100644 index 00000000..c0dde4c9 --- /dev/null +++ b/resources/assets/js/pages/manage/components/ReportReceive.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/resources/assets/sass/_.scss b/resources/assets/sass/_.scss new file mode 100644 index 00000000..7620c4ea --- /dev/null +++ b/resources/assets/sass/_.scss @@ -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"; diff --git a/resources/assets/sass/app-down.scss b/resources/assets/sass/app-down.scss new file mode 100644 index 00000000..81e12c1f --- /dev/null +++ b/resources/assets/sass/app-down.scss @@ -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; + } +} diff --git a/resources/assets/sass/auto-tip.scss b/resources/assets/sass/auto-tip.scss new file mode 100644 index 00000000..935fab46 --- /dev/null +++ b/resources/assets/sass/auto-tip.scss @@ -0,0 +1,6 @@ +.common-auto-tip { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap +} diff --git a/resources/assets/sass/circle.scss b/resources/assets/sass/circle.scss new file mode 100644 index 00000000..53a000c3 --- /dev/null +++ b/resources/assets/sass/circle.scss @@ -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%; + } +} diff --git a/resources/assets/sass/components/_.scss b/resources/assets/sass/components/_.scss index 28cf8881..7620c4ea 100644 --- a/resources/assets/sass/components/_.scss +++ b/resources/assets/sass/components/_.scss @@ -11,3 +11,4 @@ @import "tag-input"; @import "user-avatar"; @import "user-input"; +@import "report"; diff --git a/resources/assets/sass/components/report.scss b/resources/assets/sass/components/report.scss new file mode 100644 index 00000000..99a28cca --- /dev/null +++ b/resources/assets/sass/components/report.scss @@ -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; + } +} diff --git a/resources/assets/sass/drawer-overlay.scss b/resources/assets/sass/drawer-overlay.scss new file mode 100644 index 00000000..943c9ab2 --- /dev/null +++ b/resources/assets/sass/drawer-overlay.scss @@ -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); + } + } + } + } +} diff --git a/resources/assets/sass/img-update.scss b/resources/assets/sass/img-update.scss new file mode 100644 index 00000000..3c0cf6dd --- /dev/null +++ b/resources/assets/sass/img-update.scss @@ -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; +} diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss index bf9dfbb6..c27e80b1 100644 --- a/resources/assets/sass/pages/components/dialog-wrapper.scss +++ b/resources/assets/sass/pages/components/dialog-wrapper.scss @@ -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; diff --git a/resources/assets/sass/pages/page-login.scss b/resources/assets/sass/pages/page-login.scss index dab531e1..ce92e1ff 100644 --- a/resources/assets/sass/pages/page-login.scss +++ b/resources/assets/sass/pages/page-login.scss @@ -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 { diff --git a/resources/assets/sass/quick-edit.scss b/resources/assets/sass/quick-edit.scss new file mode 100755 index 00000000..f9f59f15 --- /dev/null +++ b/resources/assets/sass/quick-edit.scss @@ -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; + } + } +} diff --git a/resources/assets/sass/report.scss b/resources/assets/sass/report.scss new file mode 100644 index 00000000..99a28cca --- /dev/null +++ b/resources/assets/sass/report.scss @@ -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; + } +} diff --git a/resources/assets/sass/scroller-y.scss b/resources/assets/sass/scroller-y.scss new file mode 100755 index 00000000..7f9f816d --- /dev/null +++ b/resources/assets/sass/scroller-y.scss @@ -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; + } +} diff --git a/resources/assets/sass/spinner.scss b/resources/assets/sass/spinner.scss new file mode 100644 index 00000000..8238a0ed --- /dev/null +++ b/resources/assets/sass/spinner.scss @@ -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%; + } +} diff --git a/resources/assets/sass/t-editor.scss b/resources/assets/sass/t-editor.scss new file mode 100755 index 00000000..30d5a48f --- /dev/null +++ b/resources/assets/sass/t-editor.scss @@ -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; +} diff --git a/resources/assets/sass/tag-input.scss b/resources/assets/sass/tag-input.scss new file mode 100755 index 00000000..a377ea07 --- /dev/null +++ b/resources/assets/sass/tag-input.scss @@ -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) + } + } +} diff --git a/resources/assets/sass/user-avatar.scss b/resources/assets/sass/user-avatar.scss new file mode 100755 index 00000000..93d872a4 --- /dev/null +++ b/resources/assets/sass/user-avatar.scss @@ -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; + } + } + } +} diff --git a/resources/assets/sass/user-input.scss b/resources/assets/sass/user-input.scss new file mode 100755 index 00000000..f316f691 --- /dev/null +++ b/resources/assets/sass/user-input.scss @@ -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; + } +} diff --git a/routes/web.php b/routes/web.php index 4f3fc9eb..bc307054 100644 --- a/routes/web.php +++ b/routes/web.php @@ -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); }); /**