Commit 98b45360 by 杨铁龙

demo

parent 66958fa2
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"init-submodule": "git submodule init && git submodule update && cd src/customer-service && git checkout master && git pull && npm install --registry http://npm.job.qinqinxiaobao.com" "init-submodule": "git submodule init && git submodule update && cd src/customer-service && git checkout master && git pull && npm install --registry http://npm.job.qinqinxiaobao.com"
}, },
"dependencies": { "dependencies": {
"axios": "^0.26.0",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-ui": "^2.15.7", "element-ui": "^2.15.7",
"lodash": "^4.17.21", "lodash": "^4.17.21",
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
"vuex-class": "^0.3.2" "vuex-class": "^0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.14.178",
"@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0", "@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-babel": "~5.0.0",
...@@ -42,6 +44,8 @@ ...@@ -42,6 +44,8 @@
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0", "eslint-plugin-promise": "^5.1.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"sass": "^1.32.7", "sass": "^1.32.7",
"sass-loader": "^12.0.0", "sass-loader": "^12.0.0",
"typescript": "~4.5.5", "typescript": "~4.5.5",
...@@ -72,7 +76,13 @@ ...@@ -72,7 +76,13 @@
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/camelcase": "off", "@typescript-eslint/camelcase": "off",
"no-useless-constructor": "off", "no-useless-constructor": "off",
"@typescript-eslint/no-namespace": "off" "@typescript-eslint/no-namespace": "off",
"camelcase": [
0,
{
"properties": "never"
}
]
} }
}, },
"browserslist": [ "browserslist": [
......
VUE_APP_WWW_WORK_APP_URL="http://106.120.107.150:45000"
VUE_APP_API_WORK_APP_URL="http://106.120.107.150:48090"
VUE_APP_USER_CENTER="http://106.120.107.150:48080"
VUE_APP_UNIPLAT="http://hro.dev-xim-api.qqxb.jinsehuaqin.com:8800"
VUE_APP_H5_URL="https://pre-bj.hrs100.com"
VUE_APP_LAND_PAGE="https://static-bijie.qinqinxiaobao.com"
VUE_APP_BJRSY_COLLECTION="https://bjcjtest.e-tecsun.com"
VUE_APP_CLIENT_ID="daai_bijie_wechat_mini_app"
VUE_APP_UNIPLAT_WEBSOCKET_URI="ws://channel.jinsehuaqin.com:8080/ws"
VUE_APP_CLIENT_SECRET="123456"
VUE_APP_LOG_ENV="dev"
\ No newline at end of file
<template> <template>
<div id="app"> <div id="app">
<nav>
<router-link to="/">Home</router-link>|
<router-link to="/about">About</router-link>
</nav>
<router-view /> <router-view />
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style> </style>
// 此部分是参考常见栅格样式,提供常用分割布局的全局class
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12,
.col,
.col-auto,
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12,
.col-sm,
.col-sm-auto,
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11,
.col-md-12,
.col-md,
.col-md-auto,
.col-lg-1,
.col-lg-2,
.col-lg-3,
.col-lg-4,
.col-lg-5,
.col-lg-6,
.col-lg-7,
.col-lg-8,
.col-lg-9,
.col-lg-10,
.col-lg-11,
.col-lg-12,
.col-lg,
.col-lg-auto,
.col-xl-1,
.col-xl-2,
.col-xl-3,
.col-xl-4,
.col-xl-5,
.col-xl-6,
.col-xl-7,
.col-xl-8,
.col-xl-9,
.col-xl-10,
.col-xl-11,
.col-xl-12,
.col-xl,
.col-xl-auto {
position: relative;
width: 100%;
padding-right: 15px;
padding-left: 15px;
}
.col {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.row-cols-1 > * {
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.row-cols-2 > * {
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.row-cols-3 > * {
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.row-cols-4 > * {
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.row-cols-5 > * {
-ms-flex: 0 0 20%;
flex: 0 0 20%;
max-width: 20%;
}
.row-cols-6 > * {
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-auto {
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: 100%;
}
.col-1 {
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-2 {
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-3 {
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-4 {
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-5 {
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-6 {
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-7 {
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-8 {
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-9 {
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-10 {
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-11 {
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-12 {
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.d-flex {
display: -ms-flexbox;
display: flex;
}
.d-inline-flex {
display: -ms-inline-flexbox;
display: inline-flex;
}
.flex-row {
-ms-flex-direction: row;
flex-direction: row;
}
.flex-column {
-ms-flex-direction: column;
flex-direction: column;
}
.flex-row-reverse {
-ms-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.flex-column-reverse {
-ms-flex-direction: column-reverse;
flex-direction: column-reverse;
}
.flex-wrap {
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.flex-nowrap {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.flex-wrap-reverse {
-ms-flex-wrap: wrap-reverse;
flex-wrap: wrap-reverse;
}
.flex-fill {
-ms-flex: 1 1 auto;
flex: 1 1 auto;
}
.flex-none {
flex: none;
}
.flex-grow-0 {
-ms-flex-positive: 0;
flex-grow: 0;
}
.flex-grow-1 {
-ms-flex-positive: 1;
flex-grow: 1;
}
.flex-shrink-0 {
-ms-flex-negative: 0;
flex-shrink: 0;
}
.flex-shrink-1 {
-ms-flex-negative: 1;
flex-shrink: 1;
}
.justify-content-start {
-ms-flex-pack: start;
justify-content: flex-start;
}
.justify-content-end {
-ms-flex-pack: end;
justify-content: flex-end;
}
.justify-content-center {
-ms-flex-pack: center;
justify-content: center;
}
.justify-content-between {
-ms-flex-pack: justify;
justify-content: space-between;
}
.justify-content-around {
-ms-flex-pack: distribute;
justify-content: space-around;
}
.align-items-start {
-ms-flex-align: start;
align-items: flex-start;
}
.align-items-end {
-ms-flex-align: end;
align-items: flex-end;
}
.align-items-center {
-ms-flex-align: center;
align-items: center;
}
.align-items-baseline {
-ms-flex-align: baseline;
align-items: baseline;
}
.align-items-stretch {
-ms-flex-align: stretch;
align-items: stretch;
}
.align-content-start {
-ms-flex-line-pack: start;
align-content: flex-start;
}
.align-content-end {
-ms-flex-line-pack: end;
align-content: flex-end;
}
.align-content-center {
-ms-flex-line-pack: center;
align-content: center;
}
.align-content-between {
-ms-flex-line-pack: justify;
align-content: space-between;
}
.align-content-around {
-ms-flex-line-pack: distribute;
align-content: space-around;
}
.align-content-stretch {
-ms-flex-line-pack: stretch;
align-content: stretch;
}
.align-self-auto {
-ms-flex-item-align: auto;
align-self: auto;
}
.align-self-start {
-ms-flex-item-align: start;
align-self: flex-start;
}
.align-self-end {
-ms-flex-item-align: end;
align-self: flex-end;
}
.align-self-center {
-ms-flex-item-align: center;
align-self: center;
}
.align-self-baseline {
-ms-flex-item-align: baseline;
align-self: baseline;
}
.align-self-stretch {
-ms-flex-item-align: stretch;
align-self: stretch;
}
.ml-auto {
margin-left: auto;
}
.mr-auto {
margin-right: auto;
}
.mt-auto {
margin-top: auto;
}
.mb-auto {
margin-bottom: auto;
}
@import 'variables.less';
// 此部分 layout 大多是参考 bootstrap 的全局样式设计
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
article,
aside,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section {
display: block;
}
@root-font-family: 'PingFangSC-Regular', 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
body {
margin: 0;
font-family: @root-font-family;
font-size: 13px;
font-weight: 400;
line-height: 1;
text-align: left;
background-color: #fff;
line-height: 1 !important;
}
.font-family-medium {
font-family: @root-weight-family;
font-weight: 600;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
[tabindex='-1']:focus:not(:focus-visible) {
outline: 0;
}
textarea,
input[type='text'],
input[type='number'] {
font-family: @root-font-family;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: @primary-a-color;
text-decoration: none;
background-color: transparent;
}
a:hover {
color: @primary-a-hover;
text-decoration: underline;
}
a:not([href]) {
color: inherit;
text-decoration: none;
}
a:not([href]):hover {
color: inherit;
text-decoration: none;
}
.w-25 {
width: 25%;
}
.w-50 {
width: 50%;
}
.w-75 {
width: 75%;
}
.w-100 {
width: 100%;
}
.w-auto {
width: auto;
}
.h-25 {
height: 25%;
}
.h-50 {
height: 50%;
}
.h-75 {
height: 75%;
}
.h-100 {
height: 100%;
}
.text-justify {
text-align: justify;
}
.text-wrap {
white-space: normal;
}
.text-nowrap {
white-space: nowrap;
}
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-clickable {
cursor: pointer;
}
.overflow-hidden {
overflow: hidden;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
.required {
position: relative;
padding-left: 10px;
&.no-offset {
padding-left: 0;
&:before {
left: -10px;
}
}
&:before {
position: absolute;
content: '*';
left: 0;
top: 0;
color: @text-danger;
}
&.center {
&:before {
top: 50%;
transform: translateY(-50%);
}
}
}
[type='number'],
[type='number'],
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button {
height: auto;
-webkit-appearance: none;
-moz-appearance: textfield;
}
[type='search'] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
span:focus,
div:focus {
outline: none;
}
.main-content-router-view {
width: calc(100% - @left-menu-width);
}
.hyper-link {
text-decoration: underline;
color: @text-danger-2;
cursor: pointer;
}
@mainColor: #077aec; // 团队工作站主色调
// 默认控件在disabled 状态时的不透明度
@default-control-disable-opacity: 0.5;
/// 适用于对话框,弹框的header 头
@primary-header-text-color: #000;
@primary-a-color: @mainColor;
@primary-a-hover: @mainColor;
// 以下均为不同type的按钮在各自不同状态下的属性
@fs-button-bgc-primary: @mainColor;
@fs-button-border-color-primary: @mainColor;
@fs-button-text-color-primary: #fff;
@fs-button-hover-bgc-primary: #60a1ff;
@fs-button-press-bgc-primary: #176ce9;
@fs-button-disable-opacity-primary: @default-control-disable-opacity;
@fs-button-bgc-default: #fff;
@fs-button-border-color-default: @mainColor;
@fs-button-text-color-default: @mainColor;
@fs-button-hover-bgc-default: #f3f7ff;
@fs-button-press-bgc-default: #e4f0ff;
@fs-button-disable-opacity-default: @default-control-disable-opacity;
@fs-button-bgc-info: #f0f0f0;
@fs-button-border-color-info: transparent;
@fs-button-text-color-info: #666;
@fs-button-hover-bgc-info: #e4f0ff;
@fs-button-press-bgc-info: #cfe4ff;
@fs-button-disable-opacity-info: @default-control-disable-opacity;
@fs-button-bgc-plain: #fff;
@fs-button-border-color-plain: #b7bfc7;
@fs-button-text-color-plain: #888;
@fs-button-hover-bgc-plain: #fff;
@fs-button-press-bgc-plain: #f3f7ff;
@fs-button-disable-opacity-plain: @default-control-disable-opacity;
@fs-text-button-default-text-color: #333;
@fs-text-primary-button-active-text-color: #176ce9;
@fs-icon-button-font-size: 16px;
@fs-button-extra-large-size-width: 160px;
@fs-button-extra-large-size-height: 40px;
@fs-button-extra-large-font-size: 16px;
@fs-button-large-size-width: 120px;
@fs-button-large-size-height: 36px;
@fs-button-large-font-size: 15px;
@fs-button-normal-size-width: 100px;
@fs-button-normal-size-height: 36px;
@fs-button-normal-font-size: 14px;
@fs-button-md-size-width: 60px;
@fs-button-md-size-height: 30px;
@fs-button-md-font-size: 14px;
@fs-button-sm-size-width: 50px;
@fs-button-sm-size-height: 25px;
@fs-button-sm-font-size: 13px;
/** 以下是常用文字颜色*/
// 可点击的文字,常用于主按钮/a的颜色
@text-primary: @mainColor;
// 可点击的文字,常用于次级按钮/a的颜色
@text-secondary: #93b1d0;
// 常用于提示信息的文字颜色
@text-warn: #e87005;
// 常用于危险操作的警告色
@text-danger: #dc3545;
@text-danger-2: #d85537;
// 常用于成功操作的文字颜色
@text-success: #22bd7a;
// 用户会话弹窗遮罩背景色
@dialog-mask: rgba(20, 23, 26, 0.2);
//主标题,大标题文字颜色
@text-primary-header: #222;
//次级标题,正文文字颜色
@text-secondary-header: #333;
//次级正文颜色
@text-body: #666;
//提示性正文
@text-info-body: #888;
//提示性文字
@text-hint: #999;
@text-hint-2: #aaa;
@text-timestamp: #c2c2c2;
@dialog-header-border-color: #f0f0f0;
@dialog-header-border-bottom-color: #e2e0e0;
@dialog-header-height: 50px;
@primary-header-border-color: #e1e1e1;
@home-banner-height: 55px;
@selected-menu-color: #077aec;
@hrs-main-content-width: 1200px;
@root-weight-family: 'PingFang SC Medium', 'PingFangSC-Medium', 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
// 右下侧主内容页面宽度,有table时可以使用
@main-content-width: calc(100% - 240px);
@banner-height: 64px;
@left-menu-width: 240px;
@top-nav-menu-height: 54px;
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br />
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa" target="_blank" rel="noopener">pwa</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
export const config = {
passportUrl: 'http://106.120.107.150:45000',
passportApi: 'http://106.120.107.150:48090',
uniplatApi: 'http://hro.dev-xim-api.qqxb.jinsehuaqin.com:8800',
clientId: 'daai_bijie_wechat_mini_app',
uniplatSocketUrl: 'ws://channel.jinsehuaqin.com:8080/ws',
clientSecret: '123456',
testAccount: '18040417207',
testPassword: 'y1234567',
rootEntrance: '大爱毕节小程序',
}
Subproject commit 0c1d96e2c39c3f81caa914d12a8a526e7004ead5 Subproject commit ecca9b6f0f69a1fb3b624bd5e8e1321dc1eba2a0
...@@ -5,10 +5,32 @@ import router from './router' ...@@ -5,10 +5,32 @@ import router from './router'
import store from './store' import store from './store'
import element from 'element-ui' import element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
import { filters } from './utils/filter'
import moment from 'moment'
import './assets/css/flex.less'
import './assets/css/layout.less'
Vue.use(filters)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(element) Vue.use(element)
moment.updateLocale('zh-cn', {
meridiem: function (hour, minute) {
if (hour < 9) {
return '早上'
} else if (hour < 11 && minute < 30) {
return '上午'
} else if (hour < 13 && minute < 30) {
return '中午'
} else if (hour < 18) {
return '下午'
} else {
return '晚上'
}
},
})
new Vue({ new Vue({
router, router,
store, store,
......
File mode changed
File mode changed
/* eslint-disable */
import axios from 'axios'
// create an axios instance
const service = axios.create({
timeout: 5000,
})
service.interceptors.request.use(
(config: any) => {
config.headers.Authorization = localStorage.JWT_TOKEN || ''
return config
},
(error: any) => {
return Promise.reject(error)
}
)
service.interceptors.response.use(
(response: any) => {
const res = response.data
if (res.rescode !== 0) {
console.log(res.msg || 'Error')
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res.data
}
},
(error: string) => {
return Promise.reject(error)
}
)
export default service
import Vue from 'vue' import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router' import VueRouter, { RouteConfig } from 'vue-router'
import HomeView from '../views/HomeView.vue' import HomeView from '../views/home.vue'
Vue.use(VueRouter) Vue.use(VueRouter)
...@@ -10,14 +10,6 @@ const routes: Array<RouteConfig> = [ ...@@ -10,14 +10,6 @@ const routes: Array<RouteConfig> = [
name: 'home', name: 'home',
component: HomeView, component: HomeView,
}, },
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue'),
},
] ]
const router = new VueRouter({ const router = new VueRouter({
......
import { config } from '@/config'
import { ServiceType } from '@/customer-service/model'
import { ns } from '@/customer-service/store'
import { ChatStore } from '@/customer-service/store/model'
import Chat from '@/customer-service/xim'
import store from '@/store'
import { throttle } from 'lodash'
import { sdk } from './sdk'
export function initChat() {
console.log('初始化chat')
return Chat.setup({
sdk: () => sdk.core,
orgId: () => sdk.orgId,
connection: config.uniplatSocketUrl,
serviceType: ServiceType.Frontend,
}).then(() => {
console.log('初始化chat✅ 开始获取和监听消息列表')
return initChatMsg()
})
}
/**
* 初始化消息列表
*/
export async function initChatMsg() {
/** 注册基础事件 */
await store.dispatch(`${ns}/${ChatStore.ACTION_REGISTER_EVENT}`)
/** 注册新消息刷新列表事件 */
await store.commit(`${ns}/${ChatStore.MUTATION_SAVE_FUNC_ON_NEW_MSG}`, fetchChatList)
/** 第一次加载消息列表 */
fetchChatList()
}
export const fetchChatList = throttle(() => {
console.log('fetchChatList')
/** 获取im会话列表 */
store.dispatch(`${ns}/${ChatStore.ACTION_GET_MY_CHAT_LIST}`)
}, 1000 * 2)
import { config } from '@/config'
import axios from 'axios'
import qs from 'qs'
const baseAuthParams = {
client_id: config.clientId,
client_secret: config.clientSecret,
}
export interface TokenResponse {
access_token: string
}
function getAnonymousToken() {
return axios
.post<TokenResponse>(
`${config.passportUrl}/connect/token`,
qs.stringify({
...baseAuthParams,
grant_type: 'anonymous',
scope: 'api.workapps.open',
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
)
.then((r) => r.data.access_token)
}
export function getPassportTokenByPassport(username: string, password: string) {
return getAnonymousToken().then((token) => {
return axios
.post<TokenResponse>(
`${config.passportUrl}/connect/token`,
qs.stringify({
...baseAuthParams,
grant_type: 'password',
scope: 'openid workapps.client api.workapps.open api.workapps.user',
username,
password,
}),
{
headers: {
'content-type': 'application/x-www-form-urlencoded',
Authorization: 'Bearer ' + token,
},
}
)
.then((r) => r.data.access_token)
})
}
import { metaRow, SdkListRowPredict, SdkListRowPredictObject, UniplatSdk, UniplatSdkExtender } from 'uniplat-sdk'
import { config } from '@/config'
class Sdk {
private uniplatSdk!: UniplatSdk
private readonly handler = new UniplatSdkExtender()
private token!: string
public orgId!: string
constructor() {
// 从config获取目标服务器
const baseUrl = config.uniplatApi
// 生成uniplat实例
this.uniplatSdk = new UniplatSdk({ sse: false })
// 传入目标服务器以链接服务器
this.uniplatSdk.connect({
baseUrl: baseUrl,
axiosTimeout: 2e3,
})
}
public setup(token: string) {
this.token = 'Bearer ' + token
// 设置实例根入口程序
this.uniplatSdk.global.rootEntrance = config.rootEntrance
// 添加Token过期时的回调
this.uniplatSdk.events.addTokenExpiring(() => {
console.log('token过期了')
})
// 传入token登录业务平台
return this.uniplatSdk
.getPassportLogin()
.login(this.token)
.then(() => {
return this.uniplatSdk
.org()
.loadList({ name: '', itemIndex: 0, itemSize: 10 })
.then((org) => {
if (org.list.length) {
this.orgId = String(org.list[0].id)
this.uniplatSdk.setInitData({
orgId: org.list[0].id,
})
} else {
throw Error('no Org')
}
})
})
}
public get core() {
return this.uniplatSdk
}
public buildRows<T>(rows: metaRow[], predicts: SdkListRowPredict[] | SdkListRowPredictObject) {
return this.handler.buildRows<T>(rows, predicts)
}
public buildRow<T>(item: metaRow, predicts: SdkListRowPredict[] | SdkListRowPredictObject) {
return this.handler.buildRow<T>(item, predicts)
}
public buildActionParameter(parameter: { [key: string]: any }) {
return this.handler.buildActionParameter(parameter)
}
}
const sdk = new Sdk()
export { sdk }
import { VueConstructor } from 'vue'
import moment from 'moment'
const filters = function install(Vue: VueConstructor) {
function format(v: string) {
return v.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
// 将数字转换为千分位显示
Vue.filter('number', (v: number, fixed?: number, prefix?: string) => {
if (fixed) {
const s = format((+v).toFixed(fixed).toString())
if (prefix) {
return prefix + s
}
return s
}
return format((v || '').toString())
})
Vue.filter('currency', (v: number, fixed = 2, prefix = '¥') => {
if (fixed) {
const s = format((+v).toFixed(fixed).toString())
if (prefix) {
return prefix + s
}
return s
}
return format((v || '').toString())
})
const k = 1024
const m = 1024 * k
const g = 1024 * m
const t = 1024 * g
Vue.filter('formatSize', function formatSize(size: number) {
if (size === undefined || size === null) {
return ''
}
if (size < k) {
return size + ' B'
}
if (size < m) {
return Number((size / k).toFixed(2)) + ' KB'
}
if (size < g) {
return Number((size / m).toFixed(2)) + ' MB'
}
if (size < t) {
return Number((size / g).toFixed(2)) + ' GB'
}
return Number((size / t).toFixed(2)) + ' TB'
})
Vue.filter('time2YYYYMMDD', function (time: string | number, separator?: string) {
if (!time) {
return ''
}
if (separator) {
return moment(time).format(`YYYY${separator}MM${separator}DD`)
}
return moment(time).format('YYYY-MM-DD')
})
Vue.filter('time2YYYYMM', function (time: string | number, separator?: string) {
if (!time) {
return ''
}
if (separator) {
return moment(time).format(`YYYY${separator}MM`)
}
return moment(time).format('YYYY年MM月')
})
Vue.filter('time2String', function (time: string | number) {
if (!time) {
return ''
}
return moment(time).format('YYYY-MM-DD HH:mm:ss')
})
Vue.filter('time2MiniString', function (time: string | number) {
if (!time) {
return ''
}
return moment(time).format('YYYY-MM-DD HH:mm')
})
Vue.filter('time2YYYYMMDDCN', function (time: string | number) {
if (!time) {
return ''
}
return moment(time).format('YYYY年MM月DD日')
})
Vue.filter('beautifyTime', function (v?: string | number) {
if (!v) {
return ''
}
const time = moment(v)
if (!time.isValid()) {
return v
}
let str = time.format('YYYY-MM-DD')
const hour = time.hour()
const minute = time.minute()
if (!hour && !minute) {
return str
}
if (hour) {
str += ` ${time.format('Ah点')}`
}
if (minute) {
str += ` ${time.format('m分')}`
}
return str
})
const today = moment()
function isToday(time: moment.Moment) {
return time.year() === today.year() && time.month() === today.month() && time.date() === today.date()
}
function isThisYear(time: moment.Moment) {
return time.year() === today.year()
}
function isThisHour(time: moment.Moment) {
return time.hour() === today.hour()
}
function getSomeMinuteAgo(time: moment.Moment) {
return today.minute() - time.minute()
}
Vue.filter('time2Relative', function (time: string | number) {
if (!time) {
return ''
}
const v = moment(time)
if (isThisHour(v)) {
const n = getSomeMinuteAgo(v)
return n <= 2 ? '刚刚' : `${n}分钟前`
}
if (isToday(v)) {
return moment(time).format('HH:mm')
}
if (isThisYear(v)) {
return moment(time).format('MM-DD A HH:mm')
}
return moment(time).format('YYYY-MM-DD HH:mm')
})
Vue.filter('leftFixedZero', function (val: string | number, len?: number) {
len = len || 2
val = ('' + val).trim()
return (Array(len).join('0') + val).slice(-len)
})
function formatSalary(v: number, type?: 'Y' | 'K') {
if (type === 'K') {
return {
v: parseFloat((v / 1000).toFixed(2)),
unit: 'K',
}
}
if (+v < 1000) {
return {
v,
unit: '',
}
} else {
return {
v: parseFloat((v / 1000).toFixed(2)),
unit: 'K',
}
}
}
Vue.filter('salaryRange', function (min: number, max: number) {
if (!max && !min) {
return '面议'
}
if (+min >= +max) {
const v = formatSalary(min)
return `${v.v}${v.unit}`
}
const formatMin = formatSalary(min)
const formatMax = formatSalary(max)
if (formatMin.unit === formatMax.unit) {
return `${formatMin.v}-${formatMax.v} ${formatMax.unit}`
} else {
const formatMin = formatSalary(min, 'K')
const formatMax = formatSalary(max, 'K')
return `${formatMin.v}-${formatMax.v} K`
}
})
}
export { filters }
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator"
import HelloWorld from "@/components/HelloWorld.vue" // @ is an alias to /src
@Component({
components: {
HelloWorld,
},
})
export default class HomeView extends Vue {}
</script>
<template>
<div>
<div v-for="item in chatList" :key="item.id" @click="openChat(item)">
<div>{{ item.title }}</div>
<div>{{ (item.last_msg_ts * 1000) | time2Relative }}</div>
</div>
<el-drawer
:title="chatTitle || '加载中...'"
:visible.sync="dislogVisible"
@close="clearCurrentChatId"
:size="600"
>
<div class="chat" v-loading="!chatTitle">
<chat-room />
</div>
</el-drawer>
</div>
</template>
<script lang="ts">
import { Component } from "vue-property-decorator"
import { getPassportTokenByPassport } from "@/service/passport"
import { config } from "@/config"
import ChatList from "@/customer-service/components/controller/chat-list"
import { initChat } from "@/service/chat"
import { sdk } from "@/service/sdk"
import { Chat } from "@/customer-service/xim/models/chat"
import { ChatStore, chatStore } from "@/customer-service/store/model"
import ChatRoom from "@/customer-service/components/chat-room.vue"
@Component({
components: { ChatRoom },
})
export default class HomeView extends ChatList {
private dislogVisible = false
@chatStore.State(ChatStore.STATE_CURRENT_CHAT_TITLE)
private chatTitle!: ChatStore.STATE_CURRENT_CHAT_TITLE
mounted() {
this.init()
}
private openChat(item: Chat) {
this.dislogVisible = true
this.saveChatId(item.id)
}
private init() {
return getPassportTokenByPassport(config.testAccount, config.testPassword)
.then((token) => {
return sdk.setup(token)
})
.then(() => {
return initChat()
})
}
}
</script>
<style scoped lang="less">
.chat {
height: 100%;
/deep/.chat-room-con {
height: 100%;
.h-100 {
height: 100%;
}
.content-avatar {
margin-top: 10px;
}
.tm-avatar {
margin-left: 10px;
}
.cs-flex-direction {
justify-content: flex-end;
.tm-avatar {
margin-left: 0;
margin-right: 10px;
}
}
.msg-detail {
margin-top: 0;
}
.withdraw-message {
background-color: transparent;
padding: 0 4px;
font-size: 12px;
color: #999;
}
.el-scrollbar__wrap {
overflow-x: hidden;
}
.chat-area .chat-messages {
height: calc(100% - 180px + 1px);
}
.chat-room-con {
height: 100%;
}
}
}
</style>
...@@ -5,11 +5,11 @@ const pro = process.env.NODE_ENV === 'production' ...@@ -5,11 +5,11 @@ const pro = process.env.NODE_ENV === 'production'
module.exports = defineConfig({ module.exports = defineConfig({
transpileDependencies: true, transpileDependencies: true,
chainWebpack: (config) => { // chainWebpack: (config) => {
config.plugin('ignoreMoment').use(webpack.ContextReplacementPlugin, [/moment[/\\]locale$/, /zh-cn/]) // config.plugin('ignoreMoment').use(webpack.ContextReplacementPlugin, [/moment[/\\]locale$/, /zh-cn/])
config.plugin('lodash').use(webpack.ProvidePlugin, [{ _: 'lodash' }]) // config.plugin('lodash').use(webpack.ProvidePlugin, [{ _: 'lodash' }])
}, // },
configureWebpack: (config) => { configureWebpack: (config) => {
// 配置别名等放到这里 // 配置别名等放到这里
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment