Merge branch 'dev' into vite

# Conflicts:
#	examples/router/autoRoutes.js
#	package.json
#	packages/bigscreen/designer/components/Add.vue
#	project/dv/apps/AppGridDV.vue
#	vue.config.js
This commit is contained in:
aixianling
2022-08-23 11:14:38 +08:00
125 changed files with 15445 additions and 4898 deletions

View File

@@ -10,8 +10,11 @@
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :colConfigs="columns"
:size.sync="page.size" border @getList="getTableData" tableSize="mini" height="430px">
<el-table-column slot="chb" width="100px">
:size.sync="page.size" @getList="getTableData" tableSize="mini" :dict="dict" v-bind="$attrs">
<el-table-column slot="chb" width="100px" v-if="!disabled">
<template #header>
<el-checkbox v-if="multiple" v-model="selectAll" @change="handleCheckAll"/>
</template>
<template slot-scope="{row}">
<el-checkbox v-model="row.checked" @change="handleCheck(row)"/>
</template>
@@ -37,18 +40,23 @@ export default {
default: () => [
{prop: 'label', label: "应用名称"},
{prop: 'project', label: "项目/框架"},
{prop: 'category', label: "分类", dict: "appsCategory"},
{prop: 'name', label: "模块名"},
]
},
nodeKey: {default: "id"},
searchKey: {default: "name"},
multiple: Boolean
multiple: Boolean,
disabled: Boolean,
meta: {default: () => []},
choose: {default: null}
},
data() {
return {
page: {total: 0, current: 1, size: 10},
search: {},
tableData: [],
selectAll: false
}
},
computed: {
@@ -58,7 +66,9 @@ export default {
]
},
selected() {
return [this.value].flat().filter(e => !!e) || []
const {choose, value, nodeKey} = this,
list = [choose].flat().map(e => e?.[nodeKey])
return [...new Set([value, list].flat())].filter(Boolean) || []
}
},
watch: {
@@ -68,40 +78,66 @@ export default {
},
methods: {
getTableData() {
let {page, search, action, nodeKey} = this
this.instance?.post(action, null, {
const {page, search, action, meta, searchKey, dict} = this
if (meta.length > 0) {
const reg = new RegExp(search[searchKey])
this.handleTableData(meta.filter(e => reg.test(e.label) || reg.test(e.name) || reg.test(dict.getLabel('appsCategory', e.category))))
} else this.instance?.post(action, null, {
params: {...page, ...search}
}).then(res => {
if (res?.data) {
const list = res.data.records || res.data || []
list.map(e => {
if (/\/project\//.test(e.libPath)) {
e.project = e.libPath.replace(/.*project\/([^\/]+)\/.+/, '$1')
} else if (/\/core\//.test(e.libPath)) {
e.project = "core"
} else e.project = "standard"
})
this.tableData = list.map(e => ({...e, checked: this.selected.includes(e[nodeKey])}))
this.page.total = res.data.total
this.handleTableData(res.data.records || res.data || [])
}
})
},
handleTableData(list) {
const {nodeKey} = this
list.map(e => {
e.category = e.libPath.replace(/^\/[^\/]+\/([^\/]+)\/.+/, '$1')
if (/\/project\//.test(e.libPath)) {
e.project = e.libPath.replace(/.*project\/([^\/]+)\/.+/, '$1')
} else if (/\/core\//.test(e.libPath)) {
e.project = "core"
} else e.project = "standard"
})
this.tableData = list.map(e => ({...e, checked: this.selected.includes(e[nodeKey])}))
},
handleCheck(row) {
const {nodeKey} = this
if (this.multiple) {
let selected = this.$copy(this.selected)
let selected = this.$copy(this.selected),
choose = this.$copy(this.choose) || []
if (row.checked) {
selected.push(row[nodeKey])
choose.push(row)
} else {
selected = selected.filter(e => e != row[nodeKey])
choose = choose.filter(e => e[nodeKey] != row[nodeKey])
}
this.$emit("change", selected)
this.$emit("update:choose", choose)
this.$emit("select", choose)
} else {
this.tableData.map(e => e.checked = e[nodeKey] == row.id && row.checked)
this.$emit("change", row.checked ? row[nodeKey] : '')
this.$emit("update:choose", row.checked ? row : null)
this.$emit("select", row.checked ? row : null)
}
},
handleCheckAll(v) {
const {nodeKey} = this
let selected = this.tableData.map(e => {
e.checked = v
return e
}).filter(e => e.checked) || []
this.$emit("change", selected?.map(e => e[nodeKey]))
this.$emit("update:choose", selected)
this.$emit("select", selected)
}
},
created() {
this.dict.load('appsCategory')
this.$set(this.search, this.searchKey, "")
this.getTableData()
}

View File

@@ -11,7 +11,7 @@ import Add from "./add";
export default {
name: "AppDeployCustom",
components: {Add, List},
label: "定制项目",
label: "定制方案",
props: {
instance: Function,
dict: Object,
@@ -24,7 +24,7 @@ export default {
}
},
created() {
this.dict.load('yesOrNo','systemType')
this.dict.load('yesOrNo', 'systemType', 'appsCategory')
}
}
</script>

View File

@@ -3,40 +3,87 @@
<ai-detail>
<ai-title slot="title" :title="pageTitle" isShowBottomBorder/>
<template #content>
<el-form ref="AddForm" :model="form" size="small" label-width="120px" :rules="rules">
<ai-card title="基本信息">
<template #content>
<el-form-item label="项目/系统名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" clearable/>
</el-form-item>
<el-row type="flex">
<div class="fill">
<el-form-item label="系统类型" prop="type">
<ai-select v-model="form.type" :selectList="dict.getDict('systemType')"/>
<el-tabs tab-position="left">
<el-tab-pane label="方案设置">
<el-form ref="AddForm" :model="form" size="small" label-width="120px" :rules="rules">
<ai-card title="基本信息">
<template #content>
<el-form-item label="项目/系统名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="更新项目路径" prop="dist">
<el-input v-model="form.dist" placeholder="常填写nginx路径,下载包从这里取" clearable/>
</el-form-item>
</div>
<div class="fill mar-l16">
<el-form-item label="项目路径" prop="customPath">
<el-input v-model="form.customPath" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" placeholder="请输入" clearable/>
</el-form-item>
</div>
</el-row>
</template>
</ai-card>
<ai-card title="主库应用">
<template #content>
<ai-lib-table v-if="form.type" v-model="form.apps" v-bind="$props" multiple searchKey="name"
:action="`/node/wechatapps/list?type=${form.type}&isMain=1`"/>
<ai-empty v-else>请先选择系统类型</ai-empty>
</template>
</ai-card>
</el-form>
<el-row type="flex">
<div class="fill">
<el-form-item label="系统类型" prop="type">
<ai-select v-model="form.type" :selectList="dict.getDict('systemType')" @change="form.apps = [],handleSysTypeChange(form.type)"/>
</el-form-item>
<el-form-item label="更新项目路径" prop="dist">
<el-input v-model="form.dist" placeholder="常填写nginx路径,下载包从这里取" clearable/>
</el-form-item>
</div>
<div class="fill mar-l16">
<el-form-item label="库项目根路径" prop="customPath">
<el-input v-model="form.customPath" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" placeholder="请输入" clearable/>
</el-form-item>
</div>
</el-row>
</template>
</ai-card>
<ai-card title="主库应用">
<template #content>
<ai-lib-table v-if="form.type" v-model="form.apps" v-bind="$props" multiple searchKey="name"
:action="`/node/wechatapps/list?type=${form.type}&isMain=1`" border/>
<ai-empty v-else>请先选择系统类型</ai-empty>
</template>
</ai-card>
<ai-card title="扩展设置">
<template #content>
<template v-if="form.type=='mp'">
<el-form-item label="小程序AppId">
<el-input v-model="form.appId" clearable placeholder="小程序appId"/>
</el-form-item>
<ai-title title="底部导航栏"/>
<ai-table :tableData="tabBar.list" :colConfigs="colConfigs" tableSize="mini" :isShowPagination="false" border>
<el-table-column slot="options" label="操作" width="80" align="center">
<template slot-scope="{row}">
<ai-dialog-btn text="更换" dialogTitle="选择应用">
<ai-lib-table :meta="appList" v-model="row.id" @select="v=>handleTabbarChange(row,v)" :isShowPagination="false" v-bind="$props"
:border="false"/>
</ai-dialog-btn>
</template>
</el-table-column>
</ai-table>
</template>
<template v-else-if="form.type=='wxwork'">
<el-row type="flex">
<div class="fill">
<el-form-item label="接口是否单服务">
<el-checkbox v-model="form.isSingleService"/>
</el-form-item>
<el-form-item label="是否启用水印">
<el-checkbox v-model="form.waterMarker"/>
</el-form-item>
</div>
<div class="fill">
<el-form-item label="默认首页">
<el-input v-model="form.homePage" clearable placeholder="填写应用的文件名"/>
</el-form-item>
<el-form-item label="开启百度流量">
<el-checkbox v-model="form.hmt"/>
</el-form-item>
</div>
</el-row>
</template>
</template>
</ai-card>
</el-form>
</el-tab-pane>
<el-tab-pane label="方案应用" lazy>
<ai-lib-table :meta="appList" :isShowPagination="false" v-bind="$props" disabled :colConfigs="appListConfigs"/>
</el-tab-pane>
</el-tabs>
</template>
<template #footer>
<el-button @click="back">取消</el-button>
@@ -59,17 +106,53 @@ export default {
},
computed: {
isEdit: v => !!v.$route.query.id,
pageTitle: v => v.isEdit ? "编辑定制项目" : "新增定制项目",
pageTitle: v => v.isEdit ? "编辑定制方案" : "新增定制方案",
appList() {
return this.form.appList?.map(e => {
e.category = e.libPath.replace(/^\/[^\/]+\/([^\/]+)\/.+/, '$1')
if (/\/project\//.test(e.libPath)) {
e.project = e.libPath.replace(/.*project\/([^\/]+)\/.+/, '$1')
} else if (/\/core\//.test(e.libPath)) {
e.project = "core"
} else e.project = "standard"
return e
}) || []
},
},
data() {
return {
form: {apps: []},
form: {apps: [], type: null},
rules: {
name: {required: true, message: "请输入"},
type: {required: true, message: "请选择"},
customPath: {required: true, message: "请输入"},
},
mainLibApps: [],
colConfigs: [
{prop: 'text', label: "名称"},
{prop: 'pagePath', label: "应用路径"},
{prop: 'iconPath', label: "默认图标"},
{prop: 'selectedIconPath', label: "选中图标"},
],
appListConfigs: [
{prop: 'label', label: "应用名称", render: (h, {row}) => h(row.tabbar ? 'b' : 'p', row.label + ` ${row.tabbar ? '(底部导航栏)' : ''}`)},
{prop: 'project', label: "项目/框架"},
{prop: 'category', label: "分类", dict: "appsCategory"},
{prop: 'name', label: "模块名"}
],
tabBar: {
color: "#666666",
selectedColor: "#197DF0",
backgroundColor: "#ffffff",
list: [
{pagePath: "pages/AppHome/AppHome", text: "首页", iconPath: "static/TabBar/home.png", selectedIconPath: "static/TabBar/home_selected.png"},
{pagePath: "pages/AppModules/AppModules", text: "应用", iconPath: "static/TabBar/service.png", selectedIconPath: "static/TabBar/service_selected.png"},
{
pagePath: "pages/AppEnteringVillage/AppEnteringVillage", text: "进村",
iconPath: "static/TabBar/custom.png", selectedIconPath: "static/TabBar/custom_selected.png"
},
{pagePath: "pages/AppMine/AppMine", text: "我的", iconPath: "static/TabBar/me.png", selectedIconPath: "static/TabBar/me_selected.png"}
]
}
}
},
methods: {
@@ -80,6 +163,7 @@ export default {
}).then(res => {
if (res?.data) {
this.form = res.data
this.handleSysTypeChange(this.form.type, this.form.extra)
}
})
},
@@ -89,6 +173,12 @@ export default {
submit() {
this.$refs.AddForm.validate(v => {
if (v) {
const {tabBar, form: {type, appId, isSingleService, homePage}} = this
if (type == 'mp') {
this.form.extra = {tabBar, appId}
} else if (type == 'wxwork') {
this.form.extra = {isSingleService, homePage}
}
this.instance.post("/node/custom/addOrUpdate", this.form).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功!")
@@ -98,6 +188,20 @@ export default {
}
})
},
handleSysTypeChange(v, data = {}) {
let values = this.$copy(data)
if (v == 'mp') {
if (values?.tabBar) {
this.tabBar = values.tabBar || this.tabBar
delete values.tabBar
}
}
Object.keys(values).map(e => this.$set(this.form, e, values[e]))
},
handleTabbarChange(row, {name, label}) {
row.text = label
row.pagePath = `pages/${name}/${name}`
}
},
created() {
this.getDetail()

View File

@@ -1,7 +1,7 @@
<template>
<section class="list">
<ai-list>
<ai-title slot="title" title="定制项目" isShowBottomBorder/>
<ai-title slot="title" title="定制方案" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #left>
@@ -19,13 +19,15 @@
<el-progress v-else :percentage="row.count"/>
</template>
</el-table-column>
<el-table-column slot="options" label="操作" fixed="right" align="center" width="300">
<el-table-column slot="options" label="操作" fixed="right" width="300" header-align="center">
<template slot-scope="{row}">
<el-button type="text" @click="handleAdd(row.id)">编辑</el-button>
<el-button type="text" @click="handleUpdate(row)" v-if="row.count==0">打包更新</el-button>
<el-button type="text" @click="handleCancelUpdate(row)" v-else>停止</el-button>
<el-button type="text" @click="handleDownload(row)" v-if="row.dist">下载</el-button>
<el-button type="text" @click="handleDelete(row.id)">删除</el-button>
<template v-if="!!row.dist">
<el-button type="text" @click="handleUpdate(row)" v-if="row.count==0">打包更新</el-button>
<el-button type="text" @click="handleCancelUpdate(row)" v-else>停止</el-button>
<el-button type="text" @click="handleDownload(row)" v-if="row.dist">下载</el-button>
</template>
</template>
</el-table-column>
</ai-table>
@@ -118,7 +120,7 @@ export default {
this.$message.error("打包失败!")
} else if (row.count % 2 == 0 && row.target) {
row.count++
} else this.getRowById(row).then(v => {
} else this.getRowById(row.id).then(v => {
if (v.error) {
clearInterval(timer[id])
this.$message.error("打包失败!")
@@ -152,7 +154,7 @@ export default {
if (res?.code == 0) {
clearInterval(this.timer[id])
row.count = 0
this.getRowById(row).then(v => this.refreshRow(row, v))
this.getRowById(row.id).then(v => this.refreshRow(row, v))
}
})
},

View File

@@ -31,7 +31,8 @@
<el-table-column slot="options" label="操作" fixed="right" align="center" width="300">
<template slot-scope="{row}">
<el-button type="text" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" @click="handleZip(row)">打包</el-button>
<el-button type="text" @click="handleZip(row)" v-if="row.count==0">打包</el-button>
<el-button type="text" @click="handleCancelZip(row)" v-else>停止</el-button>
<el-button type="text" v-if="/^打包时间/.test(row.error)" @click="handleDownload(row)">下载</el-button>
<el-button v-if="row.target" type="text" @click="handleUpdateSystem(row)">更新部署</el-button>
</template>
@@ -44,15 +45,15 @@
<el-form-item label="项目/系统" prop="name">
{{ form.name }}(appid:<b v-text="form.miniapp_appid"/>)
</el-form-item>
<el-form-item label="版本号" prop="version">
<ai-select v-model="form.version" :instance="instance" action="/node/custom/list?type=mp" :prop="{label:'name'}"/>
</el-form-item>
<el-form-item label="小程序上传私钥" prop="privateKey">
<el-input v-model="form.privateKey" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="项目地址" prop="projectPath">
<el-input v-model="form.projectPath" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="npm构建脚本" prop="npmScript">
<el-input v-model="form.npmScript" clearable placeholder="请输入"/>
</el-form-item>
@@ -77,6 +78,7 @@ export default {
desConfigs() {
let isLine = true
return [
{prop: "corp_id", label: "企业微信corpId"},
{prop: "corp_address_book_secret", label: "企业微信通讯录SECRET", width: 200},
{prop: "corp_agent_id", label: "企业微信AGENTID", width: 150},
{prop: "corp_secret", label: "企业微信SECRET", isLine},
@@ -100,10 +102,9 @@ export default {
colConfigs: [
{slot: "expand"},
{label: "项目/系统名称", prop: "name", width: 300},
{label: "corpId", prop: "corp_id", width: 180},
{label: "管理后台", prop: "web_url"},
{label: "appId", prop: "miniapp_appid", width: 180},
{label: "上传版本", prop: "version"},
{label: "管理后台", prop: "web_url"},
{label: "上传版本", render: (h, {row}) => h('p', row.versionName || row.version)},
{slot: "process"},
{slot: "options"}
],
@@ -112,8 +113,9 @@ export default {
rules: {
// privateKey: {required: true, message: "请输入 小程序上传私钥"},
// projectPath: {required: true, message: "请输入 项目地址"},
version: {required: true, message: "请输入 版本号"},
}
version: {required: true, message: "请选择 定制方案"},
},
timer: {}
}
},
methods: {
@@ -155,15 +157,15 @@ export default {
}).then(res => {
if (res?.code == 0) {
row.count = 1
let timer = setInterval(() => {
this.timer[id] = setInterval(() => {
if (row.count >= 100) {
clearInterval(timer)
clearInterval(this.timer[id])
this.$message.error("打包失败!")
} else if (row.count <= 25) {
row.count++
} else this.handleConfirmZip(row).then(v => {
if (v.error) {
clearInterval(timer)
clearInterval(this.timer[id])
row.error = v.error
row.count = 0
} else row.count++
@@ -172,6 +174,10 @@ export default {
}
}).catch(() => this.$message.error("打包失败!"))
},
handleCancelZip(row) {
clearInterval(this.timer[row.id])
row.count = 0
},
handleUpdateSystem(row) {
let {appid} = row
return this.instance.post("/node/wxmp/updateSystem", null, {
@@ -225,6 +231,9 @@ export default {
},
created() {
this.getTableData()
},
beforeDestroy() {
Object.values(this.timer).map(t => clearInterval(t))
}
}
</script>