Nginx反向代理配置
代理到 /api
的操作配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server { listen 9099; server_name localhost;
location / { root /opt/service/manager/frontend; index index.html index.htm; try_files $uri $uri/ /index.html; }
location ^~ /api { proxy_pass http://xxxxxxx/; } }
|
Nginx同个端口配置多个项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| server { listen 9099; server_name localhost;
# 官网 location / { root /opt/service/manager/frontend/web; index index.html index.htm; try_files $uri $uri/ /index.html; }
# 后台 location /super/admin { alias /opt/service/manager/frontend/admin; index index.html index.htm; try_files $uri $uri/ /super/admin/index.html; }
location ^~ /api { # 代理到后端接口地址 proxy_pass http://11.111.111.111:8080/; } }
|
这样就可以使用 http://11.111.111.111:9099
访问官网,使用 http://11.111.111.111:9099/super/admin
访问后台了。
Nginx同个端口配置移动端与PC端项目
我们想要在一个端口上配置PC端与移动端项目,并在手机上打开显示移动端页面,在PC端打开显示PC端页面。
可以在 Nginx 下做如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| server { listen 8080; server_name localhost; index index.html; root /opt/service/frontend/pc; #PC端的路径
location / { root /opt/service/frontend/pc; #PC端的路径 if ( $http_user_agent ~ "(MIDP)|(WAP)|(UP.Browser)|(Smartphone)|(Obigo)|(Mobile)|(AU.Browser)|(wxd.Mms)|(WxdB.Browser)|(CLDC)|(UP.Link)|(KM.Browser)|(UCWEB)|(SEMC\-Browser)|(Mini)|(Symbian)|(Palm)|(Nokia)|(Panasonic)|(MOT\-)|(SonyEricsson)|(NEC\-)|(Alcatel)|(Ericsson)|(BENQ)|(BenQ)|(Amoisonic)|(Amoi\-)|(Capitel)|(PHILIPS)|(SAMSUNG)|(Lenovo)|(Mitsu)|(Motorola)|(SHARP)|(WAPPER)|(LG\-)|(LG/)|(EG900)|(CECT)|(Compal)|(kejian)|(Bird)|(BIRD)|(G900/V1.0)|(Arima)|(CTL)|(TDG)|(Daxian)|(DAXIAN)|(DBTEL)|(Eastcom)|(EASTCOM)|(PANTECH)|(Dopod)|(Haier)|(HAIER)|(KONKA)|(KEJIAN)|(LENOVO)|(Soutec)|(SOUTEC)|(SAGEM)|(SEC\-)|(SED\-)|(EMOL\-)|(INNO55)|(ZTE)|(iPhone)|(Android)|(Windows CE)|(Wget)|(Java)|(curl)|(Opera)" ){ root /opt/service/frontend/h5; #移动端的路径 } try_files $uri $uri/ /index.html; index index.html index.htm; }
# 下面还可以配置一些代理等等 }
|
Nginx配置ws
在 http
下新增:
1 2 3 4
| map $http_upgrade $connection_upgrade { default upgrade; '' close; }
|
在 server
下做如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| server { listen 80; server_name 域名/localhost;
location / { root /opt/service/...; index index.html index.htm; try_files $uri $uri/ /index.html;
proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 3600s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
location ^~ /api { proxy_pass http://xxx/; } }
|
在项目的 .env.production
文件可以配置 ws 路径:
1 2 3 4 5 6 7
| ENV = 'production'
# base api VUE_APP_BASE_API = '/api'
# ws VUE_APP_WS_API = 'ws://xxx:9000'
|
预览文件功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <template> <div class="preview"> <el-button @click="getfileSrc()">预览</el-button> <el-dialog :visible.sync="fileshow" :close-on-click-modal="false" class="pdfshow-dialog" title="预览" width="90%" top="2%" > <iframe :src='fileSrc' width="100%" height="100%" frameborder="0" scrolling="auto" style="position:absolute;left: 0px;z-index:1000" v-if="isImg == false" > </iframe> <div v-else-if="isImg == true"> <el-image style="width: 10%; height: 10%" :src="fileSrc" :preview-src-list="srcList" > </el-image> </div> <span slot="footer" class="dialog-footer" > </span> </el-dialog> </div> </template>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <script> export default { name: 'preview', props: ['fileUrl'], data() { return { fileshow: false, fileSrc: '', isImg: false, srcList: [] } }, methods: { getfileSrc() { if (/\.(xlsx|xls|doc|docx)$/.test(this.fileUrl)) { this.fileSrc = 'https://view.officeapps.live.com/op/view.aspx?src=' + this.fileUrl this.fileshow = true } else if (/\.(pdf|PDF)$/.test(this.fileUrl)) { this.fileshow = true this.fileSrc = this.fileUrl } else if (/\.(png|jpg|webp|jpeg)$/.test(this.fileUrl)) { this.isImg = true this.fileshow = true this.fileSrc = this.fileUrl this.srcList.push(this.fileUrl) } else { this.$message.warning('该格式暂不支持预览,请直接下载查看') } } } } </script>
|
使用:
1
| <preview :fileUrl="url地址"></preview>
|
file-online-preview
word、pdf文件内容比较
Draftable
element引入骨架屏
这里使用 vue-elementui-skeleton
安装:
1
| npm i vue-elementui-skeleton
|
引入:
1 2 3 4 5 6 7 8 9 10 11 12
| import VueElementUISkeleton from 'vue-elementui-skeleton'; Vue.use(VueElementUISkeleton);
|
使用:
1
| <el-table v-skeleton="loading"></el-table>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| export default { data() { return { loading: false }; }, mounted() { this.loading = true; this.getList() }, methods: { getList(){ this.loading = false; } } };
|
实现语音播报功能
这里我们使用 百度TTS 来实现。
首先在 utils
文件夹下新建 voicePrompt.js
:
1 2 3 4 5 6 7
| function voicePrompt(text) { new Audio('http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=6&text=' + text).play(); }
export { voicePrompt }
|
在 main.js
文件中导入:
1 2
| import * as voicePromptFun from './utils/voicePrompt' Vue.prototype.voicePrompt = voicePromptFun.voicePrompt
|
使用:
百度TTS 相关参数解释:
lan=zh
:语言,英文则为 lan=en
;
ie=UTF-8
:文字格式;
spd=6
:语速,范围是 1~9 的数字;
text=
:需要播报的文字;
element表格复制每一行特定内容
使用 vue-clipboard2 来实现此功能。
安装:
1
| npm install --save vue-clipboard2
|
在 main.js
引入:
1 2
| import VueClipboard from 'vue-clipboard2' Vue.use(VueClipboard)
|
使用:
1 2 3 4 5 6 7 8 9 10 11 12
| <el-table :data="dataList"> <el-table-column prop="content" label="复制内容" > <template scope="scope"> <div @click="copyContent(scope.row.content)"> {{scope.row.content}} </div> </template> </el-table-column> </el-table>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <script> export default { methods: { copyContent(content) { this.$copyText(content) .then(res => { this.$message({ showClose: true, message: '已复制内容: ' + content, type: 'info' }) }) .catch(err => { this.$message({ showClose: true, message: '复制失败,请手动复制', type: 'error' }) }) }, } } </script>
|
element-admin打包去除log打印
编辑 vue.config.js
文件:
1 2 3 4 5 6 7 8 9
| module.exports = { chainWebpack(config) { config.optimization.minimizer('terser').tap(options => { options[0].terserOptions.compress.drop_console = true; return options; }) } }
|
el-tabs切换刷新数据并跳转到指定的tab上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <el-tabs tab-position="left" v-model="activeName" @tab-click="handleTabClick" > <el-tab-pane label="Demo1" name="demo1" > <DemoOne v-if="tabRefresh.demo1" /> </el-tab-pane> <el-tab-pane label="Demo2" name="demo2" > <DemoTwo v-if="tabRefresh.demo2" /> </el-tab-pane> </el-tabs>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| export default { data() { return { activeName: "demo1", tabRefresh: { demo1: true, demo2: false } }; }, created() { this.jumpTab(); }, methods: { jumpTab() { if (this.$route.query.activeName) { this.activeName = this.$route.query.activeName; for (let i in this.tabRefresh) { if (i == this.$route.query.activeName) { this.switchTab(i); } } } }, handleTabClick(tab, event) { switch (this.activeName) { case "demo1": this.switchTab("demo1"); break; case "demo2": this.switchTab("demo2"); break; default: } }, switchTab(tab) { for (let [key, value] of Object.entries(this.tabRefresh)) { if (key == tab) { this.tabRefresh[key] = true; } else { this.tabRefresh[key] = false; } } } } };
|
封装axios
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| import axios from 'axios' import { MessageBox, Message, Loading } from 'element-ui' import { getToken } from '@/utils/auth'
const service = axios.create({ baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/api', timeout: 60000 })
service.interceptors.request.use( config => {
if (getToken()) { config.headers['X-Token'] = getToken() } config.headers['Content-Type'] = 'application/json' return config }, error => { console.log(error) return Promise.reject(error) } )
service.interceptors.response.use( response => { const res = response.data
if (res.type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { return response }
if (res.code !== 0) { return Promise.reject(new Error(res.msg || 'Error')) } else { return res } }, error => { console.log('err' + error) if (error.toString().indexOf('Error: timeout') !== -1) { Message({ message: '网络请求超时', type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } else { Message({ message: error.message, type: 'error', duration: 5 * 1000 }) } return Promise.reject(error) } )
export function upload(url, file, data) { const formData = new FormData() formData.append('file', file)
if (data) { Object.keys(data).forEach((key) => { formData.append(key, data[key]) }) }
return new Promise((resolve, reject) => { const loading = Loading.service({ text: '正在上传数据...', background: 'rgba(0, 0, 0, 0.7)' })
service.request({ url: url, method: 'post', data: formData, timeout: 1200000 }).then(response => { loading.close() resolve(response) }).catch(err => { loading.close() reject(err) }) }) }
export function downloadTemplate(url, data, fileName) { return new Promise((resolve, reject) => { const loading = Loading.service({ text: '正在下载数据...', background: 'rgba(0, 0, 0, 0.7)' })
service.request({ url: url, method: 'post', data: data, timeout: 1200000, responseType: 'blob' }).then(res => { loading.close()
const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
let link = document.createElement('a') link.href = URL.createObjectURL(blob) link.setAttribute('download', fileName) link.click() link = null Message.success('模板下载成功!')
}).catch(err => { loading.close() reject(err) }) }) }
export default service
|
文件上传的使用方法:
创建 /src/api/file.js
文件:
1 2 3 4 5
| import { upload } from '@/utils/request'
export function importExcelApi(file) { return upload('/non/ledger/import', file) }
|
在需要的页面引入并使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div> <el-button type="warning" size="small" icon="el-icon-upload" @click="chooseFile" >上传导入</el-button> <input ref="upFile" class="file" name="file" type="file" style="display: none;" @change="doImport" > </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { importExcelApi } from "@/api/file"; export default { methods: { chooseFile: function() { this.$refs.upFile.dispatchEvent(new MouseEvent("click")); }, doImport(e) { const file = e.target.files[0];
importExcelApi(file).then(res => { console.log(res); if (res.code !== 0) { this.$alert(res.msg, "导入信息", { dangerouslyUseHTMLString: true }); } else { this.$message({ message: "数据导入成功!", type: "success" }); } }); } } };
|
element中Select选择器实现可选可输
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <el-select v-model="form.bindValue" placeholder="请选择" default-first-option filterable @blur="selectBlur($event)" @focus="selectFocus($event)" ref="selectRef" > <el-option v-for="item in list" :key="item.id" :label="item.label" :value="item.value" > </el-option> </el-select>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| export default { data() { return { list: [], form: { bindValue: "", } }; }, methods: { selectBlur(e) { if (e.target.value) { this.$set(this.form, "bindValue", e.target.value); } }, selectFocus(e) { let value = e.target.value; setTimeout(() => { let input = this.$refs.selectRef.$children[0].$refs.input; input.value = value; }); } } };
|
持续更新中!