| | |
| | | <template><div class="my-amis-scope">加载中...</div></template> |
| | | <template><div ref="amisRootRef" class="my-amis-scope">加载中...</div></template> |
| | | |
| | | <script lang="ts"> |
| | | // import '/static/sdk/sdk.js'; |
| | | // import '/static/sdk/sdk.css'; |
| | | // import '/static/sdk/iconfont.css'; |
| | | import { accessSessionKey, handleNoAuth } from '/@/utils/request'; |
| | | import { NO_AUTH_API_LIST } from '/@/api/ai/chat'; |
| | | import { LOGIN_URL, TEL_LOGIN_URL } from '/@/api/ai/user'; |
| | | <script setup lang="ts"> |
| | | import { MAIN_URL } from '/@/constants'; |
| | | import router from '/@/router/index'; |
| | | |
| | | import { Local } from '/@/utils/storage'; |
| | | |
| | | import { accessSessionKey, handleNoAuth } from '/@/utils/request'; |
| | | // 可以不引用, 如果你不想要任何辅助类样式的话 (比如 `m-t-xs` 这种) |
| | | // https://aisuda.bce.baidu.com/amis/zh-CN/style/index |
| | | // import 'amis/sdk/helper.css'; |
| | | import qs from 'qs'; |
| | | import { onMounted, onUnmounted, reactive, ref, shallowRef, watch } from 'vue'; |
| | | import { NO_AUTH_API_LIST } from '/@/api/ai/chat'; |
| | | import { LOGIN_URL, TEL_LOGIN_URL } from '/@/api/ai/user'; |
| | | import { Local } from '/@/utils/storage'; |
| | | import { isSharePage } from '/@/stores/chatRoom'; |
| | | |
| | | const amisRootRef = ref<HTMLDivElement>(null); |
| | | |
| | | const props = defineProps({ |
| | | schema: { |
| | | type: Object, |
| | | default: () => ({ |
| | | type: 'page', |
| | | body: 'Hello World!', |
| | | }), |
| | | }, |
| | | locals: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | context:{ |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | props: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | env: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(['ready']); |
| | | |
| | | function loadScript(callback) { |
| | | window.eventList.amisSdkJsPromise |
| | |
| | | }); |
| | | } |
| | | |
| | | function loadStyles(styles) { |
| | | for (const path of styles) { |
| | | const style = document.createElement('link'); |
| | | style.setAttribute('rel', 'stylesheet'); |
| | | style.setAttribute('type', 'text/css'); |
| | | style.setAttribute('href', path); |
| | | document.head.appendChild(style); |
| | | } |
| | | } |
| | | |
| | | function loadSDK() { |
| | | return new Promise((resolve, reject) => { |
| | | // loadStyles(['/static/amis/sdk/sdk.css', '/static/amis/sdk/helper.css', '/static/amis/sdk/iconfont.css']); |
| | | |
| | | if (window.amisRequire) { |
| | | resolve(); |
| | | return; |
| | |
| | | }); |
| | | } |
| | | |
| | | export default { |
| | | name: 'AMISRenderer', |
| | | components: {}, |
| | | props: { |
| | | schema: { |
| | | type: Object, |
| | | default: () => ({ |
| | | type: 'page', |
| | | body: 'Hello World!', |
| | | }), |
| | | }, |
| | | locals: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | props: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | env: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | // 这里面的数据所有 amis 页面都可以获取到 |
| | | // 可以用来放一下公共数据,比如用户信息等 |
| | | // 不要放受控数据,受控数据应该通过 data 下发 |
| | | context: { |
| | | siteName: 'AMIS DEMO', |
| | | }, |
| | | get location() { |
| | | const current = router.currentRoute.value; |
| | | return { |
| | | pathname: current?.path, |
| | | hash: current?.hash, |
| | | query: current?.query, |
| | | search: `?${qs.stringify(current.query)}`, |
| | | }; |
| | | // return 'localtion' |
| | | }, |
| | | loading: false, |
| | | amisInstance: null, |
| | | unmounted: false, |
| | | }; |
| | | }, |
| | | |
| | | watch: { |
| | | locals: function () { |
| | | this.updateProps(); |
| | | }, |
| | | props: function () { |
| | | this.updateProps(); |
| | | }, |
| | | $route: function () { |
| | | this.updateProps(); |
| | | }, |
| | | }, |
| | | async mounted() { |
| | | try { |
| | | this.loading = true; |
| | | await loadSDK(); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | if (this.unmounted) { |
| | | return; |
| | | } |
| | | const current = router.currentRoute.value; |
| | | |
| | | const scoped = amisRequire('amis/embed'); |
| | | const { normalizeLink } = amisRequire('amis'); |
| | | const instance = scoped.embed( |
| | | this.$el, |
| | | this.schema, |
| | | { |
| | | data: { |
| | | ...this.locals, |
| | | }, |
| | | context: this.context, |
| | | location: this.location, |
| | | const location = { |
| | | pathname: current?.path, |
| | | hash: current?.hash, |
| | | query: current?.query, |
| | | search: `?${qs.stringify(current.query)}`, |
| | | }; |
| | | |
| | | // todo 下发 location 对象 |
| | | ...this.props, |
| | | const loading = ref(false); |
| | | const amisInstance = shallowRef(null); |
| | | const unmounted = ref(false); |
| | | |
| | | const updateProps = () => { |
| | | amisInstance.value?.updateProps({ |
| | | data: { |
| | | // ...props.locals, |
| | | }, |
| | | context: props.context, |
| | | ...props.props, |
| | | }); |
| | | }; |
| | | watch( |
| | | () => props.locals, |
| | | (val) => { |
| | | updateProps(); |
| | | } |
| | | ); |
| | | watch( |
| | | () => props.props, |
| | | (val) => { |
| | | updateProps(); |
| | | } |
| | | ); |
| | | |
| | | // watch(() => router.value, (val) => { |
| | | |
| | | // }) |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | await loadSDK(); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | if (unmounted.value) { |
| | | return; |
| | | } |
| | | |
| | | const scoped = amisRequire('amis/embed'); |
| | | const { normalizeLink } = amisRequire('amis'); |
| | | const instance = scoped.embed( |
| | | amisRootRef.value, |
| | | props.schema, |
| | | { |
| | | data: { |
| | | // ...props.locals, |
| | | }, |
| | | { |
| | | requestAdaptor(api) { |
| | | // 支持异步,可以通过 api.mockResponse 来设置返回结果,跳过真正的请求发送 |
| | | // 此功能自定义 fetcher 的话会失效 |
| | | // api.context 中包含发送请求前的上下文信息 |
| | | // 获取本地的 token |
| | | const accessSession = Local.get(accessSessionKey); |
| | | if (!NO_AUTH_API_LIST.includes(api.url)) { |
| | | if (accessSession) { |
| | | // 将 token 添加到请求报文头中 |
| | | api.headers['hswatersession'] = accessSession; |
| | | } else { |
| | | if (api.url !== LOGIN_URL && api.url !== TEL_LOGIN_URL) { |
| | | handleNoAuth(api.url); |
| | | throw '权限验证失败'; |
| | | } |
| | | context: props.context, |
| | | location: location, |
| | | |
| | | // todo 下发 location 对象 |
| | | ...props.props, |
| | | }, |
| | | { |
| | | requestAdaptor(api) { |
| | | // 支持异步,可以通过 api.mockResponse 来设置返回结果,跳过真正的请求发送 |
| | | // 此功能自定义 fetcher 的话会失效 |
| | | // api.context 中包含发送请求前的上下文信息 |
| | | // 获取本地的 token |
| | | const accessSession = Local.get(accessSessionKey); |
| | | if (!NO_AUTH_API_LIST.includes(api.url) && !isSharePage.value) { |
| | | if (accessSession) { |
| | | // 将 token 添加到请求报文头中 |
| | | api.headers['hswatersession'] = accessSession; |
| | | } else { |
| | | if (api.url !== LOGIN_URL && api.url !== TEL_LOGIN_URL) { |
| | | handleNoAuth(api.url); |
| | | throw '权限验证失败'; |
| | | } |
| | | } |
| | | } |
| | | |
| | | api.url = `${MAIN_URL}${api.url}`; |
| | | return api; |
| | | }, |
| | | // 覆盖 amis env |
| | | // 参考 https://aisuda.bce.baidu.com/amis/zh-CN/docs/start/getting-started#sdk |
| | | jumpTo: (to, action) => { |
| | | return; |
| | | console.log('🚀 ~ to:', to); |
| | | console.log('🚀 ~ action:', action); |
| | | if (to === 'goBack') { |
| | | return router.go(-1); |
| | | } |
| | | |
| | | to = normalizeLink(to, this.location); |
| | | |
| | | if (action?.actionType === 'url') { |
| | | action.blank === false ? router.push(to) : window.open(to); |
| | | return; |
| | | } |
| | | |
| | | // 主要是支持 nav 中的跳转 |
| | | if (action && to && action.target) { |
| | | window.open(to, action.target); |
| | | return; |
| | | } |
| | | |
| | | if (/^https?:\/\//.test(to)) { |
| | | window.location.replace(to); |
| | | } else { |
| | | router.push(to); |
| | | } |
| | | }, |
| | | |
| | | updateLocation: (location, replace) => { |
| | | // 禁止跳转 |
| | | return; |
| | | console.log('🚀 ~ location:', location); |
| | | console.log('🚀 ~ replace:', replace); |
| | | if (location === 'goBack') { |
| | | return router.go(-1); |
| | | } |
| | | |
| | | location = normalizeLink(location, this.location); |
| | | replace ? router.replace(location) : router.replace(location); |
| | | }, |
| | | |
| | | ...this.env, |
| | | api.url = `${MAIN_URL}${api.url}`; |
| | | return api; |
| | | }, |
| | | () => { |
| | | this.$emit('ready', { |
| | | instance, |
| | | }); |
| | | } |
| | | ); |
| | | // 全局 api 适配器。 |
| | | // 另外在 amis 配置项中的 api 也可以配置适配器,针对某个特定接口单独处理。 |
| | | responseAdaptor(api, payload, query, request, response) { |
| | | // { |
| | | // "json_ok": true, |
| | | // "sections": [ |
| | | // { |
| | | // "section_id": "knowledge_base", |
| | | // "section_name": "水务知识库", |
| | | // "section_title": "拥有水务行业相关的通用知识,包括:法律法规、设计规范、给排水相关知识等等" |
| | | // }, |
| | | // { |
| | | // "section_id": "office_assistant", |
| | | // "section_name": "办公助手", |
| | | // "section_title": "办公助手能够辅助写会议通知、请假条、工作总结、PPT等工作。" |
| | | // }, |
| | | // { |
| | | // "section_id": "customer_service", |
| | | // "section_name": "客户服务", |
| | | // "section_title": "针对水务企业对外客户服务相关的内容,包括:抄表、开账、收费,以及热线相关" |
| | | // }, |
| | | // { |
| | | // "section_id": "network_operation", |
| | | // "section_name": "管网运行", |
| | | // "section_title": "针对水务企业管网运行与维护管理、水质管理等相关" |
| | | // }, |
| | | // { |
| | | // "section_id": "waterworks_operation", |
| | | // "section_name": "水厂运行", |
| | | // "section_title": "针对水务企业水厂运日常运营管理服务,包括:水厂工艺流程、水泵运行调度" |
| | | // } |
| | | // ] |
| | | // } |
| | | return payload; |
| | | }, |
| | | // 覆盖 amis env |
| | | // 参考 https://aisuda.bce.baidu.com/amis/zh-CN/docs/start/getting-started#sdk |
| | | jumpTo: (to, action) => { |
| | | return; |
| | | if (to === 'goBack') { |
| | | return router.go(-1); |
| | | } |
| | | |
| | | this.amisInstance = instance; |
| | | }, |
| | | to = normalizeLink(to, this.location); |
| | | |
| | | methods: { |
| | | updateProps() { |
| | | this.amisInstance?.updateProps({ |
| | | data: { |
| | | ...this.locals, |
| | | }, |
| | | context: this.context, |
| | | ...this.props, |
| | | }); |
| | | if (action?.actionType === 'url') { |
| | | action.blank === false ? router.push(to) : window.open(to); |
| | | return; |
| | | } |
| | | |
| | | // 主要是支持 nav 中的跳转 |
| | | if (action && to && action.target) { |
| | | window.open(to, action.target); |
| | | return; |
| | | } |
| | | |
| | | if (/^https?:\/\//.test(to)) { |
| | | window.location.replace(to); |
| | | } else { |
| | | router.push(to); |
| | | } |
| | | }, |
| | | |
| | | updateLocation: (location, replace) => { |
| | | // 禁止跳转 |
| | | return; |
| | | if (location === 'goBack') { |
| | | return router.go(-1); |
| | | } |
| | | |
| | | location = normalizeLink(location, this.location); |
| | | replace ? router.replace(location) : router.replace(location); |
| | | }, |
| | | |
| | | ...props.env, |
| | | }, |
| | | }, |
| | | () => { |
| | | emit('ready', { |
| | | instance, |
| | | }); |
| | | } |
| | | ); |
| | | amisInstance.value = instance; |
| | | }); |
| | | |
| | | unmounted() { |
| | | this.unmounted = true; |
| | | this.amisInstance?.unmount(); |
| | | }, |
| | | }; |
| | | onUnmounted(() => { |
| | | unmounted.value = true; |
| | | |
| | | amisInstance.value?.unmount(); |
| | | }); |
| | | </script> |