From 2f13076729b558d1760a48b9d55b697e0d9c3318 Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Tue, 22 Jun 2021 15:06:47 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=8E=88=E6=9D=83=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=86=85=E5=AE=B9,=20=E5=B0=86=E9=A1=B5=E9=9D=A2=E5=86=99?= =?UTF-8?q?=E6=88=90=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84state=E7=9A=84?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=91=88=E7=8E=B0=E5=87=BA=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Rich}/EditorImage.vue | 11 +- src/admin/common/Rich/RichState.ts | 8 +- .../Tinymce => admin/common/Rich}/config.ts | 2 +- src/admin/common/Rich/index.vue | 178 ++++++++++++- src/auth/AuthPage.ts | 14 - src/auth/AuthPage.vue | 251 ------------------ src/auth/AuthTemplate.vue | 99 ------- .../flows/SaveAuthPage/nodes/SaveAuthPage.ts | 13 - src/components/Tinymce/index.vue | 222 ---------------- src/config/auth/auth_page.json | 185 +++++++++++++ .../authPageBtn/nodes/authPageBtn.ts | 44 +++ .../openAuthPage/nodes/openAuthPage.ts | 17 +- .../appManager/saveTemplate}/index.ts | 8 +- .../saveTemplate/nodes/saveTemplate.ts | 110 ++++++++ src/flows/initPage/nodes/initPage.ts | 2 +- src/router/index.ts | 6 - 16 files changed, 536 insertions(+), 634 deletions(-) rename src/{components/Tinymce/components => admin/common/Rich}/EditorImage.vue (95%) rename src/{components/Tinymce => admin/common/Rich}/config.ts (92%) delete mode 100644 src/auth/AuthPage.ts delete mode 100644 src/auth/AuthPage.vue delete mode 100644 src/auth/AuthTemplate.vue delete mode 100644 src/auth/flows/SaveAuthPage/nodes/SaveAuthPage.ts delete mode 100644 src/components/Tinymce/index.vue create mode 100644 src/config/auth/auth_page.json rename src/{auth/flows/SaveAuthPage => flows/appManager/saveTemplate}/index.ts (78%) create mode 100644 src/flows/appManager/saveTemplate/nodes/saveTemplate.ts diff --git a/src/components/Tinymce/components/EditorImage.vue b/src/admin/common/Rich/EditorImage.vue similarity index 95% rename from src/components/Tinymce/components/EditorImage.vue rename to src/admin/common/Rich/EditorImage.vue index 4fe30e4a..d6e33f29 100644 --- a/src/components/Tinymce/components/EditorImage.vue +++ b/src/admin/common/Rich/EditorImage.vue @@ -21,7 +21,7 @@ :on-success="handleSuccess" :before-upload="beforeUpload" class="editor-slide-upload" - action="https://httpbin.org/post" + action="/api/v1/upload/" list-type="picture-card" > import { Component, Prop, Vue } from 'vue-property-decorator' import { ElUploadInternalRawFile } from 'element-ui/types/upload' +import { SettingsModule } from '@/store/modules/settings' export interface IUploadObject { hasSuccess: boolean @@ -57,11 +58,9 @@ export interface IUploadObject { } @Component({ - name: 'EditorImageUpload' + name: 'EditorImage' }) export default class extends Vue { - @Prop({ required: true }) private color!: string - private dialogVisible = false private listObj: { [key: string]: IUploadObject } = {} private defaultFileList = [] @@ -70,6 +69,10 @@ export default class extends Vue { return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess) } + get color() { + return SettingsModule.theme + } + private handleSubmit() { const arr = Object.keys(this.listObj).map(v => this.listObj[v]) if (!this.checkAllSuccess()) { diff --git a/src/admin/common/Rich/RichState.ts b/src/admin/common/Rich/RichState.ts index 15a7f9fd..ff189d70 100644 --- a/src/admin/common/Rich/RichState.ts +++ b/src/admin/common/Rich/RichState.ts @@ -1,5 +1,11 @@ import { BaseState } from '@/admin/base/BaseVue' export default interface RichState extends BaseState { - value: string; //内容 + value: string + id?: string + height?: string + width?: string + toolbar?: string[] + menubar?: string + isDisabledUploadImage?: boolean } diff --git a/src/components/Tinymce/config.ts b/src/admin/common/Rich/config.ts similarity index 92% rename from src/components/Tinymce/config.ts rename to src/admin/common/Rich/config.ts index 73f4bc58..fd1ca01c 100644 --- a/src/components/Tinymce/config.ts +++ b/src/admin/common/Rich/config.ts @@ -5,4 +5,4 @@ export const plugins = ['advlist anchor autolink autosave code codesample direct // Here is the list of toolbar control components // Details see: https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols -export const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'] +export const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table forecolor backcolor fullscreen'] diff --git a/src/admin/common/Rich/index.vue b/src/admin/common/Rich/index.vue index 90ae0296..5b1b69cd 100644 --- a/src/admin/common/Rich/index.vue +++ b/src/admin/common/Rich/index.vue @@ -1,29 +1,195 @@ diff --git a/src/auth/AuthPage.ts b/src/auth/AuthPage.ts deleted file mode 100644 index 4399ba24..00000000 --- a/src/auth/AuthPage.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default interface AuthPageTemplate { - icon?: string - title?: string - info?: any - btns?: Array -} - -export interface AuthBtn { - text?: string - bgcolor?: string - color?: string - width?: number - height?: number -} \ No newline at end of file diff --git a/src/auth/AuthPage.vue b/src/auth/AuthPage.vue deleted file mode 100644 index af0cf511..00000000 --- a/src/auth/AuthPage.vue +++ /dev/null @@ -1,251 +0,0 @@ - - - - - diff --git a/src/auth/AuthTemplate.vue b/src/auth/AuthTemplate.vue deleted file mode 100644 index c5025bc3..00000000 --- a/src/auth/AuthTemplate.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - - diff --git a/src/auth/flows/SaveAuthPage/nodes/SaveAuthPage.ts b/src/auth/flows/SaveAuthPage/nodes/SaveAuthPage.ts deleted file mode 100644 index 8176d6ca..00000000 --- a/src/auth/flows/SaveAuthPage/nodes/SaveAuthPage.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { APINode } from "arkfbp/lib/apiNode" -// import { jsonp } from 'vue-jsonp' - -export class SaveAuthPage extends APINode { - async run() { - this.url = this.inputs.url - this.method = 'POST' - this.params = { - html: this.inputs.html - } - await super.run() - } -} diff --git a/src/components/Tinymce/index.vue b/src/components/Tinymce/index.vue deleted file mode 100644 index f1a11c2c..00000000 --- a/src/components/Tinymce/index.vue +++ /dev/null @@ -1,222 +0,0 @@ - - - - - diff --git a/src/config/auth/auth_page.json b/src/config/auth/auth_page.json new file mode 100644 index 00000000..6ec7ce7c --- /dev/null +++ b/src/config/auth/auth_page.json @@ -0,0 +1,185 @@ +{ + "title": "自定义配置授权页面", + "visible": false, + "data": {}, + "state": { + "type": "FormPage", + "state": { + "title": "是否使用模板", + "select": { + "value": "first", + "options": [ + { + "value": "first", + "label": "使用模板" + }, + { + "value": "no", + "label": "不使用模板" + } + ] + }, + "forms": { + "first": { + "items": { + "icon": { + "type": "InputLink", + "label": "图标", + "prop": "icon", + "state": { + "value": "", + "placeholder": "请输入或上传图标" + } + }, + "title": { + "type": "Input", + "label": "标题", + "prop": "title", + "state": { + "value": "", + "placeholder": "请输入标题" + } + }, + "info": { + "type": "Rich", + "label": "授权信息", + "prop": "info", + "state": { + "value": "", + "isDisabledUploadImage": true + } + }, + "agree": { + "type": "FormPage", + "label": "确认按钮", + "prop": "agree", + "state": { + "form": { + "items": { + "text": { + "type": "Input", + "label": "文本", + "prop": "text", + "state": { + "placeholder": "请输入确认按钮文本", + "value": "" + } + }, + "tcolor": { + "type": "ColorPicker", + "label": "文本颜色", + "prop": "tcolor", + "state": { + "value": "" + } + }, + "bcolor": { + "type": "ColorPicker", + "label": "按钮颜色", + "prop": "tcolor", + "state": { + "value": "" + } + }, + "width": { + "type": "InputNumber", + "label": "长度", + "prop": "width", + "state": { + "value": 0 + } + }, + "height": { + "type": "InputNumber", + "label": "宽度", + "prop": "height", + "state": { + "value": 0 + } + } + } + } + } + }, + "cancel": { + "type": "FormPage", + "label": "取消按钮", + "prop": "cancel", + "state": { + "form": { + "items": { + "text": { + "type": "Input", + "label": "文本", + "prop": "text", + "state": { + "placeholder": "请输入取消按钮文本", + "value": "" + } + }, + "tcolor": { + "type": "ColorPicker", + "label": "文本颜色", + "prop": "tcolor", + "state": { + "value": "" + } + }, + "bcolor": { + "type": "ColorPicker", + "label": "按钮颜色", + "prop": "tcolor", + "state": { + "value": "" + } + }, + "width": { + "type": "InputNumber", + "label": "长度", + "prop": "width", + "state": { + "value": 0 + } + }, + "height": { + "type": "InputNumber", + "label": "宽度", + "prop": "height", + "state": { + "value": 0 + } + } + } + } + } + } + } + }, + "no": { + "items": { + "html": { + "type": "Input", + "label": "自定义HTML", + "prop": "html", + "state": { + "value": "", + "placeholder": "请输入完整的HTML文件信息", + "type": "textarea", + "autosize": { + "minRows": 20 + } + } + } + } + } + } + } + }, + "buttons": [ + { + "label": "保存", + "type": "primary", + "action": "saveTemplate" + } + ] +} \ No newline at end of file diff --git a/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts b/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts index 35b1f425..219e8f35 100644 --- a/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts +++ b/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts @@ -1,8 +1,10 @@ import { FunctionNode } from 'arkfbp/lib/functionNode' +import authPage from '@/config/auth/auth_page.json' export class AuthPageBtn extends FunctionNode { async run() { const tempState = this.inputs.state.state + // button const authPageBtn = { label: '配置授权页面', type: 'info', @@ -14,5 +16,47 @@ export class AuthPageBtn extends FunctionNode { name: 'flows/appManager/openAuthPage' } ] + tempState.actions!['saveTemplate'] = [ + { + name: 'flows/appManager/saveTemplate', + url: '/api/v1/tenant/{tenant_uuid}/app/{uuid}/add_auth_tmpl/', + method: 'POST', + request: { + template: { + value: 'dialogs.auth.state.state.select.value', + first: { + icon: 'dialogs.auth.state.state.forms.first.items.icon.state.value', + title: 'dialogs.auth.state.state.forms.first.items.title.state.value', + info: 'dialogs.auth.state.state.forms.first.items.info.state.value', + agree: { + text: 'dialogs.auth.state.state.forms.first.items.agree.state.form.items.text.state.value', + tcolor: 'dialogs.auth.state.state.forms.first.items.agree.state.form.items.tcolor.state.value', + bcolor: 'dialogs.auth.state.state.forms.first.items.agree.state.form.items.bcolor.state.value', + width: 'dialogs.auth.state.state.forms.first.items.agree.state.form.items.width.state.value', + height: 'dialogs.auth.state.state.forms.first.items.agree.state.form.items.height.state.value' + }, + cancel: { + text: 'dialogs.auth.state.state.forms.first.items.cancel.state.form.items.text.state.value', + tcolor: 'dialogs.auth.state.state.forms.first.items.cancel.state.form.items.tcolor.state.value', + bcolor: 'dialogs.auth.state.state.forms.first.items.cancel.state.form.items.bcolor.state.value', + width: 'dialogs.auth.state.state.forms.first.items.cancel.state.form.items.width.state.value', + height: 'dialogs.auth.state.state.forms.first.items.cancel.state.form.items.height.state.value' + } + }, + no: { + html: 'dialogs.auth.state.state.forms.no.items.html.state.value' + } + } + } + }, + { + name: 'arkfbp/flows/assign', + response: { + 'dialogs.auth.visible': false + } + } + ] + // dialog + tempState.dialogs.auth = authPage } } diff --git a/src/flows/appManager/openAuthPage/nodes/openAuthPage.ts b/src/flows/appManager/openAuthPage/nodes/openAuthPage.ts index f669d177..78b76fb2 100644 --- a/src/flows/appManager/openAuthPage/nodes/openAuthPage.ts +++ b/src/flows/appManager/openAuthPage/nodes/openAuthPage.ts @@ -1,18 +1,11 @@ import { FunctionNode } from 'arkfbp/lib/functionNode' -import { TenantModule } from '@/store/modules/tenant' export class OpenAuthPage extends FunctionNode { async run() { - const com = this.inputs.com - const router = com.$router - const data = com.state.data - const { href } = router.resolve({ - name: 'auth', - query: { - tenant: TenantModule.currentTenant.uuid, - app: data.uuid - } - }) - window.open(href, '_blank') + const state = this.inputs.client + const data = this.inputs.com.state.data + const auth = state.dialogs.auth + auth.data = data + auth.visible = true } } diff --git a/src/auth/flows/SaveAuthPage/index.ts b/src/flows/appManager/saveTemplate/index.ts similarity index 78% rename from src/auth/flows/SaveAuthPage/index.ts rename to src/flows/appManager/saveTemplate/index.ts index 26f2c339..cb73c372 100644 --- a/src/auth/flows/SaveAuthPage/index.ts +++ b/src/flows/appManager/saveTemplate/index.ts @@ -2,7 +2,7 @@ import { Flow } from 'arkfbp/lib/flow' import { Graph } from 'arkfbp/lib/graph' import { StartNode } from 'arkfbp/lib/startNode' import { StopNode } from 'arkfbp/lib/stopNode' -import { SaveAuthPage } from './nodes/SaveAuthPage' +import { SaveTemplate } from './nodes/saveTemplate' export class Main extends Flow { createNodes() { @@ -10,11 +10,11 @@ export class Main extends Flow { { cls: StartNode, id: 'start', - next: 'saveauthpage' + next: 'saveTemplate' }, { - cls: SaveAuthPage, - id: 'saveauthpage', + cls: SaveTemplate, + id: 'saveTemplate', next: 'stop' }, { diff --git a/src/flows/appManager/saveTemplate/nodes/saveTemplate.ts b/src/flows/appManager/saveTemplate/nodes/saveTemplate.ts new file mode 100644 index 00000000..e20e99fe --- /dev/null +++ b/src/flows/appManager/saveTemplate/nodes/saveTemplate.ts @@ -0,0 +1,110 @@ +import { AuthApiNode } from "@/arkfbp/nodes/authApiNode" + +interface AuthTemplate { + icon?: string + title?: string + info?: string + agree?: AuthButton + cancel?: AuthButton +} + +interface AuthButton { + text?: string + tcolor?: string + bcolor?: string + width?: number + height?: number +} + +export class SaveTemplate extends AuthApiNode { + + private style: string = '' + + private template: AuthTemplate = {} + + async run() { + const { template, ...args } = this.inputs.params + this.template = args + const html = template !== 'no' ? this.getTemplateHtml() : args.html + this.url = this.inputs.url + this.method = 'POST' + this.params = { + html: html + } + await super.run() + } + + getTemplateHtml() { + const template = document.createElement('html') + const head = document.createElement('head') + head.innerHTML = '应用授权' + const body = document.createElement('body') + const auth = this.initAuthPage() + body.appendChild(auth) + const style = document.createElement('style') + style.innerHTML = this.style + head.appendChild(style) + template.appendChild(head) + template.appendChild(body) + const page = '' + template.innerHTML + '' + return page + } + + initAuthPage() { + const auth = this.createAuthElement('div', ['auth'], '.auth{width: 500px;height: auto;position: absolute;top: 30%;left: 50%;transform: translateX(-50%) translateY(-50%);background-color: #fff;padding: 15px;box-shadow: 0 2px 16px #D3CECE, 0 0 1px #D3CECE, 0 0 1px #D3CECE;}') + const header = this.initAuthPageHeader() + const info = this.initAuthPageInfo() + const footer = this.initAuthPageBtns() + auth.appendChild(header) + auth.appendChild(info) + auth.appendChild(footer) + return auth + } + + initAuthPageHeader() { + const header = this.createAuthElement('div', ['header'], '.header{text-align: center;}') + if (this.template.icon) { + const icon = this.createAuthElement('img', ['icon'], '.icon{width: 60px;}') + icon.setAttribute('src', this.template.icon) + header.appendChild(icon) + } + if (this.template.title) { + const title = this.createAuthElement('div', ['title'], '.title{font-size: 20px;font-weight: bold;}') + title.innerHTML = this.template.title + header.appendChild(title) + } + return header + } + + initAuthPageInfo() { + const info = this.createAuthElement('div', ['info'], '') + info.innerHTML = this.template.info || '' + return info + } + + initAuthPageBtns() { + const footer = this.createAuthElement('form', ['footer'], '.footer{margin-top: 20px;}') + footer.setAttribute('method', 'post') + const crsf = this.createAuthElement('span', ['crsf'], '.crsf{display: none}') + crsf.innerHTML = '{% csrf_token %}' + footer.appendChild(crsf) + const agreeBtn = this.createAuthElement('input', ['btn', 'agree'], `.btn{width: ${this.template.agree?.width || 360}px;height: ${this.template.agree?.height || 36}px;display: block;margin-bottom: 10px;position: relative;left: 50%;transform: translateX(-50%);border: 0px;cursor: pointer;}.agree{background-color: ${this.template.agree?.bcolor || 'rgb(177, 31, 31)'};color: ${this.template.agree?.tcolor || 'white'};}`) + agreeBtn.setAttribute('value', this.template.agree?.text || '授 权') + agreeBtn.setAttribute('type', 'submit') + agreeBtn.setAttribute('name', 'allow') + const cancelBtn = this.createAuthElement('input', ['btn', 'cancel'], `.cancel{background-color: ${this.template.cancel?.bcolor || ''};color: ${this.template.cancel?.tcolor || ''};}`) + cancelBtn.setAttribute('value', this.template.cancel?.text || '取 消') + cancelBtn.setAttribute('type', 'submit') + footer.appendChild(agreeBtn) + footer.appendChild(cancelBtn) + return footer + } + + createAuthElement(type: string, classNames: Array, style: string) { + const el = document.createElement(type) + el.className = classNames.join(' ') + this.style = this.style + style + return el + } + +} diff --git a/src/flows/initPage/nodes/initPage.ts b/src/flows/initPage/nodes/initPage.ts index 38f611b4..36a983ad 100644 --- a/src/flows/initPage/nodes/initPage.ts +++ b/src/flows/initPage/nodes/initPage.ts @@ -48,7 +48,7 @@ export class InitPage extends FunctionNode { async runCustomPageFlow(state: any, initContent: ITagPage, currentPage: string) { let curstomPageFlow: string = '' switch (currentPage) { - case 'app': + case 'app_list': curstomPageFlow = 'flows/appManager/authPageBtn' break case 'group': diff --git a/src/router/index.ts b/src/router/index.ts index 99d0507f..988b0668 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -56,12 +56,6 @@ export const menuRoutes: RouteConfig[] = [ component: () => import(/* webpackChunkName: "login" */ '@/views/tenant/TenantManager.vue'), meta: { hidden: true, page: 'tenant' } }, - { - path: '/auth', - component: () => import(/* webpackChunkName: "login" */ '@/auth/AuthPage.vue'), - meta: { hidden: true, page: 'auth' }, - name: 'auth' - }, { path: '/', component: Layout, From fdb59b23df9e1eb1737b0fdfbc69a604d5a5a727 Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Tue, 22 Jun 2021 15:59:24 +0800 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=AF=8C=E6=96=87=E6=9C=AC=E9=AB=98=E5=BA=A6=E5=AE=BD=E5=BA=A6?= =?UTF-8?q?=E7=AD=89=E9=BB=98=E8=AE=A4=E6=A0=B7=E5=BC=8F=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=AD=89=E9=97=AE=E9=A2=98,=20=E4=BB=A5=E5=8F=8Aaction?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/admin/common/Rich/index.vue | 8 +++++++- src/arkfbp/index.ts | 4 ---- src/arkfbp/nodes/clientResponseNode.ts | 3 +-- src/utils/generate-action.ts | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/admin/common/Rich/index.vue b/src/admin/common/Rich/index.vue index 5b1b69cd..2b69152e 100644 --- a/src/admin/common/Rich/index.vue +++ b/src/admin/common/Rich/index.vue @@ -2,7 +2,7 @@
{ diff --git a/src/arkfbp/nodes/clientResponseNode.ts b/src/arkfbp/nodes/clientResponseNode.ts index 47fcc3a7..913a9d51 100644 --- a/src/arkfbp/nodes/clientResponseNode.ts +++ b/src/arkfbp/nodes/clientResponseNode.ts @@ -33,7 +33,6 @@ export class ClientResponseNode extends FunctionNode { } } // 判断此时的类型内容 -- 之后需要进一步增大兼容性 - if (temp) { const lastKey = ks[len - 1] if (type === 'fetch') { @@ -58,7 +57,7 @@ export class ClientResponseNode extends FunctionNode { temp[lastKey] = res } } else if (type === 'assign') { - temp[lastKey] = temp?.default || clientServer[key] + temp[lastKey] = clientServer[key] || temp?.default } } }) diff --git a/src/utils/generate-action.ts b/src/utils/generate-action.ts index 6136258e..300d4aca 100644 --- a/src/utils/generate-action.ts +++ b/src/utils/generate-action.ts @@ -23,7 +23,7 @@ export default function generateAction(path: string, method: string, target: str required = { [ propertyName ]: {} } const objRequired = required[propertyName] Object.keys(schema.discriminator.mapping).forEach(key => { - const itemTarget = `${target}forms[${key}].items.` + const itemTarget = `${target}forms.${key}.items.` const itemRef = schema.discriminator!.mapping[key] const itemSchema = OpenAPI.instance.getSchemaByRef(itemRef) const items = itemSchema.properties From f0eba44341c7e163e236b8f5d08bc79c9bd142c3 Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Tue, 22 Jun 2021 19:52:24 +0800 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=9C=A8=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=B3=A8=E5=86=8C=E9=85=8D=E7=BD=AE=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=96=B0=E5=A2=9E'=E6=98=AF=E5=90=A6=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E8=87=AA=E5=8A=A8=E9=80=80=E5=87=BA'?= =?UTF-8?q?=E9=80=89=E9=A1=B9,=20=E5=A6=82=E6=9E=9C=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E8=AF=A5=E9=80=89=E9=A1=B9,=20=E5=BD=93=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=90=8E=E9=87=8D=E6=96=B0=E6=89=93=E5=BC=80?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E9=87=8D=E6=96=B0=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 29 ++++++++++++++++++ src/admin/base/BaseVue.ts | 2 +- src/flows/init/nodes/afterLogin.ts | 10 +++++++ src/flows/initPage/nodes/initPage.ts | 3 ++ .../loginRegisterConfig/updated/index.ts | 30 +++++++++++++++++++ .../updated/nodes/loginRegisterConfig.ts | 13 ++++++++ src/flows/user/logout/nodes/logout.ts | 2 +- src/store/modules/global-value.ts | 9 +++++- 8 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/flows/loginRegisterConfig/updated/index.ts create mode 100644 src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts diff --git a/src/App.vue b/src/App.vue index db406c7e..2158d9ce 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,6 +10,9 @@ diff --git a/src/admin/base/BaseVue.ts b/src/admin/base/BaseVue.ts index 82192c13..d2e2eed6 100644 --- a/src/admin/base/BaseVue.ts +++ b/src/admin/base/BaseVue.ts @@ -70,7 +70,7 @@ export default class extends Vue { async runAction(action?: string | Function) { if (action) { if (action instanceof Function) { - action() + action(this) } else { await runFlowByActionName(this, action) } diff --git a/src/flows/init/nodes/afterLogin.ts b/src/flows/init/nodes/afterLogin.ts index 2771afcb..18d0e3bf 100644 --- a/src/flows/init/nodes/afterLogin.ts +++ b/src/flows/init/nodes/afterLogin.ts @@ -2,6 +2,7 @@ import { AuthApiNode } from '@/arkfbp/nodes/authApiNode' import OpenAPI from '@/config/openapi' import { UserModule, UserRole } from '@/store/modules/user' import { TenantModule } from '@/store/modules/tenant' +import { GlobalValueModule } from '@/store/modules/global-value' import processUUId from '@/utils/process-uuid' export class AfterLogin extends AuthApiNode { @@ -17,6 +18,8 @@ export class AfterLogin extends AuthApiNode { await this.setCurrentUserInfo() // 获取用户权限 await this.setCurrentUserPermission() + // 获取config + await this.setTenantConfig() } async setCurrentTenantInfo() { @@ -60,4 +63,11 @@ export class AfterLogin extends AuthApiNode { } } + async setTenantConfig() { + this.url = `/api/v1/tenant/${TenantModule.currentTenant.uuid}/config/` + this.method = 'GET' + const { data } = await super.run() + GlobalValueModule.setClosePageAutoLogout(data?.close_page_auto_logout || false) + } + } diff --git a/src/flows/initPage/nodes/initPage.ts b/src/flows/initPage/nodes/initPage.ts index 36a983ad..29e7f828 100644 --- a/src/flows/initPage/nodes/initPage.ts +++ b/src/flows/initPage/nodes/initPage.ts @@ -59,6 +59,9 @@ export class InitPage extends FunctionNode { break case 'third_party_account': curstomPageFlow = 'flows/thirdPartyAccount/addUnbindButton' + break + case 'lr_config': + curstomPageFlow = 'flows/loginRegisterConfig/updated' } if (curstomPageFlow !== '') { await runFlowByFile(curstomPageFlow, { diff --git a/src/flows/loginRegisterConfig/updated/index.ts b/src/flows/loginRegisterConfig/updated/index.ts new file mode 100644 index 00000000..5b524830 --- /dev/null +++ b/src/flows/loginRegisterConfig/updated/index.ts @@ -0,0 +1,30 @@ +import { Flow } from 'arkfbp/lib/flow' +import { Graph } from 'arkfbp/lib/graph' +import { StartNode } from 'arkfbp/lib/startNode' +import { StopNode } from 'arkfbp/lib/stopNode' +import { LoginRegisterConfig } from './nodes/loginRegisterConfig' + +export class Main extends Flow { + createNodes() { + return [ + { + cls: StartNode, + id: 'start', + next: 'loginRegisterConfig' + }, { + cls: LoginRegisterConfig, + id: 'loginRegisterConfig', + next: 'stop' + }, { + cls: StopNode, + id: 'stop' + } + ] + } + + createGraph() { + const g = new Graph() + g.nodes = this.createNodes() + return g + } +} diff --git a/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts b/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts new file mode 100644 index 00000000..d63368fb --- /dev/null +++ b/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts @@ -0,0 +1,13 @@ +import { FunctionNode } from 'arkfbp/lib/functionNode' +import { GlobalValueModule } from '@/store/modules/global-value' + +export class LoginRegisterConfig extends FunctionNode { + async run() { + const tempState = this.inputs.state + const saveConfig = (com) => { + const value = com.state.value + GlobalValueModule.setClosePageAutoLogout(value) + } + tempState.state.form.items.data.state.items.close_page_auto_logout.state.updated = saveConfig + } +} \ No newline at end of file diff --git a/src/flows/user/logout/nodes/logout.ts b/src/flows/user/logout/nodes/logout.ts index 2349803c..a106fb36 100644 --- a/src/flows/user/logout/nodes/logout.ts +++ b/src/flows/user/logout/nodes/logout.ts @@ -9,7 +9,7 @@ export class Logout extends AuthApiNode { const outputs = await super.run() if (outputs.is_succeed) { removeToken() - router.push('/login') + if (router) router.push('/login') } } } \ No newline at end of file diff --git a/src/store/modules/global-value.ts b/src/store/modules/global-value.ts index 3ff6922c..36337605 100644 --- a/src/store/modules/global-value.ts +++ b/src/store/modules/global-value.ts @@ -4,12 +4,14 @@ import store from '@/store' export interface IGlobalValueState { originUrl: string slug: string + closePageAutoLogout: boolean } -@Module({ dynamic: true, store, name: 'flow' }) +@Module({ dynamic: true, store, name: 'global' }) class GlobalValue extends VuexModule implements IGlobalValueState { public originUrl: string = '' public slug: string = '' + public closePageAutoLogout: boolean = false @Mutation setOriginUrl(url: string) { @@ -21,6 +23,11 @@ class GlobalValue extends VuexModule implements IGlobalValueState { this.slug = slug } + @Mutation + setClosePageAutoLogout(value: boolean) { + this.closePageAutoLogout = value + } + } export const GlobalValueModule = getModule(GlobalValue) From 2f4d10d8378b65a919bc2e2959ca33697ce76c7c Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Wed, 23 Jun 2021 13:55:47 +0800 Subject: [PATCH 04/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?arkfbp=E4=B8=AD=E7=9A=84clientResponseNode=E7=AD=89=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/arkfbp/flows/assign/index.ts | 5 + src/arkfbp/flows/assign/nodes/assign.ts | 12 +-- src/arkfbp/flows/fetch/nodes/fetch.ts | 6 +- .../flows/fetchTree/nodes/changeTreeState.ts | 4 +- src/arkfbp/flows/password/nodes/password.ts | 12 +-- src/arkfbp/index.ts | 2 +- src/arkfbp/nodes/clientResponseNode.ts | 100 ++++++++---------- src/constants/error.ts | 1 + .../group/fetchTable/nodes/fetchTable.ts | 2 - src/utils/flow.ts | 28 ++++- src/utils/state-filter.ts | 26 ----- 11 files changed, 87 insertions(+), 111 deletions(-) delete mode 100644 src/utils/state-filter.ts diff --git a/src/arkfbp/flows/assign/index.ts b/src/arkfbp/flows/assign/index.ts index fefd52e5..00f00964 100644 --- a/src/arkfbp/flows/assign/index.ts +++ b/src/arkfbp/flows/assign/index.ts @@ -3,6 +3,7 @@ import { Graph } from 'arkfbp/lib/graph' import { StartNode } from 'arkfbp/lib/startNode' import { StopNode } from 'arkfbp/lib/stopNode' import { Assign } from './nodes/assign' +import { ClientResponseNode } from '@/arkfbp/nodes/clientResponseNode' export class Main extends Flow { createNodes() { @@ -13,6 +14,10 @@ export class Main extends Flow { }, { cls: Assign, id: 'assign', + next: 'clientResponseNode' + }, { + cls: ClientResponseNode, + id: 'clientResponseNode', next: 'stop' }, { cls: StopNode, diff --git a/src/arkfbp/flows/assign/nodes/assign.ts b/src/arkfbp/flows/assign/nodes/assign.ts index ff1b5b08..61101b30 100644 --- a/src/arkfbp/flows/assign/nodes/assign.ts +++ b/src/arkfbp/flows/assign/nodes/assign.ts @@ -1,13 +1,9 @@ -import { ClientResponseNode } from '@/arkfbp/nodes/clientResponseNode' -import { proxyClientServer } from '@/utils/flow' +import { FunctionNode } from 'arkfbp/lib/functionNode' -export class Assign extends ClientResponseNode { +export class Assign extends FunctionNode { async run() { - this.$state.commit(state => { - state.type = 'assign' - state.client = this.inputs.client - state.clientServer = proxyClientServer(this.inputs.clientServer) + this.$state.commit((state: any) => { + state.inputs = this.inputs }) - await super.run() } } diff --git a/src/arkfbp/flows/fetch/nodes/fetch.ts b/src/arkfbp/flows/fetch/nodes/fetch.ts index 84bd71fb..dd8a994d 100644 --- a/src/arkfbp/flows/fetch/nodes/fetch.ts +++ b/src/arkfbp/flows/fetch/nodes/fetch.ts @@ -1,5 +1,4 @@ import { AuthApiNode } from '@/arkfbp/nodes/authApiNode' -import { proxyClientServer } from '@/utils/flow' export class Fetch extends AuthApiNode { async run() { @@ -8,10 +7,7 @@ export class Fetch extends AuthApiNode { this.params = this.inputs.params const outputs = await super.run() this.$state.commit((state: any) => { - state.client = this.inputs.client - state.clientServer = proxyClientServer(this.inputs.clientServer, outputs) - state.type = 'fetch' - state.com = this.inputs.com + state.inputs = this.inputs }) return outputs } diff --git a/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts b/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts index b93f63de..44dc6be0 100644 --- a/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts +++ b/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts @@ -3,9 +3,7 @@ import getTreeData from '@/utils/get-tree-data' export class ChangeTreeState extends ClientResponseNode { async run() { - const res = this.inputs - const data = getTreeData(res.results) - this.inputs.results = data + this.inputs.results = getTreeData(this.inputs.results) await super.run() } } diff --git a/src/arkfbp/flows/password/nodes/password.ts b/src/arkfbp/flows/password/nodes/password.ts index f0a12d40..38f6f0b4 100644 --- a/src/arkfbp/flows/password/nodes/password.ts +++ b/src/arkfbp/flows/password/nodes/password.ts @@ -1,7 +1,5 @@ import { Update } from '@/arkfbp/flows/update/nodes/update' import { UserModule } from '@/store/modules/user' -import { FlowModule } from '@/store/modules/flow' -import { error } from '@/constants/error' export class Password extends Update { async run() { @@ -15,14 +13,6 @@ export class Password extends Update { this.inputs.url = url this.inputs.method = method this.inputs.params = params - const outputs = await super.run() - if (outputs.error) { - FlowModule.stopRunFlow() - com.$message({ - message: error[outputs.error], - type: 'error', - showClose: true, - }) - } + await super.run() } } diff --git a/src/arkfbp/index.ts b/src/arkfbp/index.ts index 9d0f8769..abe0af30 100644 --- a/src/arkfbp/index.ts +++ b/src/arkfbp/index.ts @@ -1,6 +1,6 @@ import { runWorkflowByClass } from 'arkfbp/lib/flow' import { getCurrentPageState } from '@/utils/get-page-state' -import stateFilter from '@/utils/state-filter' +import { stateFilter } from '@/utils/flow' import getUrl from '@/utils/url' import { FlowModule } from '@/store/modules/flow' diff --git a/src/arkfbp/nodes/clientResponseNode.ts b/src/arkfbp/nodes/clientResponseNode.ts index 913a9d51..e14bd245 100644 --- a/src/arkfbp/nodes/clientResponseNode.ts +++ b/src/arkfbp/nodes/clientResponseNode.ts @@ -1,67 +1,59 @@ import { FunctionNode } from 'arkfbp/lib/functionNode' -import stateFilter from '@/utils/state-filter' +import { proxyClientServer, stateFilter } from '@/utils/flow' +// 客户端响应节点 export class ClientResponseNode extends FunctionNode { async run() { - // 客户端进行响应的必要内容说明 // client 代表当前页面的 state // clientServer 代表需要进行响应的数据映射关系 - // data 代表刚刚请求的返回的数据内容 -- fetch和update时使用 - // type 代表为那种响应类型 - const { client, clientServer } = this.$state.fetch() + // data 代表刚刚请求的返回的数据内容 -- 只有fetch时才存在 + if (!this.$state.fetch().inputs) { return null } + let { client, clientServer } = this.$state.fetch().inputs let data = this.inputs - if (!data) { - return null + clientServer = proxyClientServer(clientServer, data) + + if (!clientServer || !client) { + throw new Error('ClientResponseNode Error') } - const type = this.$state.fetch().type - // start to change - if (clientServer && client) { - Object.keys(clientServer).forEach((key) => { - const ks = key.split('.') - const len = ks.length - let temp = client - for (let i = 0; i < len - 1; i++) { - if (!temp) break - const k = ks[i] - if (k.includes('[')) { - const idx = k.indexOf('[') - const firstKey = k.substring(0, idx) - const secondKey = stateFilter(k, temp) - temp = temp[firstKey][secondKey] - } else { - temp = temp[k] - } + + const keys = Object.keys(clientServer) + const length = keys.length + for (let i = 0; i < length; i++) { + const key = keys[i] + const splitKeys = key.split('.') + const splitLength = splitKeys.length - 1 + let tempC = client + for (let j = 0; j < splitLength; j++) { + if (!tempC) break + const splitKey = splitKeys[j] + if (splitKey.indexOf('[') >= 0) { + const idx = splitKey.indexOf('[') + const firstKey = splitKey.substring(0, idx) + const secondKey = stateFilter(splitKey, tempC) + tempC = tempC[firstKey][secondKey] + } else { + tempC = tempC[splitKey] + } + } + if (!tempC) continue + const lastKey = splitKeys[splitLength] + if (data) { + const valueMapping = clientServer[key].split('.') + let tempS = data + const valueMappinglength = valueMapping.length - 1 + for (let k = 0; k < valueMappinglength; k++) { + if (!tempS) break + tempS = tempS[valueMapping[k]] } - // 判断此时的类型内容 -- 之后需要进一步增大兼容性 - if (temp) { - const lastKey = ks[len - 1] - if (type === 'fetch') { - const vs = clientServer[key].split('.') - let tempS = data - for (let i = 0; i < vs.length - 1; i++) { - if (!tempS) break - tempS = tempS[vs[i]] - } - let res = tempS ? tempS[vs[vs.length - 1]] : undefined - if (res === undefined) { - if (lastKey !== 'value') { - res = clientServer[key] - } - if (lastKey === 'data') { - res = tempS - } - } - if (lastKey === 'disabled') { - temp[lastKey] = res ? false : true - } else { - temp[lastKey] = res - } - } else if (type === 'assign') { - temp[lastKey] = clientServer[key] || temp?.default - } + let value = tempS ? tempS[valueMapping[valueMappinglength]] : undefined + if (value === undefined) { + if (lastKey !== 'value' && lastKey !== 'data') { value = clientServer[key] } + if (lastKey === 'data') { value = tempS } } - }) + tempC[lastKey] = lastKey === 'disabled' ? !value : value + } else { + tempC[lastKey] = clientServer[key] || tempC?.default + } } - return this.inputs } } diff --git a/src/constants/error.ts b/src/constants/error.ts index 53d0ed88..842f088c 100644 --- a/src/constants/error.ts +++ b/src/constants/error.ts @@ -12,6 +12,7 @@ export const error = { '10011': '旧密码错误', '10013': 'slug已经存在', '10014': '注册过于频繁', + '10020': '新密码与旧密码重复', '11001': '没有注册短信插件', '11002': '没有注册验证码插件', '11003': '没有注册存储插件', diff --git a/src/flows/group/fetchTable/nodes/fetchTable.ts b/src/flows/group/fetchTable/nodes/fetchTable.ts index 6fe47843..b7b6bcb8 100644 --- a/src/flows/group/fetchTable/nodes/fetchTable.ts +++ b/src/flows/group/fetchTable/nodes/fetchTable.ts @@ -15,8 +15,6 @@ export class FetchTable extends Fetch { } const outputs = await super.run() return outputs - } else { - return null } } } diff --git a/src/utils/flow.ts b/src/utils/flow.ts index 293cc3be..8645144a 100644 --- a/src/utils/flow.ts +++ b/src/utils/flow.ts @@ -1,4 +1,4 @@ -import { isArray } from '@/utils/common' +import { isArray, stringConvertNumber } from '@/utils/common' export function proxyClientServer(clientServer: any, data?: any) { let proxyClientServer = {} @@ -6,6 +6,7 @@ export function proxyClientServer(clientServer: any, data?: any) { const cs = clientServer[key] if (typeof cs === 'object') { const val = data ? data[cs.value] : undefined + proxyClientServer = { [key]: cs.value } if (val) { Object.assign(proxyClientServer, cs[val]) } else { @@ -38,4 +39,29 @@ export function isLackRequiredParams(params: any, required: any): boolean { } } return lackRequiredParams +} + +export function stateFilter(strEquality: string, state: any): number | string { + let secondKey: number | string = 0 + const leftBracketIndex = strEquality.indexOf('[') + const rightBracketIndex = strEquality.indexOf(']') + const arrayStateMapping = strEquality.slice(leftBracketIndex + 1, rightBracketIndex) + if (arrayStateMapping.indexOf('=') < 0) { + secondKey = stringConvertNumber(arrayStateMapping) + } else { + const arrayStateMappingSpilt = arrayStateMapping.split('=') + const representKey = arrayStateMappingSpilt[0] + const representValue = arrayStateMappingSpilt[1] + const requiredStateKey = strEquality.substring(0, leftBracketIndex) + const target = state[requiredStateKey] + if (isArray(target)) { + for (let i = 0, len = target.length; i < len; i++) { + if (target[i][representKey] === representValue) { + secondKey = i + break + } + } + } + } + return secondKey } \ No newline at end of file diff --git a/src/utils/state-filter.ts b/src/utils/state-filter.ts deleted file mode 100644 index 7a18cfea..00000000 --- a/src/utils/state-filter.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { isArray, stringConvertNumber } from '@/utils/common' - -export default function stateFilter(strEquality: string, state: any): number | string { - let secondKey: number | string = 0 - const leftBracketIndex = strEquality.indexOf('[') - const rightBracketIndex = strEquality.indexOf(']') - const arrayStateMapping = strEquality.slice(leftBracketIndex + 1, rightBracketIndex) - if (arrayStateMapping.indexOf('=') < 0) { - secondKey = stringConvertNumber(arrayStateMapping) - } else { - const arrayStateMappingSpilt = arrayStateMapping.split('=') - const representKey = arrayStateMappingSpilt[0] - const representValue = arrayStateMappingSpilt[1] - const requiredStateKey = strEquality.substring(0, leftBracketIndex) - const target = state[requiredStateKey] - if (isArray(target)) { - for (let i = 0, len = target.length; i < len; i++) { - if (target[i][representKey] === representValue) { - secondKey = i - break - } - } - } - } - return secondKey -} \ No newline at end of file From 298ece2fa223383eb1fc245906006543ecd1f12a Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Wed, 23 Jun 2021 15:59:42 +0800 Subject: [PATCH 05/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?loginRegisterConfig=E9=A1=B5=E9=9D=A2=E7=9A=84=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E4=BA=8B=E4=BB=B6=E5=86=85=E5=AE=B9=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E5=AF=B9=E9=83=A8=E5=88=86=E9=A1=B5=E9=9D=A2=E5=B1=95?= =?UTF-8?q?=E7=A4=BAreadOnly=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/admin/base/BaseVue.ts | 2 +- src/admin/common/Form/Input/InputState.ts | 1 + src/admin/common/Form/Input/index.vue | 35 +++++++- .../common/Form/InputLink/InputLinkState.ts | 6 -- src/admin/common/Form/InputLink/index.vue | 82 ------------------- src/admin/index.ts | 2 - .../flows/fetchTree/nodes/changeTreeState.ts | 2 +- src/arkfbp/nodes/clientResponseNode.ts | 3 +- src/flows/basePage/nodes/stateNode.ts | 22 ++--- src/flows/init/nodes/afterLogin.ts | 2 +- src/flows/initPage/nodes/initPage.ts | 13 +-- .../loginRegisterConfig/saveConfig/index.ts | 30 +++++++ .../saveConfig/nodes/saveConfig.ts | 9 ++ .../updated/nodes/loginRegisterConfig.ts | 11 +-- src/store/modules/global-value.ts | 12 ++- src/utils/dialog.ts | 10 ++- src/utils/flow.ts | 2 +- src/utils/form.ts | 5 +- src/utils/rules.ts | 36 +++++++- 19 files changed, 158 insertions(+), 127 deletions(-) delete mode 100644 src/admin/common/Form/InputLink/InputLinkState.ts delete mode 100644 src/admin/common/Form/InputLink/index.vue create mode 100644 src/flows/loginRegisterConfig/saveConfig/index.ts create mode 100644 src/flows/loginRegisterConfig/saveConfig/nodes/saveConfig.ts diff --git a/src/admin/base/BaseVue.ts b/src/admin/base/BaseVue.ts index d2e2eed6..82192c13 100644 --- a/src/admin/base/BaseVue.ts +++ b/src/admin/base/BaseVue.ts @@ -70,7 +70,7 @@ export default class extends Vue { async runAction(action?: string | Function) { if (action) { if (action instanceof Function) { - action(this) + action() } else { await runFlowByActionName(this, action) } diff --git a/src/admin/common/Form/Input/InputState.ts b/src/admin/common/Form/Input/InputState.ts index ec1aa787..d19b0ccd 100644 --- a/src/admin/common/Form/Input/InputState.ts +++ b/src/admin/common/Form/Input/InputState.ts @@ -30,4 +30,5 @@ export default interface InputState extends BaseState { format?: string // 输入的内容所需要遵循的格式,可以在 utils/rules中进行查找 hint?: string // 输入后如果不符合格式要求则显示提示信息 required?: boolean // 是否为必填项 + file?: File // 当input输入框为link时,可以上传图片文件 } diff --git a/src/admin/common/Form/Input/index.vue b/src/admin/common/Form/Input/index.vue index 358f030d..3ab979b9 100644 --- a/src/admin/common/Form/Input/index.vue +++ b/src/admin/common/Form/Input/index.vue @@ -17,7 +17,22 @@ :autocomplete="state.autocomplete" @blur="onBlur" @paste.native.capture="onPaste" - /> + > + + diff --git a/src/admin/common/Form/InputLink/InputLinkState.ts b/src/admin/common/Form/InputLink/InputLinkState.ts deleted file mode 100644 index 0004636b..00000000 --- a/src/admin/common/Form/InputLink/InputLinkState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import InputState from '../Input/InputState' - -export default interface InputLinkState extends InputState { - action?: string | Function - file?: File -} \ No newline at end of file diff --git a/src/admin/common/Form/InputLink/index.vue b/src/admin/common/Form/InputLink/index.vue deleted file mode 100644 index f8fcbfbf..00000000 --- a/src/admin/common/Form/InputLink/index.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - - - diff --git a/src/admin/index.ts b/src/admin/index.ts index b547a4e2..49682404 100644 --- a/src/admin/index.ts +++ b/src/admin/index.ts @@ -4,7 +4,6 @@ import Button from '@/admin/common/Button/index.vue' import ButtonArray from '@/admin/common/Button/ButtonArray/index.vue' import Link from '@/admin/common/Link/index.vue' import Input from '@/admin/common/Form/Input/index.vue' -import InputLink from '@/admin/common/Form/InputLink/index.vue' import InputList from '@/admin/common/Form/InputList/index.vue' import Cascader from '@/admin/common/Form/Cascader/index.vue' import Select from '@/admin/common/Form/Select/index.vue' @@ -62,7 +61,6 @@ Vue.component('ButtonArray', ButtonArray) Vue.component('Link', Link) Vue.component('Input', Input) Vue.component('InputList', InputList) -Vue.component('InputLink', InputLink) Vue.component('Cascader', Cascader) Vue.component('Select', Select) Vue.component('Avator', Avator) diff --git a/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts b/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts index 44dc6be0..afee53d9 100644 --- a/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts +++ b/src/arkfbp/flows/fetchTree/nodes/changeTreeState.ts @@ -4,6 +4,6 @@ import getTreeData from '@/utils/get-tree-data' export class ChangeTreeState extends ClientResponseNode { async run() { this.inputs.results = getTreeData(this.inputs.results) - await super.run() + return await super.run() } } diff --git a/src/arkfbp/nodes/clientResponseNode.ts b/src/arkfbp/nodes/clientResponseNode.ts index e14bd245..d2e36cc0 100644 --- a/src/arkfbp/nodes/clientResponseNode.ts +++ b/src/arkfbp/nodes/clientResponseNode.ts @@ -52,7 +52,8 @@ export class ClientResponseNode extends FunctionNode { } tempC[lastKey] = lastKey === 'disabled' ? !value : value } else { - tempC[lastKey] = clientServer[key] || tempC?.default + const value = (clientServer[key] !== undefined) ? clientServer[key] : tempC[lastKey] + tempC[lastKey] = value } } } diff --git a/src/flows/basePage/nodes/stateNode.ts b/src/flows/basePage/nodes/stateNode.ts index 01e3c7f8..c33db504 100644 --- a/src/flows/basePage/nodes/stateNode.ts +++ b/src/flows/basePage/nodes/stateNode.ts @@ -12,11 +12,11 @@ import whetherImportListDialog from '@/utils/list-dialog' export class StateNode extends FunctionNode { async run() { - const { initContent, state } = this.inputs + const { initContent, state, currentPage } = this.inputs const initPath = initContent.init?.path const initMethod = initContent.init?.method this.initPage(state, initPath, initMethod) - this.initOperation(state, initContent) + this.initOperation(state, initContent, currentPage) return this.inputs } @@ -38,18 +38,18 @@ export class StateNode extends FunctionNode { } } - initOperation(pageState: BasePage, initContent: ITagPage) { + initOperation(pageState: BasePage, initContent: ITagPage, currentPage: string) { const state = pageState.state if (!state.dialogs) state.dialogs = {} if (initContent.page) { - this.initPageBtnState(pageState, initContent) + this.initPageBtnState(pageState, initContent, currentPage) } if (initContent.item) { - this.initItemBtnState(pageState, initContent) + this.initItemBtnState(pageState, initContent, currentPage) } } - initPageBtnState(pageState: BasePage, initContent: ITagPage) { + initPageBtnState(pageState: BasePage, initContent: ITagPage, currentPage: string) { const { state, type } = pageState const page = initContent.page const pagekeys = Object.keys(page!) @@ -57,12 +57,12 @@ export class StateNode extends FunctionNode { const key = pagekeys[i] const action = (initContent.page![key] as ITagInitUpdateAction).read || initContent.page![key] const { path, method } = action - this.initDialogState(state, path, method, key) + this.initDialogState(state, path, method, key, currentPage) this.initCardButtons(state, key, type, path, method) } } - initItemBtnState(pageState: BasePage, initContent: ITagPage) { + initItemBtnState(pageState: BasePage, initContent: ITagPage, currentPage: string) { const { state, type } = pageState const items = initContent.item const itemkeys = Object.keys(items!) @@ -71,7 +71,7 @@ export class StateNode extends FunctionNode { if (key === 'children') break const action = (initContent.item![key] as ITagInitUpdateAction).read || initContent.item![key] const { path, method } = action - this.initDialogState(state, path, method, key) + this.initDialogState(state, path, method, key, currentPage) if (key === 'sort') { this.initSortButtons(state, action) } else { @@ -80,9 +80,9 @@ export class StateNode extends FunctionNode { } } - initDialogState(state: IPage, path: string, method: string, key: string) { + initDialogState(state: IPage, path: string, method: string, key: string, currentPage: string) { if (!path || !method) return - const dialogState = generateDialogState(path, method, key) // showReadOnly + const dialogState = generateDialogState(path, method, key, currentPage) // showReadOnly if (dialogState) { state.dialogs![key] = dialogState const importListDialog = whetherImportListDialog(dialogState.state.state) diff --git a/src/flows/init/nodes/afterLogin.ts b/src/flows/init/nodes/afterLogin.ts index 18d0e3bf..6c84dae6 100644 --- a/src/flows/init/nodes/afterLogin.ts +++ b/src/flows/init/nodes/afterLogin.ts @@ -67,7 +67,7 @@ export class AfterLogin extends AuthApiNode { this.url = `/api/v1/tenant/${TenantModule.currentTenant.uuid}/config/` this.method = 'GET' const { data } = await super.run() - GlobalValueModule.setClosePageAutoLogout(data?.close_page_auto_logout || false) + GlobalValueModule.setGlobalConfig(data) } } diff --git a/src/flows/initPage/nodes/initPage.ts b/src/flows/initPage/nodes/initPage.ts index 29e7f828..63db8143 100644 --- a/src/flows/initPage/nodes/initPage.ts +++ b/src/flows/initPage/nodes/initPage.ts @@ -12,11 +12,11 @@ export class InitPage extends FunctionNode { if (isMultiPage) { state = [] for (let i = 0; i < initContent.length; i++) { - const pageState = await this.initPage(initContent[i]) + const pageState = await this.initPage(initContent[i], currentPage) state.push(pageState) } } else { - state = await this.initPage(initContent) + state = await this.initPage(initContent, currentPage) } await this.runCustomPageFlow(state, initContent, currentPage) return { @@ -24,7 +24,7 @@ export class InitPage extends FunctionNode { } } - async initPage(initContent: ITagPage) { + async initPage(initContent: ITagPage, currentPage: string) { let state let initFileName = '' switch (initContent.type) { @@ -38,7 +38,8 @@ export class InitPage extends FunctionNode { break } await runFlowByFile(initFileName, { - initContent: initContent + initContent, + currentPage }).then(async (data) => { state = data.state }) @@ -65,8 +66,8 @@ export class InitPage extends FunctionNode { } if (curstomPageFlow !== '') { await runFlowByFile(curstomPageFlow, { - state: state, - initContent: initContent + state, + initContent }) } } diff --git a/src/flows/loginRegisterConfig/saveConfig/index.ts b/src/flows/loginRegisterConfig/saveConfig/index.ts new file mode 100644 index 00000000..0f03c402 --- /dev/null +++ b/src/flows/loginRegisterConfig/saveConfig/index.ts @@ -0,0 +1,30 @@ +import { Flow } from 'arkfbp/lib/flow' +import { Graph } from 'arkfbp/lib/graph' +import { StartNode } from 'arkfbp/lib/startNode' +import { StopNode } from 'arkfbp/lib/stopNode' +import { SaveConfig } from './nodes/saveConfig' + +export class Main extends Flow { + createNodes() { + return [ + { + cls: StartNode, + id: 'start', + next: 'saveConfig' + }, { + cls: SaveConfig, + id: 'saveConfig', + next: 'stop' + }, { + cls: StopNode, + id: 'stop' + } + ] + } + + createGraph() { + const g = new Graph() + g.nodes = this.createNodes() + return g + } +} diff --git a/src/flows/loginRegisterConfig/saveConfig/nodes/saveConfig.ts b/src/flows/loginRegisterConfig/saveConfig/nodes/saveConfig.ts new file mode 100644 index 00000000..e9da6f66 --- /dev/null +++ b/src/flows/loginRegisterConfig/saveConfig/nodes/saveConfig.ts @@ -0,0 +1,9 @@ +import { FunctionNode } from 'arkfbp/lib/functionNode' +import { GlobalValueModule } from '@/store/modules/global-value' + +export class SaveConfig extends FunctionNode { + async run() { + const data = this.inputs.com.state.data + GlobalValueModule.setGlobalConfig(data.data) + } +} \ No newline at end of file diff --git a/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts b/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts index d63368fb..13c714ea 100644 --- a/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts +++ b/src/flows/loginRegisterConfig/updated/nodes/loginRegisterConfig.ts @@ -1,13 +1,14 @@ import { FunctionNode } from 'arkfbp/lib/functionNode' -import { GlobalValueModule } from '@/store/modules/global-value' export class LoginRegisterConfig extends FunctionNode { async run() { const tempState = this.inputs.state - const saveConfig = (com) => { - const value = com.state.value - GlobalValueModule.setClosePageAutoLogout(value) + tempState.state.dialogs.update.state.state.form.items.data.state.items.upload_file_format.state.options = [ + { value: 'gif' }, { value: 'jpg' }, { value: 'png' }, { value: 'jpeg' } + ] + const saveConfig = { + name: 'flows/loginRegisterConfig/saveConfig' } - tempState.state.form.items.data.state.items.close_page_auto_logout.state.updated = saveConfig + tempState.state.actions.update.push(saveConfig) } } \ No newline at end of file diff --git a/src/store/modules/global-value.ts b/src/store/modules/global-value.ts index 36337605..772bb7a6 100644 --- a/src/store/modules/global-value.ts +++ b/src/store/modules/global-value.ts @@ -5,6 +5,12 @@ export interface IGlobalValueState { originUrl: string slug: string closePageAutoLogout: boolean + uploadFileFormat: string[] +} + +interface IGlobalConfig { + upload_file_format: string[] + close_page_auto_logout: boolean } @Module({ dynamic: true, store, name: 'global' }) @@ -12,6 +18,7 @@ class GlobalValue extends VuexModule implements IGlobalValueState { public originUrl: string = '' public slug: string = '' public closePageAutoLogout: boolean = false + public uploadFileFormat: string[] = [] @Mutation setOriginUrl(url: string) { @@ -24,8 +31,9 @@ class GlobalValue extends VuexModule implements IGlobalValueState { } @Mutation - setClosePageAutoLogout(value: boolean) { - this.closePageAutoLogout = value + setGlobalConfig(data: IGlobalConfig) { + this.closePageAutoLogout = data.close_page_auto_logout || false + this.uploadFileFormat = data.upload_file_format || [] } } diff --git a/src/utils/dialog.ts b/src/utils/dialog.ts index 7ec161a5..8dbce43a 100644 --- a/src/utils/dialog.ts +++ b/src/utils/dialog.ts @@ -68,6 +68,11 @@ const DIALOG_ACTION_FLOW = { password: 'arkfbp/flows/password' } +const PAGE_READONLY = { + 'app_list': true, + 'external_idp': true +} + // key 主要读取btn按钮的label和style, pageType会影响btn按钮的type的是text或其他 export function generateButton(key: string, path: string, method: string, pageType?: string, isDialog?: boolean): ButtonState | null { const apiRoles = getApiRoles(path, method) @@ -82,8 +87,9 @@ export function generateButton(key: string, path: string, method: string, pageTy return btn } -export function generateDialogState(path: string, method: string, key: string, showReadOnly: boolean = false ): DialogState | null { +export function generateDialogState(path: string, method: string, key: string, currentPage: string, showReadOnly: boolean = false ): DialogState | null { const dialogType = DIALOG_TYPE[key] + const isShowReadOnly = PAGE_READONLY[currentPage] || showReadOnly if (!dialogType) return null const schema = getSchemaByPath(path, method) const dialogState: DialogState = {} @@ -102,7 +108,7 @@ export function generateDialogState(path: string, method: string, key: string, s case 'FormPage': dialogState.state = { type: 'FormPage', - state: generateForm(schema, showReadOnly) + state: generateForm(schema, isShowReadOnly) } break case 'Upload': diff --git a/src/utils/flow.ts b/src/utils/flow.ts index 8645144a..18f68e05 100644 --- a/src/utils/flow.ts +++ b/src/utils/flow.ts @@ -6,7 +6,7 @@ export function proxyClientServer(clientServer: any, data?: any) { const cs = clientServer[key] if (typeof cs === 'object') { const val = data ? data[cs.value] : undefined - proxyClientServer = { [key]: cs.value } + Object.assign(proxyClientServer, { [key]: cs.value }) if (val) { Object.assign(proxyClientServer, cs[val]) } else { diff --git a/src/utils/form.ts b/src/utils/form.ts index c4564071..3d90c4be 100644 --- a/src/utils/form.ts +++ b/src/utils/form.ts @@ -133,19 +133,18 @@ function createItemByPropSchema(prop:string, schema: ISchema, showReadOnly:boole state: { value: schema.default, default: schema.default, - readonly: schema.readOnly, + readonly: schema.readOnly || disabled, placeholder: '请输入' + schema.title, required: isRequired, showPassword: prop.includes('password') || prop.includes('email') || prop.includes('mobile'), autocomplete: 'new-password', - disabled: disabled && !schema.readOnly, format: schema.format, hint: schema.hint, name: prop } } if (schema.format === 'uri' && location.pathname === '/tenant') { - item.type = 'InputLink' + item.state.type = 'link' } } else if (schema.type === 'boolean') { item = { diff --git a/src/utils/rules.ts b/src/utils/rules.ts index 193a8d43..d54250b3 100644 --- a/src/utils/rules.ts +++ b/src/utils/rules.ts @@ -1,4 +1,22 @@ import { ValidateModule } from '@/store/modules/validate' +import { GlobalValueModule } from '@/store/modules/global-value' + +const getFileRegexp = (): RegExp => { + const formats = GlobalValueModule.uploadFileFormat + let formatStr = '' + for (const format of formats) { + formatStr += `\\.${format}|` + } + formatStr = formatStr.substring(0, formatStr.length - 1) + formatStr = `/\\w(${formatStr})/i` + return eval(formatStr) +} + +const getFileHint = (): string => { + let format = GlobalValueModule.uploadFileFormat.join(',') + format = `请输入${format}格式的文件` + return format +} const RULE_REGEXP = { password: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{8,}$/, // 之后需要进行动态的读取 @@ -42,18 +60,32 @@ export const RULES = { export function validate(value: any, name: string, format?: string, hint?: string, required?: boolean): string { if (!format) format = 'other' if (format === 'uri') format = 'url' + if (name.includes('icon')) format = 'icon' + let regex: RegExp = new RegExp('') let message: string = '' + switch (format) { + case 'icon': + regex = getFileRegexp() + message = getFileHint() + break + default: + regex = RULE_REGEXP[format] + } if (!value) { if (required) { message = `请输入${name}` ValidateModule.addInvalidItem(name) + } else { + message = '' + ValidateModule.deleteInvalidItem(name) } } else { - const isValid = format === 'other' ? !RULE_REGEXP.other.test(value) : RULE_REGEXP[format].test(value) + const isValid = format === 'other' ? !regex.test(value) : regex.test(value) if (isValid) { + message = '' ValidateModule.deleteInvalidItem(name) } else { - message = hint || '' + message = hint || message || '' ValidateModule.addInvalidItem(name) } } From d2f12ea4015c7e45a33832102b79c18f75fb265a Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Wed, 23 Jun 2021 16:52:03 +0800 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=AF=B9=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E9=A1=B5=E9=9D=A2=E8=BF=9B=E8=A1=8C=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/arkfbp/nodes/clientResponseNode.ts | 2 +- src/config/auth/auth_page.json | 16 ++++-- .../authPageBtn/nodes/authPageBtn.ts | 6 ++ src/utils/form.ts | 1 + src/utils/rules.ts | 56 +++++++++++-------- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/arkfbp/nodes/clientResponseNode.ts b/src/arkfbp/nodes/clientResponseNode.ts index d2e36cc0..2678c0ee 100644 --- a/src/arkfbp/nodes/clientResponseNode.ts +++ b/src/arkfbp/nodes/clientResponseNode.ts @@ -52,7 +52,7 @@ export class ClientResponseNode extends FunctionNode { } tempC[lastKey] = lastKey === 'disabled' ? !value : value } else { - const value = (clientServer[key] !== undefined) ? clientServer[key] : tempC[lastKey] + const value = (clientServer[key] !== undefined && clientServer[key] !== '') ? clientServer[key] : tempC[lastKey] tempC[lastKey] = value } } diff --git a/src/config/auth/auth_page.json b/src/config/auth/auth_page.json index 6ec7ce7c..4b0f38d7 100644 --- a/src/config/auth/auth_page.json +++ b/src/config/auth/auth_page.json @@ -23,12 +23,15 @@ "first": { "items": { "icon": { - "type": "InputLink", + "type": "Input", "label": "图标", "prop": "icon", "state": { "value": "", - "placeholder": "请输入或上传图标" + "placeholder": "请输入或上传图标", + "type": "link", + "name": "icon", + "format": "icon" } }, "title": { @@ -37,7 +40,8 @@ "prop": "title", "state": { "value": "", - "placeholder": "请输入标题" + "placeholder": "请输入标题", + "name": "title" } }, "info": { @@ -62,7 +66,8 @@ "prop": "text", "state": { "placeholder": "请输入确认按钮文本", - "value": "" + "value": "", + "name": "text" } }, "tcolor": { @@ -114,7 +119,8 @@ "prop": "text", "state": { "placeholder": "请输入取消按钮文本", - "value": "" + "value": "", + "name": "text" } }, "tcolor": { diff --git a/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts b/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts index 219e8f35..7f33495b 100644 --- a/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts +++ b/src/flows/appManager/authPageBtn/nodes/authPageBtn.ts @@ -12,11 +12,17 @@ export class AuthPageBtn extends FunctionNode { } tempState.table?.columns[tempState.table.columns.length - 1]?.scope?.state?.push(authPageBtn) tempState.actions!['openAuthPage'] = [ + { + name: 'arkfbp/flows/cancelValidate' + }, { name: 'flows/appManager/openAuthPage' } ] tempState.actions!['saveTemplate'] = [ + { + name: 'arkfbp/flows/validate' + }, { name: 'flows/appManager/saveTemplate', url: '/api/v1/tenant/{tenant_uuid}/app/{uuid}/add_auth_tmpl/', diff --git a/src/utils/form.ts b/src/utils/form.ts index 3d90c4be..08a869f4 100644 --- a/src/utils/form.ts +++ b/src/utils/form.ts @@ -145,6 +145,7 @@ function createItemByPropSchema(prop:string, schema: ISchema, showReadOnly:boole } if (schema.format === 'uri' && location.pathname === '/tenant') { item.state.type = 'link' + item.state.format = 'icon' } } else if (schema.type === 'boolean') { item = { diff --git a/src/utils/rules.ts b/src/utils/rules.ts index d54250b3..5a5ee355 100644 --- a/src/utils/rules.ts +++ b/src/utils/rules.ts @@ -50,6 +50,28 @@ export const RULES = { username: getRegexRule('用户名不包含' + "<>'()&/" + '"', RULE_REGEXP.other, true) } +// 根据OpenAPI返回的结果进行规则生成,后续可能需要进一步地更新 +const getDynamicRule = (format?: string, hint?: string, required?: boolean) => { + if (!format) format = 'other' + let pattern: RegExp = new RegExp(''), + isAnti: boolean = false + switch (format) { + case 'other': + hint = '输入内容不应包含' + "<>'()&/" + '" ' + isAnti = true + break + case 'uri': + format = 'url' + break + case 'icon': + pattern = getFileRegexp() + hint = getFileHint() + break + } + const rule = { pattern: RULE_REGEXP[format] || pattern, message: hint, isAnti, required } + return rule +} + // 输入框的内容校验 // 参数说明 => // value 当前值 @@ -58,35 +80,23 @@ export const RULES = { // hint 对应OpenAPI字段描述中的hint内容,文本提示 // required 是否为必填字段 export function validate(value: any, name: string, format?: string, hint?: string, required?: boolean): string { - if (!format) format = 'other' - if (format === 'uri') format = 'url' - if (name.includes('icon')) format = 'icon' - let regex: RegExp = new RegExp('') - let message: string = '' - switch (format) { - case 'icon': - regex = getFileRegexp() - message = getFileHint() - break - default: - regex = RULE_REGEXP[format] - } - if (!value) { - if (required) { - message = `请输入${name}` - ValidateModule.addInvalidItem(name) - } else { + let { message, pattern, isAnti } = getDynamicRule(format, hint, required) + if (value) { + const isValid = isAnti ? !pattern.test(value) : pattern.test(value) + if (isValid) { message = '' ValidateModule.deleteInvalidItem(name) + } else { + message = message || '输入内容不正确' + ValidateModule.addInvalidItem(name) } } else { - const isValid = format === 'other' ? !regex.test(value) : regex.test(value) - if (isValid) { + if (required) { + message = `请输入${name}` + ValidateModule.addInvalidItem(name) + } else { message = '' ValidateModule.deleteInvalidItem(name) - } else { - message = hint || message || '' - ValidateModule.addInvalidItem(name) } } return message From 90a8221d5ceb851b2d5c13641fdf720f3c6fc1dd Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Thu, 24 Jun 2021 16:20:59 +0800 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=B0=86=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=B3=A8=E5=86=8C=E7=AA=97=E5=8F=A3=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=BACORS=E7=9A=84=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/arkfbp/index.ts | 2 +- src/arkfbp/nodes/clientResponseNode.ts | 2 +- src/login/Login.vue | 7 +- src/login/components/LoginComponent.ts | 97 ++++++++++++++++--- src/login/flows/ButtonClick/index.ts | 50 ---------- src/login/flows/ButtonClick/nodes/GoPage.ts | 13 --- src/login/flows/ButtonClick/nodes/Http.ts | 36 ------- .../flows/ButtonClick/nodes/HttpResponse.ts | 48 --------- src/login/flows/ButtonClick/nodes/Redirect.ts | 21 ---- src/login/flows/ButtonClick/nodes/Start.ts | 12 --- src/login/flows/GetCode/index.ts | 32 ------ src/login/flows/GetCode/nodes/GetCode.ts | 11 --- src/login/request/index.ts | 21 ++++ 13 files changed, 110 insertions(+), 242 deletions(-) delete mode 100644 src/login/flows/ButtonClick/index.ts delete mode 100644 src/login/flows/ButtonClick/nodes/GoPage.ts delete mode 100644 src/login/flows/ButtonClick/nodes/Http.ts delete mode 100644 src/login/flows/ButtonClick/nodes/HttpResponse.ts delete mode 100644 src/login/flows/ButtonClick/nodes/Redirect.ts delete mode 100644 src/login/flows/ButtonClick/nodes/Start.ts delete mode 100644 src/login/flows/GetCode/index.ts delete mode 100644 src/login/flows/GetCode/nodes/GetCode.ts create mode 100644 src/login/request/index.ts diff --git a/src/arkfbp/index.ts b/src/arkfbp/index.ts index abe0af30..3371c8f7 100644 --- a/src/arkfbp/index.ts +++ b/src/arkfbp/index.ts @@ -121,7 +121,7 @@ export function parseStateMapping(state: any, mapping: any) { const item = mapping[key] if (typeof item === 'string') { tempState = getStateByStringConfig(state, item) - if (tempState !== undefined && tempState !== null ) { + if (tempState !== undefined && tempState !== null && tempState !== '') { params[key] = tempState } } else if (typeof item === 'object') { diff --git a/src/arkfbp/nodes/clientResponseNode.ts b/src/arkfbp/nodes/clientResponseNode.ts index 2678c0ee..c7aa9157 100644 --- a/src/arkfbp/nodes/clientResponseNode.ts +++ b/src/arkfbp/nodes/clientResponseNode.ts @@ -52,7 +52,7 @@ export class ClientResponseNode extends FunctionNode { } tempC[lastKey] = lastKey === 'disabled' ? !value : value } else { - const value = (clientServer[key] !== undefined && clientServer[key] !== '') ? clientServer[key] : tempC[lastKey] + const value = (clientServer[key] !== undefined || clientServer[key] !== '') ? clientServer[key] : tempC[lastKey] tempC[lastKey] = value } } diff --git a/src/login/Login.vue b/src/login/Login.vue index aff7669e..332d4afc 100644 --- a/src/login/Login.vue +++ b/src/login/Login.vue @@ -12,8 +12,9 @@ import { Component, Watch } from 'vue-property-decorator' import LoginComponent from './components/LoginComponent.vue' import { LoginPagesConfig, LoginPageConfig, LoginTenant, ButtonConfig } from './interface' import LoginStore from './store/login' -import { jsonp } from 'vue-jsonp' +// import { jsonp } from 'vue-jsonp' import getBaseUrl from '@/utils/get-base-url' +import request from './request' @Component({ name: 'Login', @@ -65,7 +66,9 @@ export default class Login extends Vue { url, method: 'get' } - const { data, tenant } = await jsonp('/api/v1/jsonp', params) + const response = await request.get(url) + const page = response.data + const { tenant, data } = page const config = {} Object.keys(data).forEach(key => { if (key === 'login') { diff --git a/src/login/components/LoginComponent.ts b/src/login/components/LoginComponent.ts index 42d2c7a7..b6e5601b 100644 --- a/src/login/components/LoginComponent.ts +++ b/src/login/components/LoginComponent.ts @@ -1,13 +1,12 @@ import Vue from 'vue' -import { Prop, Component, Watch } from 'vue-property-decorator' +import { Prop, Component } from 'vue-property-decorator' import LoginButton from './LoginButton.vue' import { LoginPagesConfig, LoginPageConfig, FormConfig, ButtonConfig, FormItemConfig } from '../interface' -import { runWorkflowByClass } from 'arkfbp/lib/flow' -import { Main as ButtonClick } from '../flows/ButtonClick' -import { Main as GetCode } from '../flows/GetCode' import LoginStore from '../store/login' import { RULES } from '@/utils/rules' import { preventPaste } from '@/utils/event' +import request from '../request' +import { error } from '@/constants/error' @Component({ name: 'LoginComponent', @@ -100,19 +99,83 @@ export default class LoginComponent extends Vue { return this.formData[this.pageData][this.currentFormIndex] } + async http(url: string, method: string, data?: any) { + method = method.toLowerCase() + const response = await request[method](url, data) + return response + } + async btnClickHandler(btn:ButtonConfig) { - if (!btn.gopage && !btn.delay && !btn.redirect) { - (this.$refs[this.pageData][this.currentFormIndex] as Vue & { validate: Function }).validate(async (valid: boolean) => { - if (valid) { - await runWorkflowByClass(ButtonClick, { com: this, btn: btn }) + if (btn.http || btn.delay) this.btnHttp(btn) + if (btn.gopage) this.togglePage(btn) + if (btn.redirect) this.redirect(btn) + } + + btnHttp(btn: ButtonConfig) { + (this.$refs[this.pageData][this.currentFormIndex] as Vue & { validate: Function }).validate(async (valid: boolean) => { + if (valid) { + await this.btnResponse(btn) + } + }) + } + + redirect(btn: ButtonConfig) { + let redirectParams = `` + const params = btn.redirect!.params + for (const key in params) { + redirectParams += `&${key}=${params[key]}` + } + redirectParams = redirectParams.substring(1) + const url = btn.redirect!.url + '?' + redirectParams + window.location.replace(url) + } + + togglePage(btn: ButtonConfig) { + this.pageData = btn.gopage! + this.resetFields() + this.resetRules() + } + + async btnResponse(btn: ButtonConfig) { + let { url, method, params } = btn.http! + for (let key in params) { + if (this.currentFormData.hasOwnProperty(key)) { + params[key] = this.currentFormData[key] + } else { + if (key === 'code_filename') params[key] = LoginStore.CodeFileName + } + } + const response = await this.http(url, method, params) + const data = response.data + if (data.error === '0' && data.data.token) { + // set token + LoginStore.token = data.data.token + // 绑定用户与第三方账号 + if (LoginStore.ThirdUserID && LoginStore.BindUrl) { + let data = 'user_id=' + LoginStore.ThirdUserID + if (LoginStore.hasToken()) { + data += '&token=' + LoginStore.token } - }) + await this.http(url, method, data) + LoginStore.BindUrl = '' + LoginStore.ThirdUserID = '' + } + // next url + if (LoginStore.NextUrl) { + window.location.href = LoginStore.NextUrl + '&token=' + LoginStore.token + LoginStore.NextUrl = '' + } else { + window.location.reload() + } } else { - await runWorkflowByClass(ButtonClick, { com: this, btn: btn }) - if (btn.gopage) { - this.resetFields() - this.resetRules() + if (data.is_need_refresh && LoginStore.CodeFileName === '') { + window.location.reload() } + this.$message({ + message: error[data.error] || data.message || 'error', + type: 'error', + showClose: true + }) } } @@ -160,11 +223,15 @@ export default class LoginComponent extends Vue { } async getGraphicCode() { - await runWorkflowByClass(GetCode, {}).then((data) => { + const url = '/api/v1/authcode/generate' + const method = 'get' + const response = await this.http(url, method) + const data = response.data + if (!data.error) { const { key, base64 } = data LoginStore.CodeFileName = key this.graphicCodeSrc = `data:image/png;base64,${base64}` - }) + } } hasGraphicCode(item: FormItemConfig) { diff --git a/src/login/flows/ButtonClick/index.ts b/src/login/flows/ButtonClick/index.ts deleted file mode 100644 index 5afe4127..00000000 --- a/src/login/flows/ButtonClick/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Flow } from 'arkfbp/lib/flow' -import { Graph } from 'arkfbp/lib/graph' -import { Start } from './nodes/Start' -import { StopNode } from 'arkfbp/lib/stopNode' -import { GoPage } from './nodes/GoPage' -import { Redirect } from './nodes/Redirect' -import { Http } from './nodes/Http' -import { HttpResponse } from './nodes/HttpResponse' - -export class Main extends Flow { - createNodes() { - return [ - { - cls: Start, - id: 'start', - next: 'gopage' - }, - { - cls: GoPage, - id: 'gopage', - next: 'redirect' - }, - { - cls: Redirect, - id: 'redirect', - next: 'http' - }, - { - cls: Http, - id: 'http', - next: 'response' - }, - { - cls: HttpResponse, - id: 'response', - next: 'stop' - }, - { - cls: StopNode, - id: 'stop' - } - ] - } - - createGraph() { - const g = new Graph() - g.nodes = this.createNodes() - return g - } -} diff --git a/src/login/flows/ButtonClick/nodes/GoPage.ts b/src/login/flows/ButtonClick/nodes/GoPage.ts deleted file mode 100644 index e32053ea..00000000 --- a/src/login/flows/ButtonClick/nodes/GoPage.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ButtonConfig } from '@/login/interface' -import { FunctionNode } from 'arkfbp/lib/functionNode' -import LoginComponent from '@/login/components/LoginComponent' - -export class GoPage extends FunctionNode { - async run() { - const com = this.$state.fetch().com as LoginComponent - const btn = this.$state.fetch().btn as ButtonConfig - - if (btn.gopage) com.pageData = btn.gopage - return this.inputs - } -} diff --git a/src/login/flows/ButtonClick/nodes/Http.ts b/src/login/flows/ButtonClick/nodes/Http.ts deleted file mode 100644 index a3b8166d..00000000 --- a/src/login/flows/ButtonClick/nodes/Http.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { FunctionNode } from 'arkfbp/lib/functionNode' -import { ButtonConfig } from '@/login/interface' -import { jsonp } from 'vue-jsonp' -import LoginStore from '@/login/store/login' - -export class Http extends FunctionNode { - async run() { - const com = this.$state.fetch().com - const btn = this.$state.fetch().btn as ButtonConfig - - if (btn.http) { - const url = btn.http.url - const method = btn.http.method - let data = '' - for (const key in btn.http.params) { - const formKey = btn.http.params[key] - if (formKey === 'checkpassword' && com.currentFormData.checkpassword !== com.currentFormData.password) { - return {} - } - let value = formKey === 'code_filename' ? LoginStore.CodeFileName : com.currentFormData[formKey] - data += formKey - data += '=' + value - data += '&' - } - data = data.substr(0, data.length - 1) - const params = { - url, - method, - data - } - const response = await jsonp('api/v1/jsonp/', params) - return response - } - return {} - } -} diff --git a/src/login/flows/ButtonClick/nodes/HttpResponse.ts b/src/login/flows/ButtonClick/nodes/HttpResponse.ts deleted file mode 100644 index 3310f944..00000000 --- a/src/login/flows/ButtonClick/nodes/HttpResponse.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { FunctionNode } from 'arkfbp/lib/functionNode' -import LoginStore from '@/login/store/login' -import { jsonp } from 'vue-jsonp' -import { error } from '@/constants/error' - -export class HttpResponse extends FunctionNode { - async run() { - if (this.inputs.data && this.inputs.error === '0' && this.inputs.data.token) { - // login success - LoginStore.token = this.inputs.data.token - - if (LoginStore.ThirdUserID && LoginStore.BindUrl) { - // 绑定用户与第三方账号 - let data = 'user_id=' + LoginStore.ThirdUserID - if (LoginStore.hasToken()) { - data += '&token=' + LoginStore.token - } - const params = { - url: LoginStore.BindUrl, - method: 'post', - data: data - } - await jsonp('api/v1/jsonp/', params) - LoginStore.BindUrl = '' - LoginStore.ThirdUserID = '' - } - - if (LoginStore.NextUrl) { - window.location.href = LoginStore.NextUrl + '&token=' + LoginStore.token - LoginStore.NextUrl = '' - } else { - window.location.reload() - } - } else { - if (this.inputs.error) { - if (this.inputs.is_need_refresh && LoginStore.CodeFileName === '') { - window.location.reload() - } - const com = this.$state.fetch().com - com.$message({ - message: error[this.inputs.error] || this.inputs.message || 'error', - type: 'error', - showClose: true - }) - } - } - } -} diff --git a/src/login/flows/ButtonClick/nodes/Redirect.ts b/src/login/flows/ButtonClick/nodes/Redirect.ts deleted file mode 100644 index 2f7da5fd..00000000 --- a/src/login/flows/ButtonClick/nodes/Redirect.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ButtonConfig } from '@/login/interface' -import { FunctionNode } from 'arkfbp/lib/functionNode' - -export class Redirect extends FunctionNode { - async run() { - const btn = this.$state.fetch().btn as ButtonConfig - - if (btn.redirect) { - let paramsUrl = '' - for (const key in btn.redirect.params) { - const value = btn.redirect.params[key] - paramsUrl += (key + '=' + value + '&') - } - const endNumber = paramsUrl.length - 1 - paramsUrl = paramsUrl.substr(0, endNumber) - const url = btn.redirect.url + '?' + paramsUrl - window.location.replace(url) - } - return this.inputs - } -} diff --git a/src/login/flows/ButtonClick/nodes/Start.ts b/src/login/flows/ButtonClick/nodes/Start.ts deleted file mode 100644 index 7480e3e2..00000000 --- a/src/login/flows/ButtonClick/nodes/Start.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { StartNode } from 'arkfbp/lib/startNode' - -export class Start extends StartNode { - async run() { - const com = this.inputs.com - const btn = this.inputs.btn - this.$state.commit((state) => { - state.com = com - state.btn = btn - }) - } -} diff --git a/src/login/flows/GetCode/index.ts b/src/login/flows/GetCode/index.ts deleted file mode 100644 index ade6bcb2..00000000 --- a/src/login/flows/GetCode/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Flow } from 'arkfbp/lib/flow' -import { Graph } from 'arkfbp/lib/graph' -import { StartNode } from 'arkfbp/lib/startNode' -import { StopNode } from 'arkfbp/lib/stopNode' -import { GetCode } from './nodes/GetCode' - -export class Main extends Flow { - createNodes() { - return [ - { - cls: StartNode, - id: 'start', - next: 'getcode' - }, - { - cls: GetCode, - id: 'getcode', - next: 'stop' - }, - { - cls: StopNode, - id: 'stop' - } - ] - } - - createGraph() { - const g = new Graph() - g.nodes = this.createNodes() - return g - } -} diff --git a/src/login/flows/GetCode/nodes/GetCode.ts b/src/login/flows/GetCode/nodes/GetCode.ts deleted file mode 100644 index 1a0211b0..00000000 --- a/src/login/flows/GetCode/nodes/GetCode.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { APINode } from 'arkfbp/lib/apiNode' -// import { jsonp } from 'vue-jsonp' - -export class GetCode extends APINode { - async run() { - this.url = '/api/v1/authcode/generate' - this.method = 'GET' - const response = await super.run() - return response - } -} diff --git a/src/login/request/index.ts b/src/login/request/index.ts new file mode 100644 index 00000000..51dc57aa --- /dev/null +++ b/src/login/request/index.ts @@ -0,0 +1,21 @@ +import axios from 'axios' +import LoginStore from '../store/login' + +const request = axios.create({ + baseURL: LoginStore.host, + withCredentials: true, + validateStatus: (status) => { + return /^(2|3)\d{2}$/.test(String(status)) + } +}) + +request.interceptors.response.use( + (response) => { + return response + }, + (err) => { + return Promise.reject(err) + } +) + +export default request From 3e7077d7a70d3ae7c26e20475692f22fabf8a245 Mon Sep 17 00:00:00 2001 From: longgui-penglei Date: Fri, 25 Jun 2021 14:00:57 +0800 Subject: [PATCH 08/22] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E5=86=85?= =?UTF-8?q?=E5=AE=B9,=20=E5=B9=B6=E5=AF=B9=E5=AF=86=E7=A0=81=E5=A4=8D?= =?UTF-8?q?=E6=9D=82=E5=BA=A6=E8=BF=9B=E8=A1=8C=E5=85=A8=E5=B1=80=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/admin/FormPage/index.vue | 2 +- src/arkfbp/flows/password/nodes/password.ts | 4 ++- src/flows/init/nodes/afterLogin.ts | 27 ++++++++++++----- src/flows/initPage/nodes/initPage.ts | 4 +++ src/flows/passwordManager/addAction/index.ts | 30 +++++++++++++++++++ .../addAction/nodes/addAction.ts | 11 +++++++ .../updatePasswordComplexify/index.ts | 30 +++++++++++++++++++ .../nodes/updatePasswordComplexify.ts | 12 ++++++++ src/store/modules/global-value.ts | 26 ++++++++++++++++ src/store/modules/tenant.ts | 12 +++++++- src/utils/list-dialog.ts | 2 +- src/utils/rules.ts | 18 +++++++---- src/utils/url.ts | 3 +- 13 files changed, 163 insertions(+), 18 deletions(-) create mode 100644 src/flows/passwordManager/addAction/index.ts create mode 100644 src/flows/passwordManager/addAction/nodes/addAction.ts create mode 100644 src/flows/passwordManager/updatePasswordComplexify/index.ts create mode 100644 src/flows/passwordManager/updatePasswordComplexify/nodes/updatePasswordComplexify.ts diff --git a/src/admin/FormPage/index.vue b/src/admin/FormPage/index.vue index ceb1562f..edfcd189 100644 --- a/src/admin/FormPage/index.vue +++ b/src/admin/FormPage/index.vue @@ -57,7 +57,7 @@ export default class extends Mixins(BaseVue) {