generated from duanshuwen/webapp-vue-frontend
feat: 问卷功能开发
This commit is contained in:
@@ -5,5 +5,10 @@ VITE_ENV = development
|
||||
VITE_CONSOLE = 1
|
||||
|
||||
# 接口地址
|
||||
VITE_BASE_API =
|
||||
VITE_BASE_API = http://8.138.234.141/ingress/hotelBiz
|
||||
|
||||
# 项目ID
|
||||
VITE_APIFOX_PROJECT_ID = 7784828
|
||||
|
||||
# 访问令牌
|
||||
VITE_APIFOX_ACCESS_TOKEN = APS-20xZ4VqkdY1I1GC63EPVJHbJGsM4VMqy
|
||||
|
||||
@@ -5,9 +5,13 @@ VITE_ENV = production
|
||||
VITE_CONSOLE = 0
|
||||
|
||||
# 接口地址
|
||||
VITE_BASE_API =
|
||||
|
||||
|
||||
VITE_BASE_API = http://8.138.234.141/ingress/hotelBiz
|
||||
|
||||
# 项目ID
|
||||
VITE_APIFOX_PROJECT_ID = 7574669
|
||||
|
||||
# 访问令牌
|
||||
VITE_APIFOX_ACCESS_TOKEN = APS-20xZ4VqkdY1I1GC63EPVJHbJGsM4VMqy
|
||||
|
||||
|
||||
|
||||
|
||||
12
.env.staging
12
.env.staging
@@ -5,10 +5,14 @@ VITE_ENV = staging
|
||||
VITE_CONSOLE = 1
|
||||
|
||||
# 接口地址
|
||||
VITE_BASE_API =
|
||||
|
||||
|
||||
|
||||
VITE_BASE_API = http://8.138.234.141/ingress/hotelBiz
|
||||
|
||||
|
||||
# 项目ID
|
||||
VITE_APIFOX_PROJECT_ID = 7574669
|
||||
|
||||
# 访问令牌
|
||||
VITE_APIFOX_ACCESS_TOKEN = APS-20xZ4VqkdY1I1GC63EPVJHbJGsM4VMqy
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
3
openapi-ts-request.cache.json
Normal file
3
openapi-ts-request.cache.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"调查问卷相关接口": "surveyRelatedInterfaces"
|
||||
}
|
||||
14
openapi-ts-request.config.ts
Normal file
14
openapi-ts-request.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { GenerateServiceProps } from 'openapi-ts-request'
|
||||
|
||||
export default [
|
||||
{
|
||||
serversPath: './src/api',
|
||||
requestLibPath: '@common/ajax',
|
||||
isTranslateToEnglishTag: true,
|
||||
apifoxConfig: {
|
||||
projectId: process.env.VITE_APIFOX_PROJECT_ID || '',
|
||||
apifoxToken: process.env.VITE_APIFOX_ACCESS_TOKEN || '',
|
||||
moduleId: 7069548 // 模块ID
|
||||
}
|
||||
}
|
||||
] as GenerateServiceProps[]
|
||||
10
package.json
10
package.json
@@ -3,9 +3,10 @@
|
||||
"description": "智念移动端单页应用Vue3模板",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build:prod": "vite build && rimraf ./dist/assets/*.map && rimraf stats.html",
|
||||
"build:stage": "vite build --mode staging",
|
||||
"dev": "dotenv -e .env.development vite",
|
||||
"build:prod": "dotenv -e .env.production vite build && rimraf ./dist/assets/*.map && rimraf stats.html",
|
||||
"build:stage": "dotenv -e .env.staging vite build && rimraf ./dist/assets/*.map && rimraf stats.html",
|
||||
"openapi": "dotenv -e .env.development -- openapi-ts",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint --ext .vue,.js src",
|
||||
"lint:fix": "eslint --fix --ext .vue,.js src",
|
||||
@@ -14,7 +15,10 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.13.4",
|
||||
"compressorjs": "^1.2.1",
|
||||
"dotenv-cli": "^11.0.0",
|
||||
"mitt": "^3.0.1",
|
||||
"openai": "^6.17.0",
|
||||
"openapi-ts-request": "^1.12.4",
|
||||
"vant": "^4.9.22",
|
||||
"vconsole": "^3.15.1",
|
||||
"vue": "^3.5.27",
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Session } from '@utils/storage'
|
||||
|
||||
const router = useRouter()
|
||||
const KeepAliveList = ref([])
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const keepAlive = to?.meta?.keepAlive
|
||||
Session.set('token', to.query.token)
|
||||
|
||||
if (!router.hasRoute(to.name)) {
|
||||
router.push('/error')
|
||||
|
||||
5
src/api/index.ts
Normal file
5
src/api/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
export * from './types';
|
||||
|
||||
export * from './surveyRelatedInterfaces';
|
||||
38
src/api/surveyRelatedInterfaces.ts
Normal file
38
src/api/surveyRelatedInterfaces.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import request from '@common/ajax';
|
||||
|
||||
import * as API from './types';
|
||||
|
||||
/** 获取问卷内容 GET /survey/getSurveyQuestionnaire */
|
||||
export function getSurveyQuestionnaireUsingGet({
|
||||
options,
|
||||
}: {
|
||||
options?: { [key: string]: unknown };
|
||||
}) {
|
||||
return request<API.RSurveyQuestionnaireDTO>(
|
||||
'/survey/getSurveyQuestionnaire',
|
||||
{
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 提交问卷答案 POST /survey/submitSurveyQuestionnaireAnswer */
|
||||
export function submitSurveyQuestionnaireAnswerUsingPost({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.SubmitSurveyQuestionnaireAnswerForm;
|
||||
options?: { [key: string]: unknown };
|
||||
}) {
|
||||
return request<API.RBoolean>('/survey/submitSurveyQuestionnaireAnswer', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
97
src/api/types.ts
Normal file
97
src/api/types.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
|
||||
export type GetSurveyQuestionnaireUsingGetResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: RSurveyQuestionnaireDTO;
|
||||
/**
|
||||
* Forbidden
|
||||
*/
|
||||
403: R;
|
||||
/**
|
||||
* Internal Server Error
|
||||
*/
|
||||
500: R;
|
||||
};
|
||||
|
||||
export type R = {
|
||||
code?: number;
|
||||
msg?: string;
|
||||
data?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type RBoolean = {
|
||||
code?: number;
|
||||
msg?: string;
|
||||
data?: boolean;
|
||||
};
|
||||
|
||||
export type RSurveyQuestionnaireDTO = {
|
||||
code?: number;
|
||||
msg?: string;
|
||||
data?: SurveyQuestionnaireDTO;
|
||||
};
|
||||
|
||||
export type SubmitSurveyQuestionnaireAnswerForm = {
|
||||
/** 问卷id */
|
||||
surveyId?: string;
|
||||
/** 答案列表 */
|
||||
answers?: SurveyQuestionnaireAnswerEntity[];
|
||||
};
|
||||
|
||||
export type SubmitSurveyQuestionnaireAnswerUsingPostResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: RBoolean;
|
||||
/**
|
||||
* Forbidden
|
||||
*/
|
||||
403: R;
|
||||
/**
|
||||
* Internal Server Error
|
||||
*/
|
||||
500: R;
|
||||
};
|
||||
|
||||
export type SurveyQuestionnaireAnswerEntity = {
|
||||
/** 问题id */
|
||||
questionId?: string;
|
||||
/** 回答 */
|
||||
answer?: string;
|
||||
};
|
||||
|
||||
export type SurveyQuestionnaireDTO = {
|
||||
/** 版本 */
|
||||
version?: string;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
/** 描述 */
|
||||
description?: string;
|
||||
/** 问卷id */
|
||||
id?: string;
|
||||
/** 标题 */
|
||||
title?: string;
|
||||
/** 问题内容 */
|
||||
questions?: SurveyQuestionnaireQuestionDTO[];
|
||||
};
|
||||
|
||||
export type SurveyQuestionnaireQuestionDTO = {
|
||||
/** 问题id */
|
||||
id?: string;
|
||||
/** 选项类型 radio text checkbox textarea */
|
||||
type?: string;
|
||||
/** 问题id */
|
||||
question?: string;
|
||||
/** 问题选项列表 */
|
||||
options?: SurveyQuestionnaireQuestionOptionDTO[];
|
||||
};
|
||||
|
||||
export type SurveyQuestionnaireQuestionOptionDTO = {
|
||||
/** 选项id */
|
||||
id?: string;
|
||||
/** 选项内容 */
|
||||
text?: string;
|
||||
};
|
||||
@@ -1,32 +1,47 @@
|
||||
import axios from 'axios'
|
||||
import { tansParams } from '@utils/tansParams'
|
||||
import { Session } from '@utils/storage'
|
||||
|
||||
const request = async (method, url, data, config = {}) => {
|
||||
const options = Object.assign({}, config, {
|
||||
url,
|
||||
method
|
||||
})
|
||||
// 获取.env中的服务地址
|
||||
const { VITE_BASE_API, VITE_ENV } = import.meta.env
|
||||
console.log('🚀 ~ VITE_ENV:', VITE_ENV)
|
||||
console.log('🚀 ~ VITE_BASE_API:', VITE_BASE_API)
|
||||
|
||||
console.log('入参', data)
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
|
||||
options.headers = Object.assign({}, options.headers, header)
|
||||
// 创建axios对象
|
||||
const instance = axios.create({
|
||||
baseURL: VITE_ENV === 'development' ? '/ingress/hotelBiz' : VITE_BASE_API,
|
||||
// 超时
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then((res) => {
|
||||
console.log('返回值', res.data)
|
||||
resolve(res.data)
|
||||
})
|
||||
.catch((res) => {
|
||||
reject(res)
|
||||
})
|
||||
}
|
||||
// 添加拦截器
|
||||
instance.interceptors.request.use((config) => {
|
||||
const token = Session.getToken()
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
|
||||
export const ajax = {
|
||||
request,
|
||||
get(url, config) {
|
||||
return request('get', url, null, config)
|
||||
},
|
||||
post(url, data, config) {
|
||||
return request('post', url, data, config)
|
||||
// get请求映射params参数
|
||||
if (config.method === 'get' && config.params) {
|
||||
let url = config.url + '?' + tansParams(config.params)
|
||||
console.log('🚀 ~ url:', url)
|
||||
|
||||
url = url.slice(0, -1)
|
||||
config.params = {}
|
||||
config.url = url
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
// 添加响应拦截器
|
||||
instance.interceptors.response.use(
|
||||
(res) => {
|
||||
return Promise.resolve(res.data.data)
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default instance
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
<template>
|
||||
<div class="page-container" :style="{ backgroundColor: bgColor }">
|
||||
<van-nav-bar
|
||||
:class="['nav-bar', navBgColor, isCustom ? 'custom-style' : '']"
|
||||
safe-area-inset-top
|
||||
left-arrow
|
||||
fixed
|
||||
v-if="showNavigator"
|
||||
:border="false"
|
||||
:left-text="navBarLeftText"
|
||||
@click-left="handleBack"
|
||||
>
|
||||
<van-nav-bar :class="['nav-bar', navBgColor, isCustom ? 'custom-style' : '']" safe-area-inset-top left-arrow fixed
|
||||
v-if="showNavigator" :border="false" :left-text="navBarLeftText" @click-left="handleBack">
|
||||
<template #title>
|
||||
<slot name="title">{{ title === '首页' ? '' : title }}</slot>
|
||||
<slot name="title">{{ title === '首页' ? '' : metaTitle }}</slot>
|
||||
</template>
|
||||
|
||||
<template #right>
|
||||
@@ -19,7 +11,9 @@
|
||||
</template>
|
||||
</van-nav-bar>
|
||||
|
||||
<slot name="body"></slot>
|
||||
<section class="body">
|
||||
<slot></slot>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -79,7 +73,7 @@ const props = defineProps({
|
||||
const showNavigator = ref(props.show)
|
||||
|
||||
// 获取页面标题
|
||||
const { title } = proxy.$router.currentRoute.value.meta
|
||||
const { title: metaTitle } = proxy.$router.currentRoute.value.meta || {}
|
||||
|
||||
const handleBack = () => {
|
||||
if (props.goback > 0) {
|
||||
@@ -113,37 +107,18 @@ const handleBack = () => {
|
||||
position: fixed;
|
||||
|
||||
:deep(.van-icon-arrow-left) {
|
||||
color: #fff;
|
||||
color: #333;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
:deep(.van-nav-bar__title) {
|
||||
color: #fff;
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
line-height: 22px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.style-1,
|
||||
&.style-2 {
|
||||
:deep(.van-icon-arrow-left) {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
:deep(.van-nav-bar__title) {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
&.style-1 {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&.style-2 {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&.custom-style {
|
||||
background-color: rgba(22, 187, 191, 1);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as PageContainer } from './PageContainer.vue'
|
||||
export { default as Layout } from './Layout.vue'
|
||||
export { default as Empty } from './Empty.vue'
|
||||
|
||||
@@ -5,9 +5,12 @@ import App from './App.vue'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
|
||||
import Layout from '@/components/Layout.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
app.config.globalProperties.$store = store
|
||||
|
||||
app.use(router)
|
||||
app.component('Layout', Layout)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@@ -7,7 +7,7 @@ const routes = [
|
||||
name: 'home', // 请和文件名一样
|
||||
component: () => import('@/views/home/index.vue'),
|
||||
meta: {
|
||||
title: '首页', // 自动设置当前页面的标题
|
||||
title: '问卷调查', // 自动设置当前页面的标题
|
||||
keepAlive: true
|
||||
}
|
||||
}
|
||||
|
||||
70
src/utils/storage.ts
Normal file
70
src/utils/storage.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* window.localStorage 浏览器永久缓存
|
||||
* @method set 设置永久缓存
|
||||
* @method get 获取永久缓存
|
||||
* @method remove 移除永久缓存
|
||||
* @method clear 移除全部永久缓存
|
||||
*/
|
||||
export const Local = {
|
||||
// 查看 v2.4.3版本更新日志
|
||||
setKey(key: string) {
|
||||
// @ts-ignore
|
||||
return `${__NEXT_NAME__}:${key}`
|
||||
},
|
||||
|
||||
// 设置永久缓存
|
||||
set<T>(key: string, val: T) {
|
||||
window.localStorage.setItem(Local.setKey(key), JSON.stringify(val))
|
||||
},
|
||||
|
||||
// 获取永久缓存
|
||||
get(key: string) {
|
||||
let json = <string>window.localStorage.getItem(Local.setKey(key))
|
||||
return JSON.parse(json)
|
||||
},
|
||||
|
||||
// 移除永久缓存
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(Local.setKey(key))
|
||||
},
|
||||
|
||||
// 移除全部永久缓存
|
||||
clear() {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* window.sessionStorage 浏览器临时缓存
|
||||
* @method set 设置临时缓存
|
||||
* @method get 获取临时缓存
|
||||
* @method remove 移除临时缓存
|
||||
* @method clear 移除全部临时缓存
|
||||
*/
|
||||
export const Session = {
|
||||
// 设置临时缓存
|
||||
set(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
|
||||
// 获取临时缓存
|
||||
get(key: string) {
|
||||
let json = <string>window.sessionStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
|
||||
// 移除临时缓存
|
||||
remove(key: string) {
|
||||
window.sessionStorage.removeItem(key)
|
||||
},
|
||||
|
||||
// 移除全部临时缓存
|
||||
clear() {
|
||||
window.sessionStorage.clear()
|
||||
},
|
||||
|
||||
// 获取当前存储的 token
|
||||
getToken() {
|
||||
return this.get('token')
|
||||
}
|
||||
}
|
||||
29
src/utils/tansParams.ts
Normal file
29
src/utils/tansParams.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 参数处理
|
||||
* @param {*} params 参数
|
||||
*/
|
||||
export function tansParams(params: any) {
|
||||
let result = ''
|
||||
|
||||
for (const propName of Object.keys(params)) {
|
||||
const value = params[propName]
|
||||
|
||||
var part = encodeURIComponent(propName) + "="
|
||||
|
||||
if (value !== null && value !== "" && typeof (value) !== "undefined") {
|
||||
if (typeof value === 'object') {
|
||||
for (const key of Object.keys(value)) {
|
||||
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
|
||||
let params = propName + '[' + key + ']'
|
||||
var subPart = encodeURIComponent(params) + "="
|
||||
result += subPart + encodeURIComponent(value[key]) + "&"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result += part + encodeURIComponent(value) + "&"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -1,8 +1,15 @@
|
||||
<template>
|
||||
<van-button @click="handleClick">跳转记录</van-button>
|
||||
<Layout>
|
||||
<template #title>{{ questionnaire.title }}</template>
|
||||
|
||||
<div class="list">
|
||||
{{ questionnaire.questions }}
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script setup name="home">
|
||||
import { getSurveyQuestionnaireUsingGet } from '@api'
|
||||
const router = useRouter()
|
||||
|
||||
// 跳转按钮操作
|
||||
@@ -10,13 +17,19 @@ const handleClick = () => {
|
||||
console.log('跳转记录')
|
||||
}
|
||||
|
||||
const questionnaire = ref({})
|
||||
const getQuestionnaire = async () => {
|
||||
questionnaire.value = await getSurveyQuestionnaireUsingGet({})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('onMounted')
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
console.log('onActivated')
|
||||
getQuestionnaire()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
section {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"],
|
||||
"@common": ["src/common/*"],
|
||||
"@api": ["src/api/*"],
|
||||
"@utils": ["src/utils/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["src/**/*", "**/*.ts"]
|
||||
}
|
||||
@@ -76,14 +76,22 @@ export default defineConfig(({ mode }) => {
|
||||
// 设置路径别名
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src'),
|
||||
'@api': resolve(__dirname, './src/api'),
|
||||
'@common': resolve(__dirname, './src/common'),
|
||||
'@utils': resolve(__dirname, './src/utils'),
|
||||
'~': resolve(__dirname, './src/assets')
|
||||
}
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/ingress/hotelBiz': {
|
||||
target: 'http://8.138.234.141',
|
||||
changeOrigin: true
|
||||
}
|
||||
},
|
||||
hmr: true,
|
||||
port: 8080,
|
||||
host: true,
|
||||
open: true
|
||||
host: true
|
||||
},
|
||||
css: {
|
||||
// css预处理器
|
||||
|
||||
Reference in New Issue
Block a user