mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-10 18:02:55 +00:00
perf: 支持查看任务描述修改历史
This commit is contained in:
parent
bd61b8c948
commit
dbdb805269
@ -32,6 +32,7 @@ use App\Models\ProjectTaskUser;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\ProjectPermission;
|
||||
use App\Models\ProjectTaskContent;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use App\Module\BillMultipleExport;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -1576,7 +1577,8 @@ class ProjectController extends AbstractController
|
||||
* @apiGroup project
|
||||
* @apiName task__content
|
||||
*
|
||||
* @apiParam {Number} task_id 任务ID
|
||||
* @apiParam {Number} task_id 任务ID
|
||||
* @apiParam {Number} [history_id] 历史ID(获取历史版本)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@ -1587,15 +1589,57 @@ class ProjectController extends AbstractController
|
||||
User::auth();
|
||||
//
|
||||
$task_id = intval(Request::input('task_id'));
|
||||
$history_id = intval(Request::input('history_id'));
|
||||
//
|
||||
$task = ProjectTask::userTask($task_id, null);
|
||||
//
|
||||
if ($history_id > 0) {
|
||||
$taskContent = ProjectTaskContent::whereTaskId($task->id)->whereId($history_id)->first();
|
||||
if (empty($taskContent)) {
|
||||
return Base::retError('历史版本不存在');
|
||||
}
|
||||
return Base::retSuccess('success', array_merge($taskContent->getContentInfo(), [
|
||||
'name' => $task->name,
|
||||
]));
|
||||
}
|
||||
if (empty($task->content)) {
|
||||
return Base::retSuccess('success', json_decode('{}'));
|
||||
}
|
||||
return Base::retSuccess('success', $task->content->getContentInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/project/task/content_history 25. 获取任务详细历史描述
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup project
|
||||
* @apiName task__content_history
|
||||
*
|
||||
* @apiParam {Number} task_id 任务ID
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:100
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function task__content_history()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$task_id = intval(Request::input('task_id'));
|
||||
//
|
||||
$task = ProjectTask::userTask($task_id, null);
|
||||
//
|
||||
$data = ProjectTaskContent::select(['id', 'task_id', 'desc', 'userid', 'created_at'])
|
||||
->whereTaskId($task->id)
|
||||
->orderByDesc('id')
|
||||
->paginate(Base::getPaginate(100, 20));
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/project/task/files 26. 获取任务文件列表
|
||||
*
|
||||
|
||||
@ -393,7 +393,7 @@ class ProjectTask extends AbstractModel
|
||||
$p_color = $data['p_color'];
|
||||
$top = intval($data['top']);
|
||||
$userid = User::userid();
|
||||
$visibility = isset($data['visibility_appoint']) ? $data['visibility_appoint'] : $data['visibility'];
|
||||
$visibility = $data['visibility_appoint'] ?? $data['visibility'];
|
||||
$visibility_userids = $data['visibility_appointor'] ?: [];
|
||||
//
|
||||
if (ProjectTask::whereProjectId($project_id)
|
||||
@ -527,6 +527,8 @@ class ProjectTask extends AbstractModel
|
||||
ProjectTaskContent::createInstance([
|
||||
'project_id' => $task->project_id,
|
||||
'task_id' => $task->id,
|
||||
'userid' => $task->userid,
|
||||
'desc' => $task->desc,
|
||||
'content' => [
|
||||
'url' => ProjectTaskContent::saveContent($task->id, $content)
|
||||
],
|
||||
@ -913,15 +915,25 @@ class ProjectTask extends AbstractModel
|
||||
}
|
||||
// 内容
|
||||
if (Arr::exists($data, 'content')) {
|
||||
$logRecord = [];
|
||||
$logContent = ProjectTaskContent::whereTaskId($this->id)->orderByDesc('id')->first();
|
||||
if ($logContent) {
|
||||
$logRecord['link'] = [
|
||||
'title' => '查看历史',
|
||||
'url' => 'single/task/content/' . $this->id . '?history_id=' . $logContent->id,
|
||||
];
|
||||
}
|
||||
$this->desc = self::generateDesc($data['content']);
|
||||
ProjectTaskContent::createInstance([
|
||||
'project_id' => $this->project_id,
|
||||
'task_id' => $this->id,
|
||||
'userid' => User::userid(),
|
||||
'desc' => $this->desc,
|
||||
'content' => [
|
||||
'url' => ProjectTaskContent::saveContent($this->id, $data['content'])
|
||||
],
|
||||
])->save();
|
||||
$this->desc = self::generateDesc($data['content']);
|
||||
$this->addLog("修改{任务}详细描述");
|
||||
$this->addLog("修改{任务}详细描述", $logRecord);
|
||||
$updateMarking['is_update_content'] = true;
|
||||
}
|
||||
// 优先级
|
||||
|
||||
@ -34,7 +34,6 @@ use App\Exceptions\ApiException;
|
||||
class ProjectTaskContent extends AbstractModel
|
||||
{
|
||||
protected $hidden = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddProjectTaskContentsUserid extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table('project_task_contents', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_task_contents', 'userid')) {
|
||||
$table->string('desc', 500)->nullable()->default('')->after('task_id')->comment('内容描述');
|
||||
$table->bigInteger('userid')->nullable()->default(0)->after('task_id')->comment('用户ID');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
Schema::table('project_task_contents', function (Blueprint $table) {
|
||||
$table->dropColumn("desc");
|
||||
$table->dropColumn("userid");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -354,6 +354,7 @@ export default {
|
||||
}
|
||||
});
|
||||
editor.ui.registry.addMenuItem('imagePreview', {
|
||||
icon: 'preview',
|
||||
text: this.$L('预览图片'),
|
||||
onAction: () => {
|
||||
this.operateImg = null
|
||||
@ -394,6 +395,7 @@ export default {
|
||||
}
|
||||
});
|
||||
editor.ui.registry.addMenuItem('screenload', {
|
||||
icon: 'fullscreen',
|
||||
text: this.$L('退出全屏'),
|
||||
onAction: () => {
|
||||
this.closeFull();
|
||||
@ -418,6 +420,7 @@ export default {
|
||||
}
|
||||
});
|
||||
editor.ui.registry.addMenuItem('screenload', {
|
||||
icon: 'fullscreen',
|
||||
text: this.$L('全屏'),
|
||||
onAction: () => {
|
||||
this.onFull();
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem @click.native="onEditing">{{ $L('编辑描述') }}</DropdownItem>
|
||||
<DropdownItem @click.native="onHistory">{{ $L('历史记录') }}</DropdownItem>
|
||||
<DropdownItem v-if="operateLink" @click.native="onLinkPreview">{{ $L('打开链接') }}</DropdownItem>
|
||||
<DropdownItem v-if="operateImg" @click.native="onImagePreview">{{ $L('查看图片') }}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
@ -81,7 +82,7 @@ export default {
|
||||
autoresize_bottom_margin: 2,
|
||||
min_height: 200,
|
||||
max_height: 380,
|
||||
contextmenu: 'checklist | bold italic underline forecolor backcolor | link | uploadImages imagePreview | screenload',
|
||||
contextmenu: 'checklist | bold italic underline forecolor backcolor | link | uploadImages imagePreview | history screenload',
|
||||
valid_elements: 'a[href|title|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code,ol[class],ul[class],li[class]',
|
||||
extended_valid_elements: 'a[href|title|target=_blank]',
|
||||
toolbar: false
|
||||
@ -89,9 +90,13 @@ export default {
|
||||
optionFull: {
|
||||
menubar: 'file edit view',
|
||||
removed_menuitems: 'preview,print',
|
||||
contextmenu: 'checklist | bold italic underline forecolor backcolor | link | uploadImages imagePreview | screenload',
|
||||
valid_elements: 'a[href|title|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code,ol[class],ul[class],li[class]',
|
||||
extended_valid_elements: 'a[href|title|target=_blank]',
|
||||
toolbar: 'uploadImages | checklist | bold italic underline | forecolor backcolor'
|
||||
toolbar: 'uploadImages | checklist | bold italic underline | forecolor backcolor',
|
||||
mobile: {
|
||||
menubar: 'file edit view',
|
||||
},
|
||||
},
|
||||
|
||||
operateStyles: {},
|
||||
@ -147,12 +152,17 @@ export default {
|
||||
this.$refs.desc.onFull()
|
||||
},
|
||||
|
||||
onHistory() {
|
||||
this.$emit('on-history');
|
||||
},
|
||||
|
||||
onBlur() {
|
||||
this.$emit('on-blur');
|
||||
},
|
||||
|
||||
onEditorInit(editor) {
|
||||
this.updateTouchContent();
|
||||
this.updateHistoryContent(editor);
|
||||
this.$emit('on-editor-init', editor);
|
||||
},
|
||||
|
||||
@ -237,6 +247,16 @@ export default {
|
||||
}, timeout)
|
||||
},
|
||||
|
||||
updateHistoryContent(editor) {
|
||||
editor.ui.registry.addMenuItem('history', {
|
||||
icon: 'insert-time',
|
||||
text: this.$L('历史记录'),
|
||||
onAction: () => {
|
||||
this.onHistory();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onLinkPreview() {
|
||||
if (this.operateLink) {
|
||||
window.open(this.operateLink);
|
||||
|
||||
@ -180,6 +180,16 @@ export default {
|
||||
vNode.push(h('span', {class:'change-value'}, now || '-'))
|
||||
}
|
||||
}
|
||||
if ($A.isJson(record.link)) {
|
||||
let {title, url} = record.link
|
||||
vNode.push(h('span', ': '))
|
||||
vNode.push(h('a', {
|
||||
attrs: {
|
||||
href: $A.baseUrl(url),
|
||||
target: '_blank'
|
||||
}
|
||||
}, this.$L(title)))
|
||||
}
|
||||
if (record.userid) {
|
||||
let userids = $A.isArray(record.userid) ? record.userid : [record.userid]
|
||||
let userNode = [];
|
||||
|
||||
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="task-content-history">
|
||||
<Table
|
||||
:max-height="windowHeight - 180"
|
||||
:columns="columns"
|
||||
:data="list"
|
||||
:loading="loadIng > 0"
|
||||
:no-data-text="$L(noText)"
|
||||
highlight-row
|
||||
stripe/>
|
||||
<Page
|
||||
v-if="total > pageSize"
|
||||
:total="total"
|
||||
:current="page"
|
||||
:page-size="pageSize"
|
||||
:disabled="loadIng > 0"
|
||||
:simple="true"
|
||||
@on-change="setPage"
|
||||
@on-page-size-change="setPageSize"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.task-content-history {
|
||||
.ivu-page {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
export default {
|
||||
name: "TaskContentHistory",
|
||||
props: {
|
||||
taskId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
taskName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
|
||||
columns: [
|
||||
{
|
||||
title: this.$L('日期'),
|
||||
key: 'created_at',
|
||||
width: 168,
|
||||
}, {
|
||||
title: this.$L('描述'),
|
||||
key: 'desc',
|
||||
ellipsis: true,
|
||||
minWidth: 150,
|
||||
render: (h, {row}) => {
|
||||
return h('span', row.desc || '-');
|
||||
}
|
||||
}, {
|
||||
title: this.$L('创建人'),
|
||||
width: 120,
|
||||
render: (h, {row}) => {
|
||||
if (!row.userid) {
|
||||
return h('div', '-');
|
||||
}
|
||||
return h('UserAvatar', {
|
||||
props: {
|
||||
showName: true,
|
||||
size: 22,
|
||||
userid: row.userid,
|
||||
}
|
||||
})
|
||||
}
|
||||
}, {
|
||||
title: this.$L('操作'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (h, {index, row, column}) => {
|
||||
if (index === 0 && this.page === 1) {
|
||||
return h('div', '-');
|
||||
}
|
||||
return h('TableAction', {
|
||||
props: {
|
||||
column: column,
|
||||
menu: [
|
||||
{
|
||||
label: this.$L('查看'),
|
||||
action: "preview",
|
||||
}
|
||||
]
|
||||
},
|
||||
on: {
|
||||
action: (name) => {
|
||||
this.onAction(name, row)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
list: [],
|
||||
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
noText: ''
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
||||
},
|
||||
|
||||
watch: {
|
||||
taskId: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.setPage(1);
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getLists() {
|
||||
if (this.taskId === 0) {
|
||||
return;
|
||||
}
|
||||
this.loadIng++;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'project/task/content_history',
|
||||
data: {
|
||||
task_id: this.taskId,
|
||||
page: Math.max(this.page, 1),
|
||||
pagesize: Math.max($A.runNum(this.pageSize), 10),
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.page = data.current_page;
|
||||
this.total = data.total;
|
||||
this.list = data.data;
|
||||
this.noText = '没有相关的数据';
|
||||
}).catch(() => {
|
||||
this.noText = '数据加载失败';
|
||||
}).finally(_ => {
|
||||
this.loadIng--;
|
||||
})
|
||||
},
|
||||
|
||||
setPage(page) {
|
||||
this.page = page;
|
||||
this.getLists();
|
||||
},
|
||||
|
||||
setPageSize(pageSize) {
|
||||
this.page = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getLists();
|
||||
},
|
||||
|
||||
onAction(name, row) {
|
||||
switch (name) {
|
||||
case 'preview':
|
||||
const title = (this.taskName || `ID: ${this.taskId}`) + ` [${row.created_at}]`;
|
||||
const path = `/single/task/content/${this.taskId}?history_id=${row.id}&history_title=${title}`;
|
||||
if (this.$isEEUiApp) {
|
||||
this.$store.dispatch('openAppChildPage', {
|
||||
pageType: 'app',
|
||||
pageTitle: title,
|
||||
url: 'web.js',
|
||||
params: {
|
||||
titleFixed: true,
|
||||
allowAccess: true,
|
||||
url: $A.rightDelete(window.location.href, window.location.hash) + `#${path}`
|
||||
},
|
||||
})
|
||||
} else {
|
||||
window.open($A.apiUrl(`..${path}`))
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -140,6 +140,7 @@
|
||||
class="desc"
|
||||
:value="taskContent"
|
||||
:placeholder="$L('详细描述...')"
|
||||
@on-history="onHistory"
|
||||
@on-blur="updateBlur('content')"/>
|
||||
<Form class="items" label-position="left" label-width="auto" @submit.native.prevent>
|
||||
<FormItem v-if="taskDetail.p_name">
|
||||
@ -496,6 +497,20 @@
|
||||
<Button type="primary" @click="onDelay" :loading="delayTaskLoading">{{$L('确定')}}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--任务描述历史记录-->
|
||||
<Modal
|
||||
v-model="historyShow"
|
||||
:title="$L('任务描述历史记录')"
|
||||
:mask-closable="false"
|
||||
:styles="{
|
||||
width: '90%',
|
||||
maxWidth: '700px'
|
||||
}">
|
||||
<TaskContentHistory v-if="historyShow" :task-id="taskDetail.id" :task-name="taskDetail.name"/>
|
||||
<div slot="footer">
|
||||
<Button @click="historyShow=false">{{$L('关闭')}}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -511,10 +526,12 @@ import ChatInput from "./ChatInput";
|
||||
import UserSelect from "../../../components/UserSelect.vue";
|
||||
import TaskExistTips from "./TaskExistTips.vue";
|
||||
import TEditorTask from "../../../components/TEditorTask.vue";
|
||||
import TaskContentHistory from "./TaskContentHistory.vue";
|
||||
|
||||
export default {
|
||||
name: "TaskDetail",
|
||||
components: {
|
||||
TaskContentHistory,
|
||||
TEditorTask,
|
||||
UserSelect,
|
||||
TaskExistTips,
|
||||
@ -621,7 +638,9 @@ export default {
|
||||
remark: [
|
||||
{ required: true, message: this.$L('请输入备注'), trigger: 'blur' },
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
historyShow: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -993,6 +1012,10 @@ export default {
|
||||
return isModify;
|
||||
},
|
||||
|
||||
onHistory() {
|
||||
this.historyShow = true;
|
||||
},
|
||||
|
||||
updateBlur(action, params) {
|
||||
if (this.canUpdateBlur) {
|
||||
this.updateData(action, params)
|
||||
|
||||
87
resources/assets/js/pages/single/taskContent.vue
Normal file
87
resources/assets/js/pages/single/taskContent.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="file-preview">
|
||||
<PageTitle :title="pageName"/>
|
||||
<Loading v-if="loadIng > 0"/>
|
||||
<div v-else-if="info" class="file-preview">
|
||||
<div class="edit-header">
|
||||
<div class="header-title">
|
||||
<div class="title-name">{{pageName}}</div>
|
||||
<Tag color="default">{{$L('只读')}}</Tag>
|
||||
<div class="refresh">
|
||||
<Icon type="ios-refresh" @click="getInfo" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
<TEditor :value="info.content" height="100%" readOnly/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TEditor from "../../components/TEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {TEditor},
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
info: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
taskId() {
|
||||
return this.$route.params ? $A.runNum(this.$route.params.taskId) : 0;
|
||||
},
|
||||
historyId() {
|
||||
return this.$route.query ? $A.runNum(this.$route.query.history_id) : 0;
|
||||
},
|
||||
pageName() {
|
||||
if (this.$route.query && this.$route.query.history_title) {
|
||||
return this.$route.query.history_title
|
||||
}
|
||||
if (this.info) {
|
||||
return `${this.info.name} [${this.info.created_at}]`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route': {
|
||||
handler() {
|
||||
this.getInfo();
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getInfo() {
|
||||
setTimeout(_ => {
|
||||
this.loadIng++;
|
||||
}, 600)
|
||||
this.$store.dispatch("call", {
|
||||
url: 'project/task/content',
|
||||
data: {
|
||||
task_id: this.taskId,
|
||||
history_id: this.historyId,
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.info = data;
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError({
|
||||
content: msg,
|
||||
onOk: () => {
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
}).finally(_ => {
|
||||
this.loadIng--;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
11
resources/assets/js/routes.js
vendored
11
resources/assets/js/routes.js
vendored
@ -143,6 +143,11 @@ export default [
|
||||
path: '/single/file/:codeOrFileId',
|
||||
component: () => import('./pages/single/file.vue'),
|
||||
},
|
||||
{
|
||||
name: 'single-task-content',
|
||||
path: '/single/task/content/:taskId',
|
||||
component: () => import('./pages/single/taskContent.vue'),
|
||||
},
|
||||
{
|
||||
name: 'single-task',
|
||||
path: '/single/task/:taskId',
|
||||
@ -154,17 +159,17 @@ export default [
|
||||
component: () => import('./pages/single/apps.vue')
|
||||
},
|
||||
{
|
||||
name: 'valid-email',
|
||||
name: 'single-valid-email',
|
||||
path: '/single/valid/email',
|
||||
component: () => import('./pages/single/validEmail.vue')
|
||||
},
|
||||
{
|
||||
name: 'report-edit',
|
||||
name: 'single-report-edit',
|
||||
path: '/single/report/edit/:reportEditId',
|
||||
component: () => import('./pages/single/reportEdit.vue')
|
||||
},
|
||||
{
|
||||
name: 'report-detail',
|
||||
name: 'single-report-detail',
|
||||
path: '/single/report/detail/:reportDetailId',
|
||||
component: () => import('./pages/single/reportDetail.vue')
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user