This commit is contained in:
liuye
2022-06-28 09:14:39 +08:00
parent fd755fa58a
commit 6896dfd197
36 changed files with 6404 additions and 179 deletions

View File

@@ -0,0 +1,62 @@
<template>
<section class="AppAiCode">
<component :is="currentPage" v-bind="$props"/>
</section>
</template>
<script>
import AcList from "./acList";
import AcAdd from "./acAdd";
export default {
name: "AppAiCode",
components: {AcAdd, AcList},
label: "低代码生成平台",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
currentPage() {
let {hash} = this.$route
return hash == "#add" ? AcAdd : AcList
}
},
provide() {
return {
top: this
}
},
methods: {
handleGetCode(id) {
id && this.instance.post("/node/aicode/getCode", null, {
params: {id},
responseType: "blob"
}).then(res => {
if (res?.code == 1) {
this.$message.error(res.err)
} else {
const link = document.createElement('a')
let blob = new Blob([res], {type: 'application/zip'})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download', 'aicode.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
})
}
},
created() {
this.dict.load("detailType")
}
}
</script>
<style lang="scss" scoped>
.AppAiCode {
height: 100%;
}
</style>

View File

@@ -0,0 +1,185 @@
<template>
<section class="acAdd">
<ai-detail list>
<ai-title slot="title" :title="pageTitle">
<template #rightBtn>
<el-button type="primary" v-if="isEdit" @click="top.handleGetCode($route.query.id)">生成代码</el-button>
</template>
</ai-title>
<template #content>
<el-form ref="AcForm" :model="form" size="small" label-width="120px" :rules="rules">
<el-tabs tab-position="left" @tab-click="handleSyncProps">
<el-tab-pane label="基本信息" lazy>
<ai-card title="基本信息">
<template #content>
<el-row type="flex">
<div class="fill">
<el-form-item label="应用名称" prop="name">
<el-input v-model="form.name" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="应用模块" prop="appName">
<el-input v-model="form.appName" clearable placeholder="请输入"/>
</el-form-item>
</div>
<div class="fill">
<el-form-item label="核心码" prop="rightCode">
<el-input v-model="form.rightCode" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="详情方式" prop="detailType">
<ai-select v-model="form.detailType" :selectList="dict.getDict('detailType')"/>
</el-form-item>
</div>
</el-row>
<el-form-item label="按钮配置" prop="btns">
<el-checkbox-group v-model="form.btns">
<el-checkbox label="insertEnable">添加</el-checkbox>
<el-checkbox label="importEnable">导入</el-checkbox>
<el-checkbox label="exportEnalbe">导出</el-checkbox>
<el-checkbox label="editEnable">编辑</el-checkbox>
<el-checkbox label="deleteEnable">删除</el-checkbox>
<el-checkbox label="batchDelEnable">批量删除</el-checkbox>
</el-checkbox-group>
</el-form-item>
</template>
</ai-card>
<ai-card title="字段设置">
<template #right>
<el-button type="text" @click="handleAddProps">批量添加</el-button>
<el-button type="text" @click="form.props.push({})">添加</el-button>
</template>
<template #content>
<ai-table :tableData="form.props" :isShowPagination="false" :colConfigs="colConfigs">
<el-table-column v-for="col in colConfigs" :key="col.slot" v-bind="col">
<template slot-scope="{row}">
<el-checkbox v-if="col.type=='checkBox'" v-model="row[col.slot]"/>
<span v-else-if="col.type=='chbShow'" v-text="row[col.slot]==true?'✔':''"/>
<el-input v-else size="small" v-model="row[col.slot]" placeholder="请输入" clearable/>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center">
<template slot-scope="{row,$index}">
<el-button type="text" @click="form.props.splice($index,1)">删除</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-card>
</el-tab-pane>
<el-tab-pane label="详情设计" lazy>
<detail-layout v-bind="$props" :form="form" v-model="form.detailConfig"/>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<template #footer>
<el-button @click="back">取消</el-button>
<el-button type="primary" @click="submit">提交</el-button>
</template>
</ai-detail>
</section>
</template>
<script>
import DetailLayout from "./detailLayout";
export default {
name: "acAdd",
components: {DetailLayout},
props: {
instance: Function,
dict: Object,
permissions: Function
},
inject: {
top: {}
},
computed: {
isEdit: v => !!v.$route.query.id,
pageTitle: v => v.isEdit ? "编辑应用" : "新增应用"
},
data() {
return {
form: {props: [], btns: []},
rules: {
name: {required: true, message: "请输入应用名称"},
appName: {required: true, message: "请输入应用模块"},
btns: {required: true, message: '请输入按钮配置', trigger: 'change'}
},
colConfigs: [
{slot: 'prop', label: "字段"},
{slot: 'label', label: "名称"},
{slot: 'dict', label: "字典"},
{slot: 'isSearch', label: "搜索字段", align: 'center', type: 'checkBox'},
{slot: 'isTable', label: "表格字段", align: 'center', type: 'checkBox'},
{slot: 'isDetail', label: "详情字段", align: 'center', type: 'chbShow'},
]
}
},
methods: {
getDetail() {
let {id} = this.$route.query
id && this.instance.post("/node/aicode/detail", null, {
params: {id}
}).then(res => {
if (res?.data) {
this.form = res.data
this.handleSyncProps()
}
})
},
back() {
this.$router.push({})
},
submit() {
this.$refs.AcForm.validate(v => {
if (v) {
this.instance.post("/node/aicode/addOrUpdate", this.form).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功!")
this.back()
}
})
}
})
},
handleSyncProps() {
let detailPorps = this.form.detailConfig?.map(e => e.column)?.flat()?.map(e => e.prop)
this.form.props = this.form.props.map(e => ({...e, isDetail: !!detailPorps?.includes(e.prop)}))
},
handleAddProps() {
this.$prompt("请输入swagger示例JSON字符串", {
type: 'warning',
title: "批量添加字段",
dangerouslyUseHTMLString: true,
center: true,
}).then(({value}) => {
if (this.$checkJson(value)) {
Object.keys(JSON.parse(value)).map(prop => {
this.form.props.push({prop})
})
}
}).catch(() => 0)
},
$checkJson(str) {
if (typeof str == 'string') {
try {
let obj = JSON.parse(str);
return !!(typeof obj == 'object' && obj);
} catch (e) {
return false;
}
}
return false;
},
},
created() {
this.getDetail()
}
}
</script>
<style lang="scss" scoped>
.acAdd {
height: 100%;
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<section class="acList">
<ai-list>
<ai-title slot="title" title="低代码生成平台" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="handleAdd()">添加</el-button>
</template>
<template #right>
<el-input size="small" placeholder="搜索应用" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
<el-table-column slot="options" label="操作" fixed="right" align="center" width="300">
<template slot-scope="{row}">
<el-button type="text" @click="handleAdd(row.id)">编辑</el-button>
<el-button type="text" @click="handleDelete(row.id)">删除</el-button>
<el-button type="text" @click="top.handleGetCode(row.id)">下载</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</section>
</template>
<script>
export default {
name: "acList",
props: {
instance: Function,
dict: Object,
permissions: Function
},
inject: {
top: {}
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
colConfigs: [
{label: "应用名称", prop: "name", width: 200},
{label: "应用模块", prop: "appName"},
{label: "权限码", prop: "rightCode"},
{label: "详情展示方式", prop: "detailType", dict: "detailType"},
],
}
},
methods: {
getTableData() {
this.instance.post("/node/aicode/list", null, {
params: {...this.page, ...this.search}
}).then(res => {
if (res?.data) {
this.tableData = res.data.records
this.page.total = res.data.total
}
})
},
handleAdd(id) {
this.$router.push({hash: "#add", query: {id}})
},
handleDelete(ids) {
this.$confirm("是否要删除该应用?").then(() => {
this.instance.post("/node/aicode/delete", null, {
params: {ids}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功")
this.getTableData()
}
})
}).catch(() => 0)
}
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.acList {
}
</style>

View File

@@ -0,0 +1,274 @@
{
"config": [
{
"type": "info",
"tips": "(不能重复添加同一元素)",
"label": "信息",
"children": [
{
"type": "name",
"fieldName": "姓名",
"fieldTips": "请输入姓名",
"fixedLabel": "姓名",
"disable": "0",
"grid": 0.5,
"defaultValue": "",
"icon": "icontext_box",
"mustFill": "1",
"maxLength": 20
},
{
"type": "idNumber",
"fieldName": "身份证号",
"fixedLabel": "身份证号",
"fieldTips": "请输入身份证号",
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"maxLength": 20,
"disable": "0",
"grid": 0.5
},
{
"type": "phone",
"fieldName": "联系方式",
"fixedLabel": "联系方式",
"fieldTips": "请输入联系方式",
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"maxLength": 20,
"disable": "0",
"grid": 0.5
},
{
"type": "area",
"fieldName": "地区",
"fixedLabel": "地区",
"fieldTips": "请选择地区",
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"areaPattern": "",
"disable": "0",
"grid": 0.5
}
]
},
{
"type": "options",
"tips": "(可重复添加)",
"label": "选项",
"children": [
{
"type": "radio",
"fieldName": "单选",
"fixedLabel": "单选",
"fieldTips": "请选择",
"grid": 0.5,
"icon": "iconradio",
"mustFill": "1",
"disable": "0",
"defaultValue": "",
"options": [
{
"label": "选项1",
"value": ""
},
{
"label": "选项2",
"value": ""
}
],
"title": ""
},
{
"type": "checkbox",
"fieldName": "多选",
"fixedLabel": "多选",
"fieldTips": "请选择",
"icon": "iconcheck_box",
"mustFill": "1",
"grid": 0.5,
"disable": "0",
"defaultValue": [],
"options": [
{
"label": "选项1",
"value": ""
},
{
"label": "选项2",
"value": ""
}
],
"title": ""
},
{
"type": "select",
"fieldName": "单下拉框",
"fixedLabel": "单下拉框",
"grid": 0.5,
"fieldTips": "请选择",
"icon": "iconSelect",
"mustFill": "1",
"defaultValue": "",
"disable": "0",
"options": [
{
"label": "选项1",
"value": ""
},
{
"label": "选项2",
"value": ""
}
],
"title": ""
},
{
"type": "onOff",
"fieldName": "开关",
"fixedLabel": "开关",
"grid": 0.5,
"fieldTips": "请选择开关",
"icon": "iconSelect",
"mustFill": "1",
"defaultValue": "0",
"disable": "0",
"title": ""
},
{
"type": "date",
"fieldName": "日期",
"fixedLabel": "日期",
"grid": 0.5,
"datetimePattern": "yyyy-MM-dd",
"fieldTips": "请选择日期",
"icon": "iconSelect",
"mustFill": "1",
"disable": "0",
"title": ""
},
{
"type": "time",
"fieldName": "时间",
"fixedLabel": "时间",
"grid": 0.5,
"datetimePattern": "HH:mm:ss",
"fieldTips": "请选择时间",
"icon": "iconSelect",
"mustFill": "1",
"disable": "0",
"title": ""
},
{
"type": "datetime",
"fieldName": "日期时间",
"fixedLabel": "日期时间",
"grid": 0.5,
"datetimePattern": "yyyy-MM-dd HH:mm:ss",
"fieldTips": "请选择日期时间",
"icon": "iconSelect",
"mustFill": "1",
"disable": "0",
"title": ""
}
]
},
{
"type": "input",
"tips": "(可重复添加)",
"label": "填空",
"children": [
{
"type": "input",
"fieldName": "单行填空",
"fieldTips": "请输入",
"fixedLabel": "单行填空",
"disable": "0",
"grid": 0.5,
"defaultValue": "",
"icon": "icontext_box",
"mustFill": "1",
"maxLength": 50
},
{
"type": "textarea",
"fieldName": "多行填空",
"fixedLabel": "多行填空",
"fieldTips": "请输入",
"lineNumber": 4,
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"maxLength": 500,
"disable": "0",
"grid": 1
},
{
"type": "number",
"fieldName": "数字输入",
"fixedLabel": "数字输入",
"fieldTips": "请输入数字",
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"maxValue": 10000,
"decimalPlaces": 0,
"minValue": 0,
"maxLength": 500,
"disable": "0",
"grid": 0.5
},
{
"type": "rtf",
"fieldName": "富文本",
"fixedLabel": "富文本",
"fieldTips": "请输入",
"defaultValue": "",
"icon": "icontext_area",
"mustFill": "1",
"maxLength": 5000,
"disable": "0",
"grid": 1
}
]
},
{
"type": "annex",
"tips": "(可重复添加)",
"label": "附件",
"children": [
{
"type": "upload",
"fieldTips": "请上传",
"fieldName": "上传附件",
"fixedLabel": "上传附件",
"disable": "0",
"fileChoseSize": 10,
"fileMaxCount": 9,
"defaultValue": "",
"icon": "iconpic",
"mustFill": "1",
"grid": 1
}
]
},
{
"type": "layout",
"tips": "(可重复添加)",
"label": "分组",
"children": [
{
"type": "group",
"fieldName": "卡片",
"fixedLabel": "卡片",
"icon": "iconpic",
"groupName": "分组标题",
"column": []
}
]
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,262 @@
<template>
<section class="AppDeploy">
<ai-list>
<ai-title slot="title" title="部署发布" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">增加</el-button>
</template>
<template #right>
<el-input size="small" placeholder="搜索项目/系统" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
<el-table-column type="expand" slot="expand">
<template slot-scope="{row}">
<ai-wrapper>
<ai-info-item labelWidth="200px" v-for="op in desConfigs" :key="op.prop" :value="row[op.prop]"
v-bind="op"/>
</ai-wrapper>
</template>
</el-table-column>
<el-table-column slot="process" label="打包进度">
<template slot-scope="{row}">
<span v-if="row.count==0" v-text="getProcessMsg(row)"/>
<el-progress v-else :percentage="row.count"/>
</template>
</el-table-column>
<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="handleDelete(row.id)">删除</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="row.target" @click="handleDownload(row)">下载</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
<ai-dialog :visible.sync="dialog" title="部署任务设置" width="700px" @close="form={}" @onConfirm="submit">
<el-form ref="DialogForm" :model="form" size="small" label-width="100px" :rules="rules">
<el-form-item label="项目/系统" prop="name">
<el-input v-model="form.name" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="系统类型" prop="type">
<ai-select v-model="form.type" :selectList="dict.getDict('systemType')"/>
</el-form-item>
<el-form-item label="打包脚本" prop="libShell">
<el-input v-model="form.libShell" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="更新脚本" prop="updateShell">
<el-input v-model="form.updateShell" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="项目URL" prop="webUrl">
<el-input v-model="form.webUrl" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="打包地址" prop="webUrl">
<el-input v-model="form.zipPath" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="nginx路径" prop="target">
<el-input v-model="form.target" clearable placeholder="请输入"/>
</el-form-item>
<el-form-item label="node版本" prop="nodeVersion">
<el-input v-model="form.nodeVersion" clearable placeholder="请输入"/>
</el-form-item>
</el-form>
</ai-dialog>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "AppDeploy",
label: "部署发布",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
desConfigs() {
let isLine = true
return [
{prop: "libShell", label: "打包脚本", width: 100},
{prop: "updateShell", label: "更新脚本", width: 100},
{prop: "zipPath", label: "打包地址", width: 100, isLine},
{prop: "target", label: "nginx路径", width: 100, isLine},
{prop: "webUrl", label: "项目URL", width: 100},
{prop: "nodeVersion", label: "node打包版本", width: 100},
]
},
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
colConfigs: [
{slot: "expand"},
{label: "项目/系统名称", prop: "name", width: 200},
{label: "系统类型", prop: "type", dict: "systemType", width: 80},
{label: "nginx路径", prop: "target"},
{slot: "process"},
{slot: "options"}
],
dialog: false,
form: {},
rules: {
name: {required: true, message: "请输入项目/系统名称"},
},
timer: {}
}
},
methods: {
getTableData() {
this.instance.post("/node/autodeploy/list", null, {
params: {...this.page, ...this.search}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records.map(e => ({...e, count: 0}))
this.page.total = res.data.total
}
})
},
handleDownload(row) {
let {id} = row
this.instance.post("/node/autodeploy/download", null, {
params: {id},
responseType: "blob"
}).then(res => {
if (res?.code == 1) {
this.$message.error(res.err)
} else {
const link = document.createElement('a')
let blob = new Blob([res], {type: 'application/zip'})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download', row.name + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
})
},
handleZip(row) {
let {id} = row, {timer} = this
this.instance.post("/node/autodeploy/getZip", null, {
params: {id}
}).then(res => {
if (res?.code == 0) {
row.count = 1
timer[id] = setInterval(() => {
if (row.count >= 100) {
clearInterval(timer[id])
row.count = 0
this.$message.error("打包失败!")
} else if (row.count <= 10 && row.target) {
row.count++
} else this.handleConfirmZip(row).then(v => {
if (v.error) {
clearInterval(timer[id])
this.$message.error("打包失败!")
this.refreshRow(row, v)
row.count = 0
} else if (v.download) {
clearInterval(timer[id])
this.refreshRow(row, v)
row.count = 0
} else row.count++
})
}, 3000)
}
})
},
refreshRow(row, v) {
row.error = v.error
row.download = v.download
row.zipTime = v.zipTime
},
handleCancelZip(row) {
let {id} = row
return this.instance.post("/node/autodeploy/cancelZip", null, {
params: {id}
}).then(res => {
if (res?.code == 0) {
clearInterval(this.timer[id])
row.count = 0
this.handleConfirmZip(row).then(v => this.refreshRow(row, v))
}
})
},
handleEdit(row) {
this.form = JSON.parse(JSON.stringify(row))
this.dialog = true
},
submit() {
this.$refs.DialogForm.validate(v => {
if (v) {
this.instance.post("/node/autodeploy/addOrUpdate", this.form).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功")
this.getTableData()
this.dialog = false
}
})
}
})
},
handleDelete(ids) {
this.$confirm("是否要删除该项目/系统?").then(() => {
this.instance.post("/node/autodeploy/delete", null, {
params: {ids}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功")
this.getTableData()
}
})
}).catch(() => 0)
},
handleConfirmZip(row) {
let {id} = row
return this.instance.post("/node/autodeploy/confirmZip", null, {
params: {id}
}).then(res => {
if (res?.code == 0) return res.data
})
},
getProcessMsg(row) {
let time = row.zipTime ? this.$moment(row.download).diff(row.zipTime, 's', true) : ""
return row.error || (row.download ? `最近打包时间:${row.download}(用时:${time}秒)` :
row.zipTime ? `正在打包,开始于:${row.zipTime}` : `暂无打包`)
}
},
created() {
this.dict.load("systemType")
this.getTableData()
},
beforeDestroy() {
Object.values(this.timer).map(t => clearInterval(t))
}
}
</script>
<style lang="scss" scoped>
.AppDeploy {
height: 100%;
::v-deep.textRight {
direction: rtl;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
</style>

View File

@@ -0,0 +1,233 @@
<template>
<section class="AppDeployWxmp">
<ai-list>
<ai-title slot="title" title="小程序部署发布" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<!-- <template #left>-->
<!-- <el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">增加</el-button>-->
<!-- </template>-->
<template #right>
<el-input size="small" placeholder="搜索项目/系统/appId/上传版本" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
<el-table-column type="expand" slot="expand">
<template slot-scope="{row}">
<ai-wrapper>
<ai-info-item labelWidth="200px" v-for="op in desConfigs" :key="op.prop" :value="row[op.prop]"
v-bind="op"/>
</ai-wrapper>
</template>
</el-table-column>
<el-table-column slot="process" label="打包进度">
<template slot-scope="{row}">
<span v-if="row.count==0" v-text="getProcessMsg(row)"/>
<el-progress v-else :percentage="row.count"/>
</template>
</el-table-column>
<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" v-if="/^打包时间/.test(row.error)" @click="handleDownload(row)">下载</el-button>
<el-button v-if="row.target" type="text" @click="handleUpdateSystem(row)">更新部署</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
<ai-dialog :visible.sync="dialog" title="部署设置" width="600px" @close="form={}" @onConfirm="submit">
<el-form ref="DialogForm" :model="form" size="small" label-width="120px" :rules="rules">
<el-form-item label="项目/系统" prop="name">
{{ form.name }}(appid:<b v-text="form.miniapp_appid"/>)
</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>
</ai-dialog>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "AppDeployWxmp",
label: "小程序发布",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
desConfigs() {
let isLine = true
return [
{prop: "corp_address_book_secret", label: "企业微信通讯录SECRET", width: 200},
{prop: "corp_agent_id", label: "企业微信AGENTID", width: 150},
{prop: "corp_secret", label: "企业微信SECRET", isLine},
{prop: "corp_token", label: "企业微信TOKEN", width: 150},
{prop: "corp_aeskey", label: "企业微信AESKEY", width: 150},
{prop: "miniapp_secret", label: "小程序SECRET", width: 150},
{prop: "area_id", label: "地区编码", width: 150, isLine},
{prop: "lat", label: "纬度", width: 100},
{prop: "lng", label: "经度", width: 100},
{prop: "address", label: "中心点", width: 100, isLine},
{prop: "web_url", label: "管理端地址", width: 100},
{prop: "dvcp_url", label: "企微端地址", width: 100},
]
},
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
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"},
{slot: "process"},
{slot: "options"}
],
dialog: false,
form: {},
rules: {
// privateKey: {required: true, message: "请输入 小程序上传私钥"},
// projectPath: {required: true, message: "请输入 项目地址"},
version: {required: true, message: "请输入 版本号"},
}
}
},
methods: {
getTableData() {
this.instance.post("/node/wxmp/list", null, {
params: {...this.page, ...this.search}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records.map(e => ({...e, count: 0}))
this.page.total = res.data.total
}
})
},
handleDownload(row) {
let {appid} = row
this.instance.post("/node/wxmp/download", null, {
params: {appid},
responseType: "blob"
}).then(res => {
if (res?.code == 1) {
this.$message.error(res.err)
} else {
const link = document.createElement('a')
let blob = new Blob([res], {type: 'application/zip'})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download', row.name + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
})
},
handleZip(row) {
let {miniapp_appid: appid, version} = row
if (!version) return this.$message.error("请先维护要上传的版本!")
appid && this.instance.post("/node/wxmp/getZip", null, {
params: {appid}
}).then(res => {
if (res?.code == 0) {
row.count = 1
let timer = setInterval(() => {
if (row.count >= 100) {
clearInterval(timer)
this.$message.error("打包失败!")
} else if (row.count <= 25) {
row.count++
} else this.handleConfirmZip(row).then(v => {
if (v.error) {
clearInterval(timer)
row.error = v.error
row.count = 0
} else row.count++
})
}, 3000)
}
}).catch(() => this.$message.error("打包失败!"))
},
handleUpdateSystem(row) {
let {appid} = row
return this.instance.post("/node/wxmp/updateSystem", null, {
params: {appid}
}).then(res => {
if (res?.code == 0) {
}
})
},
handleEdit(row) {
this.form = JSON.parse(JSON.stringify(row))
this.dialog = true
},
submit() {
this.$refs.DialogForm.validate(v => {
if (v) {
this.instance.post("/node/wxmp/addOrUpdate", this.form).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功")
this.getTableData()
this.dialog = false
}
})
}
})
},
handleDelete(ids) {
this.$confirm("是否要删除该项目/系统?").then(() => {
this.instance.post("/node/autodeploy/delete", null, {
params: {ids}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功")
this.getTableData()
}
})
}).catch(() => 0)
},
handleConfirmZip(row) {
let {appid} = row
return this.instance.post("/node/wxmp/confirmZip", null, {
params: {appid}
}).then(res => {
if (res?.code == 0) return res.data
})
},
getProcessMsg(row) {
return row.error || `暂无打包`
}
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.AppDeployWxmp {
height: 100%;
}
</style>

View File

@@ -0,0 +1,66 @@
<template>
<div class="doc-circulation">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"/>
</keep-alive>
</div>
</template>
<script>
import List from './components/List'
import Add from './components/Add'
export default {
name: 'AppForm',
label: '配置表单',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'List',
params: {},
include: []
}
},
components: {
Add,
List
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'Add') {
this.component = 'Add'
this.params = data.params
}
if (data.type === 'list') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,281 @@
<template>
<ai-detail class="form-add" :class="[currIndex === 1 ? 'form-add__active' : '']">
<ai-title title="表单配置" slot="title" isShowBottomBorder isShowBack @onBackClick="cancel(false)"></ai-title>
<template #content>
<div class="ai-step">
<div class="ai-step__item"
:class="[currIndex >= index ? 'ai-step__item--active' : '']"
v-for="(item, index) in statusList"
:key="index">
<div class="ai-step__item--icon" v-if="currIndex <= index">
<i v-if="currIndex === index"></i>
</div>
<div class="el-icon-success" v-if="currIndex > index">
</div>
<span>{{ item }}</span>
</div>
</div>
<basic-info ref="basicInfo" v-model="basicInfo" v-show="currIndex === 0" :dict="dict" :instance="instance"></basic-info>
<form-layout :appType="basicInfo.appType" :currIndex="currIndex" class="form-config__wrapper" v-model="tableInfos" ref="form" v-show="currIndex === 1" :dict="dict" :instance="instance"></form-layout>
<form-config
ref="config"
:showListFields="showListFields"
:btns="btns"
:fuzzyQueryFields="fuzzyQueryFields"
:tableInfos="tableInfos"
:orderFields="orderFields"
v-if="currIndex === 2">
</form-config>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button @click="back" v-if="currIndex > 0">上一步</el-button>
<el-button @click="next" type="primary">{{ currIndex === 2 ? '完成' : '下一步' }}</el-button>
</template>
</ai-detail>
</template>
<script>
import BasicInfo from './BasicInfo.vue'
import FormLayout from './FormLayout.vue'
import FormConfig from './FormConfig.vue'
export default {
name: 'add',
props: {
instance: Function,
dict: Object,
params: Object,
type: String
},
components: {
FormLayout,
BasicInfo,
FormConfig
},
data () {
return {
currIndex: 0,
basicInfo: {
saasPlatformId: '',
menuLeve1Style: '',
saasPlatformName: '',
menuLevel1Name: '',
menuLevel3Name: '',
menuLevel2Name: '',
appType: ''
},
orderFields: [],
showListFields: [],
fuzzyQueryFields: [],
btns: [],
btnKeys: ['insertEnable', 'importEnable', 'exportEnalbe', 'editEnable', 'deleteEnable', 'batchDelEnable'],
configInfo: {
btns: [],
orderType: '0',
fieldName: ''
},
info: {},
tableInfos: [],
statusList: ['基础设置', '表单设计', '列表设计']
}
},
mounted () {
if (this.params.id) {
this.getInfo()
}
},
methods: {
cancel (isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: isRefresh ? true : false,
isQuote: this.params.isQuote ? true : false
})
},
confirm () {
},
back () {
this.currIndex = this.currIndex - 1
},
confirmBasicInfo () {
return this.$refs.basicInfo.validate()
},
getInfo () {
this.instance.post(`/app/appapplicationinfo/queryDetailById?id=${this.params.id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.basicInfo = {
saasPlatformId: res.data.saasPlatformId,
menuLeve1Style: res.data.menuLeve1Style,
saasPlatformName: res.data.saasPlatformName,
menuLevel1Name: res.data.menuLevel1Name,
menuLevel3Name: res.data.menuLevel3Name,
menuLevel2Name: res.data.menuLevel2Name,
appType: res.data.appType,
corpId: res.data.corpId,
corpName: res.data.corpName
}
this.fuzzyQueryFields = res.data.fuzzyQueryFields
this.tableInfos = res.data.tableInfos
this.showListFields = res.data.showListFields
this.orderFields = res.data.orderFields
this.btns = Object.keys(res.data).filter(v => {
return this.btnKeys.indexOf(v) > -1 && res.data[v] === '1'
})
}
})
},
submit (info) {
this.instance.post(`/app/appapplicationinfo/addOrUpdate`, {
...this.info,
...this.basicInfo,
tableInfos: this.tableInfos,
...info.btns,
id: this.params.id,
applicationName: this.basicInfo.menuLevel3Name || this.basicInfo.menuLevel2Name,
fuzzyQueryFields: info.fuzzyQueryFields,
orderType: info.orderType,
orderFields: info.orderFields,
showListFields: info.showListFields
}).then(res => {
if (res.code === 0) {
this.$message.success(this.params.id ? '编辑成功' : '添加成功')
this.cancel(true)
}
})
},
next () {
if (this.currIndex === 0) {
if (!this.$refs.basicInfo.validate()) return
}
if (this.currIndex === 1) {
this.$refs.form.onConfirm()
}
if (this.currIndex === 2) {
const info = this.$refs.config.validate()
if (!info) return
this.submit(info)
return false
}
this.currIndex = this.currIndex + 1
}
}
}
</script>
<style lang="scss" scoped>
.form-add {
&.form-add__active {
::v-deep .ai-detail__content--wrapper {
max-width: 100%!important;
height: 100%!important;
background: #F5F6F9;
}
.form-config__wrapper {
height: calc(100% - 52px);
overflow-y: hidden;
}
::v-deep .ai-detail__content {
height: calc(100% - 114px)!important;
padding: 0!important;
overflow: hidden!important;
}
}
.ai-step {
display: flex;
align-items: center;
justify-content: center;
margin-top: 4px;
margin-bottom: 24px;
.ai-step__item {
display: flex;
position: relative;
align-items: center;
margin-right: 216px;
&.ai-step__item--active {
span {
color: #2266FF;
}
.ai-step__item--icon {
display: flex;
align-items: center;
justify-content: center;
border-color: #2266FF;
i {
width: 12px;
height: 12px;
border-radius: 50%;
background: #2266FF;
}
}
}
&:after {
position: absolute;
top: 50%;
right: -208px;
width: 200px;
height: 2px;
background: #D0D4DC;
content: ' ';
transform: translateY(-50%);
}
&:last-child {
margin-right: 0;
&::after {
display: none;
}
}
.ai-step__item--icon {
width: 24px;
height: 24px;
margin-right: 8px;
border-radius: 50%;
background: #FFFFFF;
border: 2px solid #D0D4DC;
}
.el-icon-success {
width: 24px;
height: 24px;
font-size: 24px;
margin-right: 8px;
color: #2266FF;
border-radius: 50%;
}
span {
color: #666666;
font-size: 14px;
}
}
}
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div class="basicInfo">
<el-form ref="form" :model="form" label-width="110px" label-position="right">
<ai-card title="基本信息">
<template #content>
<div class="ai-form">
<el-form-item label="所属平台" prop="saasPlatformId" style="width: 100%;" :rules="[{ required: true, message: '请选择所属平台', trigger: 'change' }]">
<el-select
size="small"
style="width: 100%;"
placeholder="请选择所属平台"
clearable
@change="onChange"
v-model="form.saasPlatformId">
<el-option
v-for="(item, index) in sassList"
:key="index"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="form.saasPlatformId" style="width: 100%;" label="所属企业" prop="corpId" :rules="[{ required: true, message: '请选择所属企业', trigger: 'change' }]">
<ai-select
v-model="form.corpId"
placeholder="请选择所属企业"
clearable
@change="onCompanyChange"
:selectList="companyList">
</ai-select>
</el-form-item>
<el-form-item style="width: 100%;" label="一级菜单名称" prop="menuLevel1Name" :rules="[{ required: true, message: '请输入一级菜单名称', trigger: 'change' }]">
<el-input size="small" placeholder="请输入一级菜单名称" :maxlength="8" v-model="form.menuLevel1Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="二级菜单名称" prop="menuLevel2Name" :rules="[{ required: true, message: '请输入二级菜单名称', trigger: 'change' }]">
<el-input size="small" placeholder="请输入二级菜单名称" :maxlength="8" v-model="form.menuLevel2Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="三级菜单名称" prop="menuLevel3Name">
<el-input size="small" placeholder="请输入三级菜单名称" :maxlength="8" v-model="form.menuLevel3Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="应用类型" prop="appType">
<ai-select
v-model="form.appType"
placeholder="请选择应用类型"
clearable
:selectList="dict.getDict('diyAppType')">
</ai-select>
</el-form-item>
</div>
</template>
</ai-card>
</el-form>
</div>
</template>
<script>
export default {
name: 'basicInfo',
model: {
prop: 'value',
event: 'change',
},
props: {
instance: Function,
dict: Object,
value: Object
},
data () {
return {
form: {
saasPlatformId: '',
menuLeve1Style: '',
saasPlatformName: '',
menuLevel1Name: '',
menuLevel2Name: '',
menuLevel3Name: '',
appType: '',
corpId: '',
corpName: ''
},
companyList: [],
sassList: []
}
},
watch: {
value (v) {
this.form = JSON.parse(JSON.stringify(v))
if (this.form.saasPlatformId) {
this.getCompanyList()
}
}
},
created () {
this.dict.load('diyAppType')
},
mounted () {
this.getSassList()
this.form = JSON.parse(JSON.stringify(this.value))
},
methods: {
onChange (e) {
this.form.saasPlatformName = this.sassList.filter(v => v.id === e)[0].name
this.form.saasPlatformId && this.getCompanyList()
},
validate () {
let result = false
this.$refs.form.validate(valid => {
result = valid
})
this.$emit('change', this.form)
return result
},
onCompanyChange (e) {
this.form.corpName = this.companyList.filter(v => v.dictValue === e)[0].dictName
},
getCompanyList () {
this.instance.post(`/app/appCorp/page?current=1&size=1000&saasId=${this.form.saasPlatformId}`).then(res => {
if (res.data.records.length) {
this.companyList = res.data.records.map(v => {
return {
dictValue: v.corpId,
dictName: v.name
}
})
}
})
},
getSassList () {
this.instance.post(`/app/appSaas/listAll`).then(res => {
if (res.data) {
this.sassList = res.data
}
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,244 @@
<template>
<div class="basicInfo">
<ai-card title="搜索字段" class="search-wrapper">
<template #content>
<el-checkbox-group v-model="queryFields">
<el-checkbox
:label="`${item.fieldDbName}~${item.fieldName}`"
v-for="(item, index) in tableInfos"
:key="index">
{{ item.fieldName }}
</el-checkbox>
</el-checkbox-group>
</template>
</ai-card>
<ai-card title="表格字段">
<template #content>
<div class="ai-table">
<div class="el-table el-table--border ai-header__border">
<el-scrollbar>
<table cellspacing="0" cellpadding="0" border="0" class="el-table__body">
<draggable element="thead" animation="500" class="el-table__header is-leaf ai-table__header" :sort="true" v-model="showFields">
<th v-for="(item, index) in showFields" style="background: #f3f4f5; text-align: center;" class="ai-table__header" :key="index">{{ item.fieldName }}</th>
</draggable>
<tbody element="tbody">
<tr>
<td @click="handleShow(index, item.isShow)" v-for="(item, index) in showFields" :key="index">{{ item.isShow ? '已显示' : '已隐藏' }}</td>
</tr>
</tbody>
</table>
</el-scrollbar>
</div>
</div>
</template>
</ai-card>
<ai-card title="排序和操作按钮">
<template #content>
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
<el-form-item label="排序字段" prop="field">
<el-select
size="small"
placeholder="默认按创建时间排序"
clearable
v-model="form.field">
<el-option
v-for="(filed, index) in tableInfos"
:key="index"
:label="filed.fieldName"
:value="`${filed.fieldDbName}~${filed.fieldName}`">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序类型" prop="orderType" :rules="[{ required: true, message: '请输入排序类型', trigger: 'change' }]">
<el-radio-group v-model="form.orderType">
<el-radio label="asc">升序</el-radio>
<el-radio label="desc">降序</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="按钮配置" prop="btns" style="width: 100%;" :rules="[{ required: true, message: '请输入按钮配置', trigger: 'change' }]">
<el-checkbox-group v-model="form.btns">
<el-checkbox label="insertEnable">添加</el-checkbox>
<el-checkbox label="importEnable">导入</el-checkbox>
<el-checkbox label="exportEnalbe">导出</el-checkbox>
<el-checkbox label="editEnable">编辑</el-checkbox>
<el-checkbox label="deleteEnable">删除</el-checkbox>
<el-checkbox label="batchDelEnable">批量删除</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
</template>
</ai-card>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'configForm',
props: {
tableInfos: Array,
btns: Array,
showListFields: Array,
orderFields: Array,
fuzzyQueryFields: Array
},
components: {
draggable
},
data () {
return {
queryFields: [],
tableData: [{}],
btnKeys: ['insertEnable', 'importEnable', 'exportEnalbe', 'editEnable', 'deleteEnable', 'batchDelEnable'],
form: {
btns: [],
orderType: 'asc',
field: ''
},
showFields: []
}
},
mounted () {
const showIds = this.showListFields.map(v => v.fieldDbName)
this.showFields = JSON.parse(JSON.stringify(this.tableInfos)).map(item => {
item.isShow = showIds.indexOf(item.fieldDbName) > -1 ? true : false
return item
})
if (!this.showListFields.length) {
this.showFields.map(v => {
v.isShow = true
return v
})
}
this.tableInfos.map(item => {
this.tableData[0][item.fieldDbName] = '删除'
})
if (this.btns.length) {
this.form.btns = this.btns
}
const tableInfosIds = this.tableInfos.map(v => v.fieldDbName)
if (this.orderFields.length) {
let arr = this.orderFields.filter(v => {
return tableInfosIds.indexOf(v.fieldDbName) > -1
}).map(item => {
return `${item.fieldDbName}~${item.fieldName}`
})
if (arr.length) {
this.form.field = arr[0]
}
}
if (this.fuzzyQueryFields.length) {
this.queryFields = this.fuzzyQueryFields.filter(v => {
return tableInfosIds.indexOf(v.fieldDbName) > -1
}).map(item => {
return `${item.fieldDbName}~${item.fieldName}`
})
}
},
methods: {
validate () {
let result = false
this.$refs.form.validate(valid => {
result = valid
})
if (!result) {
return false
}
const btns = {}
this.btnKeys.forEach(item => {
btns[item] = this.form.btns.indexOf(item) > -1 ? 1 : 0
})
return {
btns,
orderFields: [{
fieldName: this.form.field.split('~')[1],
fieldDbName: this.form.field.split('~')[0],
orderType: this.form.orderType
}],
showListFields: this.showFields.filter(v => v.isShow).map((v, index) => {
return {
fieldName: v.fieldName,
fieldDbName: v.fieldDbName,
showListIndex: index
}
}),
fuzzyQueryFields: this.queryFields.map(v => {
return {
fieldName: v.split('~')[1],
fieldDbName: v.split('~')[0]
}
})
}
},
handleShow (index, isShow) {
const total = this.showFields.map(v => v.isShow).filter(v => !!v)
if (total.length <= 1 && isShow) {
return this.$message.error('表格列数不能小于1')
}
this.$set(this.showFields[index], 'isShow', !isShow)
}
}
}
</script>
<style scoped lang="scss">
.basicInfo {
.search-wrapper {
::v-deep .el-checkbox-group {
display: flex;
flex-wrap: wrap;
.el-checkbox {
width: 16.66%;
margin-bottom: 10px;
}
}
}
}
.ai-table {
.el-table--border {
border: 1px solid #d0d4dc;
border-bottom: none;
border-right: none;
}
table {
min-width: 100%;
}
th, tr {
min-width: 100px;
cursor: move;
}
tr {
td {
cursor: pointer;
color: #26f;
text-align: center;
user-select: none;
&:hover {
opacity: 0.7;
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
<template>
<ai-list class="appform">
<template slot="title">
<ai-title title="表单配置" isShowBottomBorder></ai-title>
</template>
<template slot="content">
<ai-search-bar class="search-bar">
<template #left>
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
</template>
<template slot="right">
<el-input
v-model="search.applicationName"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入菜单名称"
clearable
@clear="search.current = 1, search.applicationName = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
v-loading="loading"
style="margin-top: 6px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="options" width="180px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
<el-button type="text" @click="push(row.id)" v-if="row.pushStatus === '0'">推送</el-button>
<el-button type="text" @click="operate(row.id, row.status)">{{ row.status === '1' ? '停用' : '启用' }}</el-button>
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
applicationName: ''
},
loading: false,
total: 10,
colConfigs: [
{ prop: 'saasPlatformName', label: '所属平台' },
{ prop: 'menuLevel1Name', label: '一级菜单名称'},
{ prop: 'menuLevel2Name', label: '二级菜单名称'},
{ prop: 'menuLevel3Name', label: '三级菜单名称'},
{ prop: 'createUserName', label: '编辑人' },
{ prop: 'createTime', label: '编辑时间' },
{
prop: 'status',
label: '状态',
align: 'center',
render (h, {row}) {
return h('span',{
style: {
color: row.status === '1' ? '#2EA222' : '#F46'
}
}, row.status === '1' ? '启用' : '停用')
}
},
{
prop: 'pushStatus',
label: '推送状态',
align: 'center',
render (h, {row}) {
return h('span',{
style: {
color: row.pushStatus === '1' ? '#2EA222' : '#F46'
}
}, row.pushStatus === '1' ? '成功' : '失败')
}
}
],
tableData: [],
ids: ''
}
},
computed: {
...mapState(['user'])
},
mounted() {
this.getList()
},
methods: {
getList () {
this.loading = true
this.instance.post(`/app/appapplicationinfo/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
this.$nextTick(() => {
this.loading = false
})
} else {
this.loading = false
}
}).catch(() => {
this.loading = false
})
},
removeAll () {
if (!this.ids) return
this.remove(this.ids)
},
push (id) {
this.instance.post(`/app/appapplicationinfo/push?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success(`推送成功`)
this.getList()
}
})
},
operate (id, status) {
this.instance.post(`/app/appapplicationinfo/enable?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success(`${status === '1' ? '停用成功' : '启用成功'}`)
this.getList()
}
})
},
remove (id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appapplicationinfo/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id: id || ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,272 @@
export const components = [
{
type: 'info',
tips: '(不能重复添加同一元素)',
label: '信息',
children: [
{
type: 'name',
fieldName: '姓名',
fieldTips: '请输入姓名',
fixedLabel: '姓名',
disable: '0',
grid: 0.5,
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
maxLength: 20
},
{
type: 'idNumber',
fieldName: '身份证号',
fixedLabel: '身份证号',
fieldTips: '请输入身份证号',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 20,
disable: '0',
grid: 0.5
},
{
type: 'phone',
fieldName: '联系方式',
fixedLabel: '联系方式',
fieldTips: '请输入联系方式',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 20,
disable: '0',
grid: 0.5
},
{
type: 'area',
fieldName: '地区',
fixedLabel: '地区',
fieldTips: '请选择地区',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
areaPattern: '',
disable: '0',
grid: 0.5
}
]
},
{
type: 'options',
tips: '(可重复添加)',
label: '选项',
children: [
{
type: 'radio',
fieldName: '单选',
fixedLabel: '单选',
fieldTips: '请选择',
grid: 0.5,
icon: 'iconradio',
mustFill: '1',
disable: '0',
defaultValue: '',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'checkbox',
fieldName: '多选',
fixedLabel: '多选',
fieldTips: '请选择',
icon: 'iconcheck_box',
mustFill: '1',
grid: 0.5,
disable: '0',
defaultValue: [],
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'select',
fieldName: '单下拉框',
fixedLabel: '单下拉框',
grid: 0.5,
fieldTips: '请选择',
icon: 'iconSelect',
mustFill: '1',
defaultValue: '',
disable: '0',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'onOff',
fieldName: '开关',
fixedLabel: '开关',
grid: 0.5,
fieldTips: '请选择开关',
icon: 'iconSelect',
mustFill: '1',
defaultValue: '0',
disable: '0',
title: ''
},
{
type: 'date',
fieldName: '日期',
fixedLabel: '日期',
grid: 0.5,
datetimePattern: 'yyyy-MM-dd',
fieldTips: '请选择日期',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
},
{
type: 'time',
fieldName: '时间',
fixedLabel: '时间',
grid: 0.5,
datetimePattern: 'HH:mm:ss',
fieldTips: '请选择时间',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
},
{
type: 'datetime',
fieldName: '日期时间',
fixedLabel: '日期时间',
grid: 0.5,
datetimePattern: 'yyyy-MM-dd HH:mm:ss',
fieldTips: '请选择日期时间',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
}
]
},
{
type: 'input',
tips: '(可重复添加)',
label: '填空',
children: [
{
type: 'input',
fieldName: '单行填空',
fieldTips: '请输入',
fixedLabel: '单行填空',
disable: '0',
grid: 0.5,
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
maxLength: 50
},
{
type: 'textarea',
fieldName: '多行填空',
fixedLabel: '多行填空',
fieldTips: '请输入',
lineNumber: 4,
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 500,
disable: '0',
grid: 1
},
{
type: 'number',
fieldName: '数字输入',
fixedLabel: '数字输入',
fieldTips: '请输入数字',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxValue: 10000,
decimalPlaces: 0,
minValue: 0,
maxLength: 500,
disable: '0',
grid: 0.5
},
{
type: 'rtf',
fieldName: '富文本',
fixedLabel: '富文本',
fieldTips: '请输入',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 5000,
disable: '0',
grid: 1
}
]
},
{
type: 'annex',
tips: '(可重复添加)',
label: '附件',
children: [
{
type: 'upload',
fieldTips: '请上传',
fieldName: '上传附件',
fixedLabel: '上传附件',
disable: '0',
fileChoseSize: 10,
fileMaxCount: 9,
defaultValue: '',
icon: 'iconpic',
mustFill: '1',
grid: 1
}
]
},
{
type: 'layout',
tips: '(可重复添加)',
label: '分组',
children: [
{
type: 'group',
fieldName: '卡片',
fixedLabel: '卡片',
icon: 'iconpic',
groupName: '分组标题',
column: []
}
]
}
];

View File

@@ -0,0 +1,66 @@
<template>
<section class="AppWebApps">
<ai-list>
<ai-title slot="title" title="web产品库" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #right>
<el-input size="small" placeholder="搜索应用" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict"/>
</template>
</ai-list>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "AppWebApps",
label: "web产品库",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user'])
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
colConfigs: [
{label: "应用名称", prop: "label", width: 200},
{label: "应用模块名", prop: "name", width: 200},
{label: "产品库目录", prop: "libPath"},
]
}
},
methods: {
getTableData() {
this.instance.post("/node/wechatapps/list", null, {
params: {...this.page, ...this.search,type:'web'}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records.map(e => ({...e, count: 0}))
this.page.total = res.data.total
}
})
}
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.AppWebApps {
}
</style>

View File

@@ -0,0 +1,67 @@
<template>
<section class="AppWechatApps">
<ai-list>
<ai-title slot="title" title="小程序产品库" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #right>
<el-input size="small" placeholder="搜索应用" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict"/>
</template>
</ai-list>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "AppWechatApps",
label: "小程序产品库",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user'])
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
colConfigs: [
{label: "应用名称", prop: "label", width: 200},
{label: "应用模块名", prop: "name", width: 200},
{label: "生产环境路径", prop: "path"},
{label: "产品库目录", prop: "libPath"},
]
}
},
methods: {
getTableData() {
this.instance.post("/node/wechatapps/list", null, {
params: {...this.page, ...this.search,type:'mp'}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records.map(e => ({...e, count: 0}))
this.page.total = res.data.total
}
})
}
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.AppWechatApps {
}
</style>

View File

@@ -0,0 +1,68 @@
<template>
<section class="AppWxworkApps">
<ai-list>
<ai-title slot="title" title="企微应用产品库" isShowBottomBorder/>
<template #content>
<ai-search-bar>
<template #right>
<el-input size="small" placeholder="搜索应用" v-model="search.name" clearable
@change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict"/>
</template>
</ai-list>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "AppWxworkApps",
label: "企微应用产品库",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user'])
},
data() {
return {
search: {name: ""},
page: {current: 1, size: 10, total: 0},
tableData: [],
colConfigs: [
{label: "应用名称", prop: "label", width: 200},
{label: "应用模块名", prop: "name", width: 200},
{label: "生产环境路径", prop: "path"},
{label: "产品库目录", prop: "libPath"},
]
}
},
methods: {
getTableData() {
this.instance.post("/node/wechatapps/list", null, {
params: {...this.page, ...this.search, type: 'wxwork'}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records.map(e => ({...e, count: 0}))
this.page.total = res.data.total
}
})
}
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.AppWxworkApps {
height: 100%;
}
</style>