parent
01ff237e03
commit
1b8746750f
@ -0,0 +1,77 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
// import "validate/validate.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
package api.v1;
|
||||
|
||||
option go_package = "moredoc/api/v1;v1";
|
||||
option java_multiple_files = true;
|
||||
option java_package = "api.v1";
|
||||
|
||||
message Banner {
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
string path = 3;
|
||||
int32 sort = 4;
|
||||
int32 status = 5;
|
||||
int32 type = 6;
|
||||
string url = 7;
|
||||
string description = 8;
|
||||
google.protobuf.Timestamp created_at = 9 [ (gogoproto.stdtime) = true ];
|
||||
google.protobuf.Timestamp updated_at = 10 [ (gogoproto.stdtime) = true ];
|
||||
}
|
||||
|
||||
message DeleteBannerRequest {repeated int64 id = 1; }
|
||||
|
||||
message GetBannerRequest { int64 id = 1; }
|
||||
|
||||
message ListBannerRequest {
|
||||
int64 page = 1;
|
||||
int64 size = 2;
|
||||
repeated int32 type = 3;
|
||||
repeated int32 status = 4;
|
||||
string wd = 5;
|
||||
}
|
||||
|
||||
message ListBannerReply {
|
||||
int64 total = 1;
|
||||
repeated Banner banner = 2;
|
||||
}
|
||||
|
||||
service BannerAPI {
|
||||
rpc CreateBanner(Banner) returns (Banner) {
|
||||
option (google.api.http) = {
|
||||
post : '/api/v1/banner',
|
||||
body : '*',
|
||||
};
|
||||
}
|
||||
|
||||
rpc UpdateBanner(Banner) returns (Banner) {
|
||||
option (google.api.http) = {
|
||||
put : '/api/v1/banner',
|
||||
body : '*',
|
||||
};
|
||||
}
|
||||
|
||||
rpc DeleteBanner(DeleteBannerRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
delete : '/api/v1/banner',
|
||||
};
|
||||
}
|
||||
|
||||
rpc GetBanner(GetBannerRequest) returns (Banner) {
|
||||
option (google.api.http) = {
|
||||
get : '/api/v1/banner',
|
||||
};
|
||||
}
|
||||
|
||||
rpc ListBanner(ListBannerRequest) returns (ListBannerReply) {
|
||||
option (google.api.http) = {
|
||||
get : '/api/v1/banner/list',
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pb "moredoc/api/v1"
|
||||
"moredoc/middleware/auth"
|
||||
"moredoc/model"
|
||||
"moredoc/util"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type BannerAPIService struct {
|
||||
pb.UnimplementedBannerAPIServer
|
||||
dbModel *model.DBModel
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewBannerAPIService(dbModel *model.DBModel, logger *zap.Logger) (service *BannerAPIService) {
|
||||
return &BannerAPIService{dbModel: dbModel, logger: logger.Named("BannerAPIService")}
|
||||
}
|
||||
|
||||
func (s *BannerAPIService) checkPermission(ctx context.Context) (*auth.UserClaims, error) {
|
||||
return checkGRPCPermission(s.dbModel, ctx)
|
||||
}
|
||||
|
||||
// CreateBanner 创建横幅
|
||||
func (s *BannerAPIService) CreateBanner(ctx context.Context, req *pb.Banner) (*pb.Banner, error) {
|
||||
_, err := s.checkPermission(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var banner model.Banner
|
||||
util.CopyStruct(req, &banner)
|
||||
err = s.dbModel.CreateBanner(&banner)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
pbBanner := &pb.Banner{}
|
||||
util.CopyStruct(&banner, pbBanner)
|
||||
|
||||
return pbBanner, nil
|
||||
}
|
||||
|
||||
// UpdateBanner 更新横幅
|
||||
func (s *BannerAPIService) UpdateBanner(ctx context.Context, req *pb.Banner) (*pb.Banner, error) {
|
||||
_, err := s.checkPermission(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var banner model.Banner
|
||||
util.CopyStruct(req, &banner)
|
||||
err = s.dbModel.UpdateBanner(&banner)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbBanner := &pb.Banner{}
|
||||
util.CopyStruct(&banner, pbBanner)
|
||||
|
||||
return pbBanner, nil
|
||||
}
|
||||
|
||||
func (s *BannerAPIService) DeleteBanner(ctx context.Context, req *pb.DeleteBannerRequest) (*emptypb.Empty, error) {
|
||||
_, err := s.checkPermission(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.dbModel.DeleteBanner(req.Id)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *BannerAPIService) GetBanner(ctx context.Context, req *pb.GetBannerRequest) (*pb.Banner, error) {
|
||||
fields := []string{"id", "title", "path", "url"}
|
||||
if _, errPermission := s.checkPermission(ctx); errPermission == nil {
|
||||
fields = []string{}
|
||||
}
|
||||
|
||||
banner, err := s.dbModel.GetBanner(req.Id, fields...)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
pbBanner := &pb.Banner{}
|
||||
util.CopyStruct(banner, pbBanner)
|
||||
return pbBanner, nil
|
||||
}
|
||||
|
||||
// GetBanners 获取横幅列表
|
||||
func (s *BannerAPIService) ListBanner(ctx context.Context, req *pb.ListBannerRequest) (*pb.ListBannerReply, error) {
|
||||
var opt = &model.OptionGetBannerList{
|
||||
Page: int(req.Page),
|
||||
Size: int(req.Size_),
|
||||
WithCount: true,
|
||||
SelectFields: []string{"id", "title", "path", "url"}, // 对于非权限用户,可查询的字段
|
||||
QueryIn: make(map[string][]interface{}),
|
||||
}
|
||||
|
||||
if len(req.Type) > 0 {
|
||||
opt.QueryIn["type"] = util.Slice2Interface(req.Type)
|
||||
}
|
||||
|
||||
_, errPermission := s.checkPermission(ctx)
|
||||
if errPermission != nil {
|
||||
opt.QueryIn["status"] = []interface{}{model.BannerStatusNormal} // 非权限用户,只能查询正常状态的横幅
|
||||
} else {
|
||||
opt.SelectFields = []string{} // 不限字段
|
||||
if len(req.Status) > 0 {
|
||||
opt.QueryIn["status"] = util.Slice2Interface(req.Status)
|
||||
}
|
||||
|
||||
if req.Wd != "" {
|
||||
opt.QueryLike = map[string][]interface{}{"title": {req.Wd}, "description": {req.Wd}}
|
||||
}
|
||||
}
|
||||
|
||||
banners, total, err := s.dbModel.GetBannerList(opt)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
var pbBanner []*pb.Banner
|
||||
util.CopyStruct(banners, &pbBanner)
|
||||
return &pb.ListBannerReply{Total: total, Banner: pbBanner}, nil
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import service from '~/utils/request'
|
||||
|
||||
export const createBanner = (data) => {
|
||||
return service({
|
||||
url: '/api/v1/banner',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateBanner = (data) => {
|
||||
return service({
|
||||
url: '/api/v1/banner',
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteBanner = (params) => {
|
||||
return service({
|
||||
url: '/api/v1/banner',
|
||||
method: 'delete',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export const getBanner = (params) => {
|
||||
return service({
|
||||
url: '/api/v1/banner',
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export const listBanner = (params) => {
|
||||
return service({
|
||||
url: '/api/v1/banner/list',
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="com-form-banner">
|
||||
<el-form
|
||||
ref="formBanner"
|
||||
label-position="top"
|
||||
label-width="80px"
|
||||
:model="banner"
|
||||
>
|
||||
<el-form-item
|
||||
label="图片"
|
||||
prop="path"
|
||||
:rules="[
|
||||
{ required: true, message: '请上传横幅图片', trigger: 'blur' },
|
||||
]"
|
||||
>
|
||||
<UploadImage
|
||||
:action="'/api/v1/upload/banner'"
|
||||
:image="banner.path"
|
||||
:width="'600px'"
|
||||
@success="success"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="名称"
|
||||
prop="title"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入横幅名称', trigger: 'blur' },
|
||||
]"
|
||||
>
|
||||
<el-input
|
||||
v-model="banner.title"
|
||||
clearable
|
||||
placeholder="请输入横幅名称"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="链接"
|
||||
prop="url"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入链接地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input
|
||||
v-model="banner.url"
|
||||
clearable
|
||||
placeholder="请输入链接地址"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select
|
||||
v-model="banner.type"
|
||||
clearable
|
||||
placeholder="请选择横幅类型"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in bannerTypeOptions"
|
||||
:key="'type-' + opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="排序(值越大越靠前)" prop="sort">
|
||||
<el-input-number
|
||||
v-model="banner.sort"
|
||||
:min="0"
|
||||
:step="1"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="是否启用" prop="status">
|
||||
<el-switch
|
||||
v-model="banner.status"
|
||||
style="display: block; margin-top: 8px"
|
||||
active-color="#ff4949"
|
||||
inactive-color="#13ce66"
|
||||
active-text="否"
|
||||
inactive-text="是"
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="描述">
|
||||
<el-input
|
||||
v-model="banner.description"
|
||||
type="textarea"
|
||||
rows="5"
|
||||
placeholder="请输入附件相关描述或备注"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
class="btn-block"
|
||||
icon="el-icon-check"
|
||||
:loading="loading"
|
||||
@click="onSubmit"
|
||||
>提交</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import UploadImage from './UploadImage.vue'
|
||||
import { createBanner, updateBanner } from '~/api/banner'
|
||||
import { bannerTypeOptions } from '~/utils/enum'
|
||||
|
||||
export default {
|
||||
name: 'FormBanner',
|
||||
components: { UploadImage },
|
||||
props: {
|
||||
initBanner: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
id: 0,
|
||||
title: '',
|
||||
description: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
banner: {
|
||||
id: 0,
|
||||
title: '',
|
||||
description: '',
|
||||
path: '',
|
||||
type: 0,
|
||||
status: 0,
|
||||
},
|
||||
bannerTypeOptions,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
initBanner: {
|
||||
handler(val) {
|
||||
const banner = { ...this.banner, ...val }
|
||||
this.banner = banner
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const banner = { ...this.banner, ...this.initBanner }
|
||||
this.banner = banner
|
||||
},
|
||||
methods: {
|
||||
onSubmit() {
|
||||
this.$refs.formBanner.validate(async (valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
const banner = { ...this.banner }
|
||||
banner.status = banner.status ? 1 : 0
|
||||
if (this.banner.id > 0) {
|
||||
const res = await updateBanner(banner)
|
||||
if (res.status === 200) {
|
||||
this.$message.success('修改成功')
|
||||
this.resetFields()
|
||||
this.$emit('success', res.data)
|
||||
} else {
|
||||
this.$message.error(res.data.message)
|
||||
}
|
||||
} else {
|
||||
const res = await createBanner(banner)
|
||||
if (res.status === 200) {
|
||||
this.$message.success('添加成功')
|
||||
this.resetFields()
|
||||
this.$emit('success', res.data)
|
||||
} else {
|
||||
this.$message.error(res.data.message)
|
||||
}
|
||||
}
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
clearValidate() {
|
||||
this.$refs.formBanner.clearValidate()
|
||||
},
|
||||
resetFields() {
|
||||
this.$refs.formBanner.resetFields()
|
||||
},
|
||||
reset() {
|
||||
this.resetFields()
|
||||
this.clearValidate()
|
||||
},
|
||||
success(res) {
|
||||
this.banner.path = res.data.path
|
||||
console.log(res)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="com-upload-image">
|
||||
<el-upload
|
||||
class="image-uploader"
|
||||
:action="action"
|
||||
:headers="{ authorization: `bearer ${token}` }"
|
||||
:show-file-list="false"
|
||||
:on-success="success"
|
||||
accept="image/jpeg,image/png,image/gif,image/jpg"
|
||||
:multiple="false"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<el-image
|
||||
v-if="disabled"
|
||||
:src="image"
|
||||
:style="'width:' + width + ';height:' + height"
|
||||
>
|
||||
<div slot="error" class="image-slot">
|
||||
<img :src="errorImage" />
|
||||
</div>
|
||||
</el-image>
|
||||
<el-tooltip v-else content="点击上传图片" placement="top">
|
||||
<el-image :src="image" :style="'width:' + width + ';height:' + height">
|
||||
<div slot="error" class="image-slot">
|
||||
<img :src="errorImage" />
|
||||
</div>
|
||||
</el-image>
|
||||
</el-tooltip>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'FormNotebookCover',
|
||||
props: {
|
||||
action: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
errorImage: {
|
||||
type: String,
|
||||
default: '/static/images/blank.png',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
profile: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('user', ['token']),
|
||||
},
|
||||
methods: {
|
||||
success(res) {
|
||||
this.$emit('success', res)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,10 +1,236 @@
|
||||
<template>
|
||||
<div>{{ $route.name }}</div>
|
||||
<div>
|
||||
<el-card shadow="never" class="search-card">
|
||||
<FormSearch
|
||||
:fields="searchFormFields"
|
||||
:loading="loading"
|
||||
:show-create="true"
|
||||
:show-delete="true"
|
||||
:disabled-delete="selectedRow.length === 0"
|
||||
@onCreate="onCreate"
|
||||
@onSearch="onSearch"
|
||||
@onDelete="batchDelete"
|
||||
/>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="mgt-20px">
|
||||
<TableList
|
||||
:table-data="listData"
|
||||
:fields="tableListFields"
|
||||
:show-actions="true"
|
||||
:show-view="false"
|
||||
:show-edit="true"
|
||||
:show-delete="true"
|
||||
:show-select="true"
|
||||
@selectRow="selectRow"
|
||||
@editRow="editRow"
|
||||
@deleteRow="deleteRow"
|
||||
/>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="mgt-20px">
|
||||
<div class="text-right">
|
||||
<el-pagination
|
||||
background
|
||||
:current-page="search.page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="search.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog
|
||||
width="640px"
|
||||
:title="banner.id > 0 ? '编辑横幅' : '新增横幅'"
|
||||
:visible.sync="formVisible"
|
||||
>
|
||||
<FormBanner :init-banner="banner" @success="formSuccess" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listBanner, deleteBanner } from '~/api/banner'
|
||||
import TableList from '~/components/TableList.vue'
|
||||
import FormSearch from '~/components/FormSearch.vue'
|
||||
import FormBanner from '~/components/FormBanner.vue'
|
||||
import { bannerTypeOptions } from '~/utils/enum'
|
||||
export default {
|
||||
components: { TableList, FormSearch, FormBanner },
|
||||
layout: 'admin',
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
formVisible: false,
|
||||
search: {
|
||||
wd: '',
|
||||
page: 1,
|
||||
status: [],
|
||||
size: 10,
|
||||
},
|
||||
listData: [],
|
||||
total: 0,
|
||||
searchFormFields: [],
|
||||
tableListFields: [],
|
||||
selectedRow: [],
|
||||
banner: {},
|
||||
bannerTypeOptions,
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.initSearchForm()
|
||||
this.initTableListFields()
|
||||
await this.listBanner()
|
||||
},
|
||||
methods: {
|
||||
async listBanner() {
|
||||
this.loading = true
|
||||
const res = await listBanner(this.search)
|
||||
if (res.status === 200) {
|
||||
this.listData = res.data.banner
|
||||
this.total = res.data.total
|
||||
} else {
|
||||
this.$message.error(res.data.message)
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.search.size = val
|
||||
this.listBanner()
|
||||
},
|
||||
handlePageChange(val) {
|
||||
this.search.page = val
|
||||
this.listBanner()
|
||||
},
|
||||
onSearch(search) {
|
||||
this.search = { ...this.search, page: 1, ...search }
|
||||
this.listBanner()
|
||||
},
|
||||
onCreate() {
|
||||
this.banner = {}
|
||||
this.formVisible = true
|
||||
},
|
||||
editRow(row) {
|
||||
this.formVisible = true
|
||||
this.banner = row
|
||||
},
|
||||
formSuccess() {
|
||||
this.formVisible = false
|
||||
this.listBanner()
|
||||
},
|
||||
batchDelete() {
|
||||
this.$confirm(
|
||||
`您确定要删除选中的【${this.selectedRow.length}个】横幅吗?删除之后不可恢复!`,
|
||||
'温馨提示',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
const ids = this.selectedRow.map((item) => item.id)
|
||||
const res = await deleteBanner({ id: ids })
|
||||
if (res.status === 200) {
|
||||
this.$message.success('删除成功')
|
||||
this.listBanner()
|
||||
} else {
|
||||
this.$message.error(res.data.message)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
deleteRow(row) {
|
||||
this.$confirm(
|
||||
`您确定要删除横幅【${row.title}】吗?删除之后不可恢复!`,
|
||||
'温馨提示',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
const res = await deleteBanner({ id: row.id })
|
||||
if (res.status === 200) {
|
||||
this.$message.success('删除成功')
|
||||
this.listBanner()
|
||||
} else {
|
||||
this.$message.error(res.data.message)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
selectRow(rows) {
|
||||
this.selectedRow = rows
|
||||
},
|
||||
initSearchForm() {
|
||||
this.searchFormFields = [
|
||||
{
|
||||
type: 'text',
|
||||
label: '关键字',
|
||||
name: 'wd',
|
||||
placeholder: '请输入关键字',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '类型',
|
||||
name: 'type',
|
||||
placeholder: '请选择横幅类型',
|
||||
multiple: true,
|
||||
options: this.bannerTypeOptions,
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '状态',
|
||||
name: 'status',
|
||||
placeholder: '是否启用',
|
||||
multiple: true,
|
||||
options: [
|
||||
{ label: '启用', value: 0 },
|
||||
{ label: '禁用', value: 1 },
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
initTableListFields() {
|
||||
const typeMap = {}
|
||||
this.bannerTypeOptions.forEach((item) => {
|
||||
typeMap[item.value] = item
|
||||
})
|
||||
const statusMap = {
|
||||
0: { label: '启用', value: 0, type: 'success' },
|
||||
1: { label: '禁用', value: 1, type: 'danger' },
|
||||
}
|
||||
this.tableListFields = [
|
||||
{ prop: 'id', label: 'ID', width: 80, type: 'number' },
|
||||
{ prop: 'path', label: '横幅', width: 360, type: 'banner' },
|
||||
{
|
||||
prop: 'type',
|
||||
label: '类型',
|
||||
width: 120,
|
||||
type: 'enum',
|
||||
enum: typeMap,
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 80,
|
||||
type: 'enum',
|
||||
enum: statusMap,
|
||||
},
|
||||
{ prop: 'title', label: '名称', minWidth: 150 },
|
||||
{ prop: 'url', label: '链接', minWidth: 150, type: 'link' },
|
||||
{ prop: 'sort', label: '排序', width: 80, type: 'number' },
|
||||
{ prop: 'description', label: '备注', width: 200 },
|
||||
{ prop: 'created_at', label: '创建时间', width: 160, type: 'datetime' },
|
||||
{ prop: 'updated_at', label: '更新时间', width: 160, type: 'datetime' },
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
|
Loading…
Reference in new issue