#Vue JS 前端問題
# 前提
網站URL
https://starrocket-cms-staging.starrocket.io/
登入帳號:
scott.hsiao@starrocket.io
Ss111111
問題網頁
https://starrocket-cms-staging.starrocket.io/course/list
# 問題
資料表的標題目前是跳轉使用者前端的預覽,想改成跳轉行動的編輯
節錄 index.js
標題欄位
```
data() {
return {
columns: [
{
name: 'id',
label: 'ID',
align: 'center',
format: (val) => val,
sortable: true,
},
...
{
name: 'title',
label: '標題',
align: 'left',
format: (val) =>
`<a href="${process.env.URL}/course/${val.category.id}/${val.id}" target="_blank" rel="noreferrer noopener">${val.title}</a>`,
html: true,
fullData: true,
sortable: true,
},
```
跳轉編輯的部分
```
dataView(row) {
this.$router.push({
name: 'course/content',
params: {
id: row.id,
},
});
},
```
完整內容
index.js
```
import moment from 'moment';
import MyTable from '@/components/MyTable/index.vue';
export default {
name: 'PageCourseList',
components: {
MyTable,
},
data() {
return {
columns: [
{
name: 'id',
label: 'ID',
align: 'center',
format: (val) => val,
sortable: true,
},
{
name: 'image',
label: '圖片',
align: 'center',
format: (val) => `<img src="${val}" width="80" height="45">`,
html: true,
sortable: false,
},
{
name: 'category',
label: '分類',
align: 'left',
format: (val) => (val ? val.name : ''),
sortable: true,
},
{
name: 'title',
label: '標題',
align: 'left',
format: (val) =>
`<a href="${process.env.URL}/course/${val.category.id}/${val.id}" target="_blank" rel="noreferrer noopener">${val.title}</a>`,
html: true,
fullData: true,
sortable: true,
},
{
name: 'created_at',
label: '課程建立時間',
align: 'left',
format: (val) => val,
sortable: true,
},
{
name: 'sale_start_at',
label: '售票開始時間',
align: 'left',
format: (val) => moment(val).format('YYYY-MM-DD HH:mm'),
sortable: true,
},
{
name: 'sale_end_at',
label: '售票結束時間',
align: 'left',
format: (val) => moment(val).format('YYYY-MM-DD HH:mm'),
sortable: true,
},
{
name: 'start_at',
label: '課程開始時間',
align: 'left',
format: (val) => moment(val).format('YYYY-MM-DD HH:mm'),
sortable: true,
},
{
name: 'end_at',
label: '課程結束時間',
align: 'left',
format: (val) => moment(val).format('YYYY-MM-DD HH:mm'),
sortable: true,
},
{
name: 'frontend_status',
label: '前台狀態',
align: 'left',
format: (val) => ['上架', '下架'][val],
sortable: true,
},
{
name: 'sale_status',
label: '售票狀態',
align: 'left',
format: (val) =>
['即將上線', '報名中', '額滿', '停止售票', '結束'][val],
sortable: true,
},
],
data: [],
filter: {
sort_by: 'id',
descending: true,
page: 1,
rows_per_page: 50,
category: null,
keyword: '',
sale_status: null,
},
actions: [
{
color: 'accent',
label: (row) => {
return row.is_top ? '下置頂' : '上置頂';
},
show: (row) => {
return this.canEdit;
},
click: this.dataIsTopChange,
},
],
total: 0,
categoryData: [],
categoryOption: [
{
value: null,
label: '全部',
},
],
StatusOption: [
{
value: null,
label: '全部',
},
{
value: 0,
label: '即將上線',
},
{
value: 1,
label: '報名中',
},
{
value: 2,
label: '額滿',
},
{
value: 3,
label: '停止售票',
},
{
value: 4,
label: '結束',
},
],
keywordInputTimer: null,
// * 0: 即將上線 / 前台: 不會出現
// * 1: 報名中 / 前台: 立刻報名
// * 2: 額滿 / 前台: 額滿
// * 3: 停止售票 / 前台: 停止售票
// * 4: 結束 / 前台: 結束
// * 5: 下線(下架) / 前台: 不會出現
};
},
computed: {},
mounted() {
if (!this.canView) {
return;
}
const listFilterStr = sessionStorage.getItem('listFilter');
if (listFilterStr) {
const listFilter = JSON.parse(listFilterStr);
if (listFilter.name === this.$route.name) {
this.filter = listFilter.filter;
}
}
this.getData();
this.getTypeData();
},
methods: {
async getData() {
const resp = await this.$services.admin.course.getList(this.filter);
this.total = resp.data.total;
this.data = resp.data.data;
if (this.data.length === 0 && this.filter.page > 1) {
this.filter.page--;
this.getData();
return;
}
sessionStorage.setItem(
'listFilter',
JSON.stringify({
name: this.$route.name,
filter: this.filter,
}),
);
},
async addCourse() {
const resp = await this.$services.admin.course.post();
this.$router.push({
name: 'course/content',
params: {
id: resp.data.id,
},
});
},
onRowsPerPageChange() {
this.filter.page = 1;
this.getData();
},
dataView(row) {
this.$router.push({
name: 'course/content',
params: {
id: row.id,
},
});
},
async dataStatusChange(row) {
await this.$services.admin.course.edit(row.id, {
frontend_status: !row.frontend_status ? 1 : 0,
});
this.$lib.notify.success('儲存成功');
this.getData();
},
async dataIsTopChange(row) {
await this.$services.admin.course.edit(row.id, {
is_top: !row.is_top ? 1 : 0,
});
this.$lib.notify.success('儲存成功');
this.getData();
},
async dataDelete(row) {
await this.$services.admin.course.delete(row.id);
this.$lib.notify.success('刪除成功');
this.getData();
},
async dataOffline(row) {
await this.$services.admin.course.edit(row.id, {
status: 5,
});
this.$lib.notify.success('下線成功');
this.getData();
},
async getTypeData() {
const resp = await this.$services.admin.course.type.getList();
this.categoryData = resp.data;
this.categoryData.forEach((item, index, array) => {
this.categoryOption.push({ label: item.name, value: item.id });
});
},
async onSelectCategory() {
const resp = await this.$services.admin.course.getList(this.filter);
this.total = resp.data.total;
this.data = resp.data.data;
},
async onSelectStatus() {
const resp = await this.$services.admin.course.getList(this.filter);
this.total = resp.data.total;
this.data = resp.data.data;
},
onKeywordInput() {
if (this.keywordInputTimer) {
clearTimeout(this.keywordInputTimer);
}
this.keywordInputTimer = setTimeout(() => {
this.filter.page = 1;
this.getData();
}, 500);
},
},
};
```
index.vue
```
<template>
<div>
<div class="row justify-between items-center q-pb-sm">
<div class="col-auto">
<div class="row items-center">
<div class="col-auto">
<div class="text-h6">課程列表</div>
</div>
<div class="col-auto">
<q-btn
no-caps
outline
size="md"
color="primary"
label="新增"
class="q-mx-sm"
v-if="canEdit"
@click="addCourse"
/>
</div>
</div>
</div>
<div class="col-auto">
<Breadcrumbs />
</div>
</div>
<q-card flat>
<q-card-section class="q-py-sm">
<div class="row items-center justify-between">
<div class="col-auto">
<div class="row items-center">
<div class="col-auto">
<q-select
dense
outlined
v-model="filter.rows_per_page"
:options="[5, 10, 20, 30, 40, 50]"
@input="onRowsPerPageChange"
>
<template v-slot:before>
<div class="text-body2">顯示</div>
</template>
<template v-slot:after>
<div class="text-body2">筆資料</div>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-auto">
<div class="row items-center">
<div class="col-auto q-ml-sm q-px-sm">
<q-select
dense
outlined
option-value="value"
emit-value
map-options
v-model="filter.category"
:options="categoryOption"
@input="onSelectCategory"
>
<template v-slot:before>
<div class="text-body2">依分類查詢</div>
</template>
</q-select>
</div>
<div class="col-auto q-ml-sm q-px-sm">
<q-select
dense
outlined
option-value="value"
emit-value
map-options
v-model="filter.sale_status"
:options="StatusOption"
@input="onSelectStatus"
>
<template v-slot:before>
<div class="text-body2">依狀態查詢</div>
</template>
</q-select>
</div>
<div class="col-auto q-ml-md">
<q-input
outlined
dense
v-model="filter.keyword"
label="關鍵字查詢"
hide-bottom-space
@input="onKeywordInput"
>
<template v-slot:before>
<div class="text-body2">依標題查詢</div>
</template>
</q-input>
</div>
</div>
</div>
</div>
</q-card-section>
<q-card-section class="q-py-sm">
<MyTable
:columns="columns"
:data="data"
:actions="actions"
:filter="filter"
:total="total"
:actionView="true"
:actionStatus="false"
:actionDelete="true"
:actionOffline="false"
:actionFrontendStatus="true"
actionViewRouter="course/content"
@getData="getData"
@dataView="dataView"
@dataStatusChange="dataStatusChange"
@dataDelete="dataDelete"
@dataOffline="dataOffline"
/>
</q-card-section>
</q-card>
</div>
</template>
<script src="./index.js"></script>
```