Browse Source

feat: 界面完成

min
song 4 years ago
parent
commit
a73f14c3e9
  1. 41
      package-lock.json
  2. 1
      package.json
  3. 19
      src/components/breadcrumb.vue
  4. 19
      src/components/leftMenu.vue
  5. 121
      src/components/listPlugin.vue
  6. 54
      src/components/listSearchBar.vue
  7. 106
      src/components/listTable.vue
  8. 2
      src/components/navbar.vue
  9. 2
      src/components/searchBar.vue
  10. 17
      src/routers/index.js
  11. 3
      src/store/index.js
  12. 26
      src/store/plugin.js
  13. 117
      src/views/index-list/add-business.vue
  14. 205
      src/views/index-list/add-plugin.vue
  15. 117
      src/views/index-list/business-detail.vue
  16. 21
      src/views/index-list/business-list.vue
  17. 24
      src/views/index-list/plugin-list.vue
  18. 104
      src/views/index-list/plugin-shop.vue

41
package-lock.json

@ -2573,6 +2573,16 @@
"integrity": "sha1-sEM9C06chH7xiGik7xb9X8gnHEg=",
"dev": true
},
"clipboard": {
"version": "2.0.8",
"resolved": "https://registry.npmmirror.com/clipboard/download/clipboard-2.0.8.tgz",
"integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npm.taobao.org/cliui/download/cliui-7.0.4.tgz?cache=0&sync_timestamp=1604880226973&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-7.0.4.tgz",
@ -3033,6 +3043,11 @@
"object-keys": "^1.0.12"
}
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.nlark.com/delegate/download/delegate-3.2.0.tgz",
"integrity": "sha1-tmtxwxWFIuirV0T3INjKDCr1kWY="
},
"detect-file": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/detect-file/download/detect-file-1.0.0.tgz",
@ -4018,6 +4033,14 @@
"type-fest": "^0.20.2"
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.nlark.com/good-listener/download/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.nlark.com/graceful-fs/download/graceful-fs-4.2.8.tgz",
@ -5715,6 +5738,11 @@
"integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
"dev": true
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.nlark.com/select/download/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.nlark.com/semver/download/semver-7.3.5.tgz",
@ -6095,6 +6123,11 @@
"readable-stream": "3"
}
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.nlark.com/tiny-emitter/download/tiny-emitter-2.1.0.tgz",
"integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz",
@ -6527,6 +6560,14 @@
"@vue/shared": "3.2.20"
}
},
"vue-clipboard3": {
"version": "1.0.1",
"resolved": "https://registry.nlark.com/vue-clipboard3/download/vue-clipboard3-1.0.1.tgz",
"integrity": "sha1-OeMfv0HxHTcBszcuOKf7g7SEeWo=",
"requires": {
"clipboard": "^2.0.6"
}
},
"vue-demi": {
"version": "0.11.4",
"resolved": "https://registry.nlark.com/vue-demi/download/vue-demi-0.11.4.tgz",

1
package.json

@ -25,6 +25,7 @@
"vite-plugin-compression": "^0.3.5",
"vite-plugin-windicss": "^1.4.11",
"vue": "^3.2.16",
"vue-clipboard3": "^1.0.1",
"vue-router": "^4.0.12",
"vuex": "^4.0.2",
"windicss": "^3.1.9"

19
src/components/breadcrumb.vue

@ -0,0 +1,19 @@
<template>
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(item, index) in path" :key="index">
<span @click="router.push({ name: item.name })" v-if="index !== path.length - 1" class="font-bold cursor-pointer">{{
item.title
}}</span>
<span v-else>{{ item.title }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { defineProps } from 'vue';
const router = useRouter();
defineProps({ path: { default: () => [], type: Array } });
</script>

19
src/components/leftMenu.vue

@ -1,29 +1,32 @@
<template>
<el-menu :default-active="data.activeIndex" class="el-menu-demo" mode="vertical" @select="handleSelect">
<el-menu-item :index="index" @click="openPage(list.name)" v-for="(list, index) in data.menus" :key="index">{{
list.title
}}</el-menu-item>
<el-menu :default-active="leftIndex" class="el-menu-demo" mode="vertical" @select="handleSelect">
<el-menu-item :index="index" @click="openPage(list.name)" v-for="(list, index) in data.menus" :key="index">
{{ list.title }}
</el-menu-item>
</el-menu>
</template>
<script setup>
import { reactive } from 'vue';
import { useStore } from 'vuex';
import { reactive, computed } from 'vue';
import { useRouter } from 'vue-router';
const store = useStore();
const leftIndex = computed(() => store.state.plugin.leftIndex);
const router = useRouter();
const data = reactive({
activeIndex: 2,
menus: [
{ title: '概览', name: '' },
{ title: '创建业务', name: 'desk-add-business' },
{ title: '创建插件', name: 'desk-add-plugin' },
{ title: '我的业务', name: 'desk-business-list' },
{ title: '我的插件', name: 'desk-plugin-shop' },
{ title: '我的插件', name: 'desk-plugin-list' },
],
});
function handleSelect(e) {
console.log(e);
store.commit('plugin/setLeftIndex', e);
}
//

121
src/components/listPlugin.vue

@ -0,0 +1,121 @@
<template>
<div class="shop-content flex py-5" v-for="list in lists" :key="list.id">
<img :src="list.preview" alt="" class="shop-left" />
<div class="shop-right ml-8">
<div>
<span class="text-xl font-semibold">{{ list.name }}</span> <span class="ml-5 text-sm">{{ list.versions }}</span>
</div>
<div class="mt-4 desc text-sm">
<span> 描述</span> <span>{{ list.intro }}</span>
</div>
<div class="mt-5 text-sm">
<el-tag v-for="item in list.tags" :type="item.btnType" class="mr-3" :key="item.name">{{ item.name }}</el-tag>
</div>
<div class="mt-5 text-sm">
<span>行业:</span> <span>{{ list.industryName }}</span> <span class="ml-8">分类:</span> <span>{{ list.sortName }}</span>
</div>
<div class="mt-4 text-sm">
<span>更新日期:</span> <span>{{ list.updateTime }}</span> <span class="ml-8">作者:</span> <span>{{ list.authorName }}</span>
</div>
<div class="mt-6">
<el-button type="primary">下载源代码</el-button>
<el-button type="primary">下载示例代码</el-button>
<el-button type="primary">添加到业务</el-button>
<el-button type="primary" v-if="showConfig">配置</el-button>
</div>
</div>
</div>
<div class="pagination mt-15 flex flex-row-reverse">
<el-config-provider :locale="zhCn">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-size="pageSize"
layout="prev, pager, next, sizes, jumper"
:total="total"
:page-sizes="[10, 20, 30, 40, 50]"
>
</el-pagination>
</el-config-provider>
</div>
</template>
<script lang="ts" setup="true">
import { defineProps, defineEmits } from 'vue';
import { ElConfigProvider } from 'element-plus';
import zhCn from 'element-plus/lib/locale/lang/zh-cn';
defineProps({
lists: { default: () => [], type: Array },
currentPage: { default: 1, type: Number },
pageSize: { default: 10, type: Number },
total: { default: 0, type: Number },
showConfig: { default: false, type: Boolean },
});
const emit = defineEmits(['handleSizeChange', 'handleCurrentChange']);
function handleSizeChange(val) {
emit('handleSizeChange', val);
}
function handleCurrentChange(val) {
emit('handleCurrentChange', val);
}
</script>
<style scoped>
.el-input {
width: 20%;
margin-right: 2rem;
}
.el-select {
margin-right: 2rem;
width: 20%;
}
.desc {
height: 30px;
line-height: 15px;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.shop-left {
width: 288px;
height: 263px;
}
.pagination >>> .el-pager li,
.pagination >>> .btn-prev,
.pagination >>> .btn-next {
border: 1px solid #ccc;
width: 2rem;
height: 2rem;
line-height: 2rem;
text-align: center;
padding: 0;
margin: 0 8px;
border-radius: 6px;
font-weight: normal;
}
.pagination >>> .el-pager li.active {
border: 1px solid #409eff;
color: #fff;
background: #409eff;
}
.pagination >>> .el-input__inner {
height: 2rem;
line-height: 2rem;
border: 1px solid #ccc;
border-radius: 6px !important;
}
.pagination >>> .el-pagination__jump {
margin-left: 0;
}
</style>

54
src/components/listSearchBar.vue

@ -0,0 +1,54 @@
<template>
<div class="flex flex-row justify-space-between items-center">
<div class="flex flex-row items-center">
<div>业务名称</div>
<el-input v-model="data.keywords" placeholder="请输入业务名称或标签搜索" class="search-input mr-10" />
<div>状态</div>
<el-select v-model="data.status" placeholder="请选择" class="search-input" @change="changeState">
<el-option v-for="item in data.statusList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</div>
<div class="flex-1 ml-10">
<el-button type="primary" size="small" class="w-60px h-40px">查询</el-button>
<el-button size="small" class="w-60px h-40px reset">重置</el-button>
</div>
</div>
</template>
<script lang="ts" setup="true">
import { reactive } from 'vue';
const data = reactive({
keywords: '',
status: '',
statusList: [
{
value: '状态一',
label: '状态一',
},
{
value: '状态二',
label: '状态二',
},
{
value: '状态三',
label: '状态三',
},
],
});
function changeState(e) {
console.log('e: ', e);
data.status = e;
}
</script>
<style scoped>
.search-input {
width: 18rem;
}
.reset {
margin-left: 0.75rem;
}
</style>

106
src/components/listTable.vue

@ -0,0 +1,106 @@
<template>
<el-table :data="data.tableData" class="bg-title" style="width: 100%">
<el-table-column prop="name" label="业务名称"> </el-table-column>
<el-table-column prop="appId" label="APPID" width="300"> </el-table-column>
<el-table-column prop="startUsing" label="状态" key="slot" sortable>
<template #default="scope">
<div class="flex flex-row items-center" @click="change(scope.row)">
<div class="point bg-green-500"></div>
<span style="margin-left: 10px">启用</span>
</div>
</template>
</el-table-column>
<el-table-column label="公开" sortable key="slot" width="180">
<template #default="scope">
<div class="flex flex-row items-center" @click="change(scope.row)">
<div class="point bg-red-500"></div>
<span style="margin-left: 10px">公开</span>
</div>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建日期" sortable> </el-table-column>
<el-table-column label="操作" key="slot">
<template #default="scope">
<el-button type="text" size="small">删除</el-button>
<el-button type="text" size="small">配置</el-button>
<el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { reactive } from 'vue';
import { useStore } from 'vuex';
const router = useRouter();
const store = useStore();
const data = reactive({
tableData: [
{
appId: '描述01',
createTime: '2016-05-02',
id: '1',
name: '王小虎',
pub: 0,
startUsing: 0,
},
{
appId: '描述02',
createTime: '2016-05-04',
id: '2',
name: '王小虎',
pub: 1,
startUsing: 1,
},
{
appId: '描述03',
createTime: '2016-05-01',
id: '3',
name: '王小虎',
pub: 0,
startUsing: 1,
},
{
appId: '描述04',
createTime: '2016-05-03',
id: '4',
name: '王小虎',
pub: 1,
startUsing: 0,
},
],
});
function change(row) {
console.log('row: ', row);
}
function handleClick(row) {
console.log(row);
router.push({ name: 'business-detail', query: { id: row.id } });
store.commit('plugin/setBusinessInfo', row);
}
</script>
<style scoped>
.bg-title >>> thead tr th {
color: #333;
background: #fafafa;
border-top: 1px solid #e8e8e8;
}
.bg-title >>> thead tr th:first-child {
border-left: 1px solid #e8e8e8;
}
.bg-title >>> thead tr th:last-child {
border-right: 1px solid #e8e8e8;
}
.point {
width: 6px;
height: 6px;
border-radius: 50%;
}
</style>

2
src/components/navbar.vue

@ -17,7 +17,7 @@
}}</el-menu-item>
</el-menu>
<div class="flex items-center" style="color: #a5adb5">
<div @click="openPage('desk-business-list')" class="text-sm">控制台</div>
<div @click="openPage('desk-business-list')" class="text-sm cursor-pointer">控制台</div>
<i class="el-icon-bell mx-6"></i>
</div>
<el-dropdown>

2
src/components/searchBar.vue

@ -26,7 +26,7 @@
</div>
<div class="line"></div>
<div class="types">
所属行业:
所属分类:
<div
class="type"
:class="sort.checked ? 'check' : ''"

17
src/routers/index.js

@ -49,20 +49,15 @@ const router = createRouter({
name: 'plugin-shop',
component: () => import('views/index-list/plugin-shop.vue'),
},
{
path: '/store/home/add-plugin',
name: 'add-plugin',
component: () => import('views/index-list/add-plugin.vue'),
},
{
path: '/store/home/console-desk',
name: 'console-desk',
component: () => import('views/index-list/console-desk.vue'),
children: [
{
path: '/store/home/console-desk/plugin-shop',
name: 'desk-plugin-shop',
component: () => import('views/index-list/plugin-shop.vue'),
path: '/store/home/console-desk/plugin-list',
name: 'desk-plugin-list',
component: () => import('views/index-list/plugin-list.vue'),
},
{
path: '/store/home/console-desk/add-plugin',
@ -81,8 +76,14 @@ const router = createRouter({
},
],
},
{
path: '/store/home/business-detail',
name: 'business-detail',
component: () => import('views/index-list/business-detail.vue'),
},
],
},
...user,
],
});

3
src/store/index.js

@ -1,8 +1,9 @@
import { createStore } from 'vuex';
import user from './user';
import plugin from './plugin';
export default createStore({
modules: { user },
modules: { user, plugin },
state: { menu: { show: true, collapse: false } },
getters: {},
mutations: {

26
src/store/plugin.js

@ -0,0 +1,26 @@
export default {
namespaced: true,
state: { leftIndex: 3, businessInfo: {} },
getters: {},
mutations: {
/**
* 设置控制台左侧菜单栏
* @param {*} state
* @param {number} data
*/
setLeftIndex(state, data) {
state.leftIndex = data;
},
/**
* 设置当前查看的业务信息
* @param {*} state
* @param {object|null} data
*/
setBusinessInfo(state, data) {
state.businessInfo = data;
},
},
actions: {},
};

117
src/views/index-list/add-business.vue

@ -1,3 +1,116 @@
<template>创建业务</template>
<template>
<div class="box">
<h1 class="text-lg font-semibold">配置业务</h1>
<el-form ref="formRef" :model="form" :rules="rules" label-width="150px" class="forms">
<el-form-item prop="name">
<template v-slot:label>
<el-tooltip class="box-item" effect="dark" content="输入帮助" placement="top-end">
<div>业务名称</div>
</el-tooltip>
</template>
<el-input v-model="form.name" placeholder="输入业务名称"></el-input>
</el-form-item>
<el-form-item label="行业:" prop="region">
<el-select v-model="form.region" placeholder="请选择">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分类:" prop="sort">
<el-select v-model="form.sort" multiple placeholder="请选择,可多选">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
<el-form-item label="标签:" prop="tags">
<el-select v-model="form.tags" multiple filterable allow-create default-first-option placeholder="请选择标签">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="描述:" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item label="是否公开:" prop="pub">
<el-switch v-model="form.pub" class="mr-3"></el-switch>
</el-form-item>
<el-form-item label="是否启用:" prop="startUsing">
<el-switch v-model="form.startUsing" class="mr-3"></el-switch>
</el-form-item>
<!-- <el-form-item label="是否开启debug模式:" prop="debug">
<el-switch v-model="form.debug" class="mr-3"></el-switch>
</el-form-item> -->
<el-form-item> <el-switch v-model="form.debug" class="mr-3"></el-switch> 是否开启debug模式 </el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit()">发布</el-button>
<el-button @click="resetForm()">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<style></style>
<script setup>
import { ref, reactive } from 'vue';
const formRef = ref(null);
const form = reactive({
name: '',
region: '',
sort: '',
tags: '',
description: '',
pub: false,
startUsing: false,
debug: false,
});
const rules = {
name: [{ required: true, message: '输入业务名称', trigger: 'blur' }],
region: [{ required: true, message: '请选择行业', trigger: 'blur' }],
sort: [{ required: true, message: '请选择分类', trigger: 'blur' }],
};
const onSubmit = () => {
formRef.value.validate(true);
};
const resetForm = () => {
formRef.value.resetFields();
};
const options = [
{
value: 'HTML',
label: 'HTML',
},
{
value: 'CSS',
label: 'CSS',
},
{
value: 'JavaScript',
label: 'JavaScript',
},
];
</script>
<style scoped>
.el-form-item {
margin-top: 1rem;
}
.tags {
width: 100%;
}
.el-select {
width: 100%;
}
.box >>> .el-form-item__label {
display: flex;
flex-direction: row-reverse;
justify-content: end;
flex: 0 0 auto;
text-align: right;
font-size: var(--el-form-label-font-size);
color: var(--el-text-color-regular);
line-height: 40px;
padding: 0 12px 0 0;
box-sizing: border-box;
}
</style>

205
src/views/index-list/add-plugin.vue

@ -1,52 +1,85 @@
<template>
<div class="box">
<h1 class="text-xl mt-10 font-semibold">上传插件</h1>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" class="forms">
<div class="flex">
<el-form-item class="font-semibold flex-1" prop="name">
<template v-slot:label>
<el-tooltip class="box-item" effect="dark" content="输入帮助" placement="top-end">
<div>插件名称 </div>
</el-tooltip>
</template>
<el-input v-model="form.name" placeholder="输入插件名称"></el-input>
</el-form-item>
<el-form-item label="版本:" class="font-semibold flex-1" prop="edition">
<el-input v-model="form.edition" placeholder="请输入"></el-input>
</el-form-item>
</div>
<el-form-item label="描述(可选):" class="font-semibold" prop="desc">
<el-input v-model="form.desc" type="textarea" placeholder="请输入备注"></el-input>
<h1 class="text-lg font-semibold">上传插件</h1>
<el-form ref="formRef" :model="form" :rules="rules" label-width="150px" class="forms">
<el-form-item prop="name">
<template v-slot:label>
<el-tooltip class="box-item" effect="dark" content="输入帮助" placement="top-end">
<div>插件名称 </div>
</el-tooltip>
</template>
<el-input v-model="form.name" placeholder="输入插件名称"></el-input>
</el-form-item>
<div class="flex">
<el-form-item label="行业:" class="font-semibold flex-1" prop="region">
<el-select v-model="form.region" placeholder="请选择">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分类:" class="font-semibold flex-1" prop="sort">
<el-select v-model="form.sort" multiple placeholder="请选择,可多选">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
</div>
<el-form-item label="标签:" class="font-semibold" prop="tags">
<el-form-item label="版本:" prop="versions">
<el-input v-model="form.versions" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="简介:" prop="intro">
<el-input v-model="form.intro" type="textarea" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item label="行业:" prop="region">
<el-select v-model="form.region" placeholder="请选择">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分类:" prop="sort">
<el-select v-model="form.sort" multiple placeholder="请选择,可多选">
<el-option value="Zone one"></el-option>
<el-option value="Zone two"></el-option>
</el-select>
</el-form-item>
<el-form-item label="标签:" prop="tags">
<el-select v-model="form.tags" multiple filterable allow-create default-first-option placeholder="请选择标签">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="HTML:" class="font-semibold" prop="htmlCodes">
<el-input v-model="form.htmlCodes" type="textarea" placeholder="请输入HTML代码片段"></el-input>
<el-form-item label="HTML:" prop="html">
<el-input v-model="form.html" type="textarea" placeholder="请输入HTML代码片段"></el-input>
</el-form-item>
<el-form-item label="JS:" prop="js">
<el-input v-model="form.js" type="textarea" placeholder="请输入JS代码片段"></el-input>
</el-form-item>
<el-form-item label="CSS:" prop="css">
<el-input v-model="form.css" type="textarea" placeholder="请输入CSS代码片段"></el-input>
</el-form-item>
<el-form-item label="JS:" class="font-semibold" prop="jsCodes">
<el-input v-model="form.jsCodes" type="textarea" placeholder="请输入JS代码片段"></el-input>
<el-form-item label="配置文件:" prop="config">
<el-input v-model="form.config" type="textarea" placeholder="请输入CSS代码片段"></el-input>
</el-form-item>
<el-form-item label="CSS:" class="font-semibold" prop="cssCodes">
<el-input v-model="form.cssCodes" type="textarea" placeholder="请输入CSS代码片段"></el-input>
<el-form-item label="上传预览图:" prop="preview">
<el-upload
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="form.preview" :src="form.preview" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item> <el-switch v-model="form.delivery" class="mr-3"></el-switch> 是否压缩代码 </el-form-item>
<el-form-item prop="carousel">
<template v-slot:label>
<el-tooltip class="box-item" effect="dark" content="输入帮助" placement="top-end">
<div>上传轮播图 </div>
</el-tooltip>
</template>
<el-upload
class="upload-dialog"
action="https://jsonplaceholder.typicode.com/posts/"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="form.dialogVisible">
<img width="100%" :src="form.carousel" alt="" />
</el-dialog>
</el-form-item>
<el-form-item label="README:" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入markdown详细介绍信息"></el-input>
</el-form-item>
<!-- <el-form-item> <el-switch v-model="form.delivery" class="mr-3"></el-switch> 是否压缩代码 </el-form-item> -->
<el-form-item>
<el-button type="primary" @click="onSubmit()">发布</el-button>
<el-button @click="resetForm()">重置</el-button>
@ -57,30 +90,35 @@
<script setup>
import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
const formRef = ref(null);
const form = reactive({
name: '',
edition: '',
desc: '',
versions: '',
intro: '',
region: '',
sort: '',
tags: '',
htmlCodes: '',
jsCodes: '',
cssCodes: '',
html: '',
js: '',
css: '',
config: '',
delivery: '',
preview: '',
carousel: '',
dialogVisible: false,
description: '',
});
const rules = {
name: [{ required: true, message: '请输入插件名称', trigger: 'blur' }],
edition: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
versions: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
region: [{ required: true, message: '请选择行业', trigger: 'blur' }],
sort: [{ required: true, message: '请选择分类', trigger: 'blur' }],
tags: [{ required: true, message: '请选择标签', trigger: 'blur' }],
htmlCodes: [{ required: true, message: '请输入HTML代码', trigger: 'blur' }],
jsCodes: [{ required: true, message: '请输入JS代码', trigger: 'blur' }],
preview: [{ required: true, message: '请上传预览图', trigger: 'blur' }],
carousel: [{ required: true, message: '请上传轮播图', trigger: 'blur' }],
};
const onSubmit = () => {
@ -103,11 +141,38 @@ const options = [
label: 'JavaScript',
},
];
function handleAvatarSuccess(res, file) {
form.preview = URL.createObjectURL(file.raw);
}
function beforeAvatarUpload(file) {
console.log('file: ', file);
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
ElMessage.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
ElMessage.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
function handleRemove(file, fileList) {
console.log(file, fileList);
}
function handlePictureCardPreview(file) {
form.carousel = file.url;
form.dialogVisible = true;
}
</script>
<style>
<style scoped>
.box {
padding-left: 5%;
/* padding-left: 5%; */
}
.el-form-item {
margin-top: 1rem;
@ -118,8 +183,9 @@ const options = [
.el-select {
width: 100%;
}
.el-form-item__label {
.box >>> .el-form-item__label {
display: flex;
flex-direction: row-reverse;
justify-content: end;
flex: 0 0 auto;
text-align: right;
@ -129,4 +195,41 @@ const options = [
padding: 0 12px 0 0;
box-sizing: border-box;
}
.avatar-uploader >>> .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader >>> .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 104px;
height: 104px;
line-height: 104px;
text-align: center;
background: #fafafa;
}
.avatar {
width: 104px;
height: 104px;
display: block;
}
.upload-dialog >>> .el-upload--picture-card {
width: 104px;
height: 104px;
line-height: 104px;
background: #fafafa;
}
.upload-dialog >>> .el-upload-list--picture-card .el-upload-list__item {
width: 104px;
height: 104px;
}
</style>

117
src/views/index-list/business-detail.vue

@ -0,0 +1,117 @@
<template>
<breadcrumb :path="data.path" />
<div class="pt-12">
<h1 class="text-lg font-semibold">业务名称</h1>
<div class="flex flex-col">
<div class="mt-3">
APPID: {{ businessInfo.appId }}
<i class="el-icon-document-copy cursor-pointer ml-2" @click="copy(businessInfo.appId)"></i>
</div>
<div class="mt-3">APPSecret: {{ businessInfo.secret }}</div>
<div class="mt-3">简介: {{ businessInfo.description }}</div>
<div class="flex flex-row mt-3">
<div class="text-sm mr-20" v-if="businessInfo.tags && businessInfo.tags.length">
<el-tag v-for="item in businessInfo.tags" :type="item.btnType" class="mr-3" :key="item.name">{{ item.name }}</el-tag>
</div>
<div>行业: {{ businessInfo.appId }}</div>
</div>
<div class="flex flex-row mt-3">
<div class="mr-20">创建时间: {{ businessInfo.createTime }}</div>
<div>最新更新时间: {{ businessInfo.createTime }}</div>
</div>
</div>
<div class="flex flex-col py-12">
<div class="flex flex-nowrap justify-between">
<h1 class="text-lg font-semibold">已绑定插件</h1>
<el-button type="primary" @click="openPage">添加插件</el-button>
</div>
<listPlugin
:lists="data.lists"
:currentPage="data.currentPage"
:pageSize="data.pageSize"
:total="data.total"
:showConfig="true"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
/>
</div>
</div>
</template>
<script setup>
import useClipboard from 'vue-clipboard3';
import { reactive, computed } from 'vue';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
const store = useStore();
const router = useRouter();
const businessInfo = computed(() => store.state.plugin.businessInfo);
const { toClipboard } = useClipboard();
const data = reactive({
path: [
{ title: '控制台', name: 'plugin-shop' },
{ title: '我的业务', name: 'desk-business-list' },
{ title: '业务详情', name: 'desk-add-business' },
],
lists: [
{
id: '1',
name: '插件名称',
versions: 'V1.0.0',
intro: 'In my dual profession as an educator and health care',
updateTime: '2021年12月20日',
authorName: '张三',
preview: 'https://s4.ax1x.com/2022/01/17/7abX3d.png',
mine: true,
tags: [
{ btnType: 'primary', name: '医疗' },
{ btnType: 'success', name: '打卡' },
{ btnType: 'warning', name: '签到' },
],
industryName: '数字医疗',
sortName: '医疗',
},
],
currentPage: 1,
pageSize: 10,
total: 55,
});
//
function openPage() {
router.push({ name: 'desk-add-plugin' });
store.commit('plugin/setLeftIndex', 2);
}
function handleSizeChange(val) {
console.log(val);
data.pageSize = val;
}
function handleCurrentChange(val) {
console.log(val);
data.currentPage = val;
}
async function copy(Msg) {
try {
//
await toClipboard(Msg);
ElMessage.success('复制成功');
//
// ...
} catch (e) {
//
console.error(e);
ElMessage.error('复制失败');
}
}
</script>
<style></style>

21
src/views/index-list/business-list.vue

@ -1,9 +1,24 @@
<template>
<div class="box">
<h1 class="text-xl mt-10 font-semibold">业务列表</h1>
<div class="flex flex-col">
<listSearchBar />
<div class="py-6">
<el-button type="primary" icon="el-icon-plus" @click="openPage">创建业务</el-button>
</div>
<listTable />
</div>
</template>
<script setup></script>
<script setup>
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
const router = useRouter();
const store = useStore();
function openPage() {
router.push({ name: 'desk-add-business' });
store.commit('plugin/setLeftIndex', 1);
}
</script>
<style></style>

24
src/views/index-list/plugin-list.vue

@ -0,0 +1,24 @@
<template>
<div class="flex flex-col">
<listSearchBar />
<div class="py-6">
<el-button type="primary" icon="el-icon-plus" @click="openPage">创建插件</el-button>
</div>
<listTable />
</div>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
const router = useRouter();
const store = useStore();
function openPage() {
router.push({ name: 'desk-add-plugin' });
store.commit('plugin/setLeftIndex', 2);
}
</script>
<style></style>

104
src/views/index-list/plugin-shop.vue

@ -1,50 +1,17 @@
<template>
<searchBar />
<div class="shop-content flex py-5" v-for="list in data.lists" :key="list.id">
<img :src="list.preview" alt="" class="shop-left" />
<div class="shop-right ml-8">
<div>
<span class="text-xl font-semibold">{{ list.name }}</span> <span class="ml-5 text-sm">{{ list.versions }}</span>
</div>
<div class="mt-4 desc text-sm">
<span> 描述</span> <span>{{ list.intro }}</span>
</div>
<div class="mt-5 text-sm">
<el-tag v-for="item in list.tags" :type="item.btnType" class="mr-3" :key="item.name">{{ item.name }}</el-tag>
</div>
<div class="mt-5 text-sm">
<span>行业:</span> <span>{{ list.industryName }}</span> <span class="ml-8">分类:</span> <span>{{ list.sortName }}</span>
</div>
<div class="mt-4 text-sm">
<span>更新日期:</span> <span>{{ list.updateTime }}</span> <span class="ml-8">作者:</span> <span>{{ list.authorName }}</span>
</div>
<div class="mt-6">
<el-button type="primary">下载源代码</el-button>
<el-button type="primary">下载示例代码</el-button>
<el-button type="primary">添加到业务</el-button>
</div>
</div>
</div>
<div class="pagination mt-15 flex flex-row-reverse">
<el-config-provider :locale="zhCn">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="data.currentPage"
:page-size="data.pageSize"
layout="prev, pager, next, sizes, jumper"
:total="data.total"
:page-sizes="[10, 20, 30, 40, 50]"
>
</el-pagination>
</el-config-provider>
</div>
<listPlugin
:lists="data.lists"
:currentPage="data.currentPage"
:pageSize="data.pageSize"
:total="data.total"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
/>
</template>
<script lang="ts" setup="true">
import { reactive } from 'vue';
import { ElConfigProvider } from 'element-plus';
import zhCn from 'element-plus/lib/locale/lang/zh-cn';
const data = reactive({
lists: [
@ -99,57 +66,4 @@ function handleCurrentChange(val) {
}
</script>
<style scoped>
.el-input {
width: 20%;
margin-right: 2rem;
}
.el-select {
margin-right: 2rem;
width: 20%;
}
.desc {
height: 30px;
line-height: 15px;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.shop-left {
width: 288px;
height: 263px;
}
.pagination >>> .el-pager li,
.pagination >>> .btn-prev,
.pagination >>> .btn-next {
border: 1px solid #ccc;
width: 2rem;
height: 2rem;
line-height: 2rem;
text-align: center;
padding: 0;
margin: 0 8px;
border-radius: 6px;
font-weight: normal;
}
.pagination >>> .el-pager li.active {
border: 1px solid #409eff;
color: #fff;
background: #409eff;
}
.pagination >>> .el-input__inner {
height: 2rem;
line-height: 2rem;
border: 1px solid #ccc;
border-radius: 6px !important;
}
.pagination >>> .el-pagination__jump {
margin-left: 0;
}
</style>
<style scoped></style>

Loading…
Cancel
Save