You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
11 KiB

1 year ago
1 year ago
1 year ago
1 year ago
12 months ago
12 months ago
1 year ago
1 year ago
12 months ago
1 year ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
12 months ago
12 months ago
12 months ago
1 year ago
12 months ago
12 months ago
1 year ago
12 months ago
1 year ago
7 months ago
1 year ago
1 year ago
12 months ago
1 year ago
1 year ago
1 year ago
  1. <template>
  2. <div class="site-wrapper site-page--login">
  3. <div class="site-content__wrapper">
  4. <div class="site-content">
  5. <div class="login-main">
  6. <div class="login-language-wrapper">
  7. <el-select
  8. v-model="selectedLanguage"
  9. class="login-language-select"
  10. :placeholder="$t('login.selectLanguagePlaceholder')"
  11. @change="switchLoginLanguage">
  12. <el-option
  13. v-for="(item, index) in languageList"
  14. :key="'login-language-' + index"
  15. :label="item.languageName"
  16. :value="item.languageCode">
  17. </el-option>
  18. </el-select>
  19. </div>
  20. <h3 class="login-title">{{ $t('login.title') }}</h3>
  21. <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" status-icon>
  22. <el-form-item prop="userName">
  23. <el-input v-model="dataForm.userName" :placeholder="$t('login.accountPlaceholder')" @blur="handleUsernameBlur"></el-input>
  24. </el-form-item>
  25. <el-form-item prop="password">
  26. <el-input v-model="dataForm.password" type="password" :placeholder="$t('login.passwordPlaceholder')"></el-input>
  27. </el-form-item>
  28. <el-form-item >
  29. <el-select v-model="selectedSite" :placeholder="$t('login.selectSitePlaceholder')" style="width: 100%;">
  30. <el-option
  31. v-for="item in siteList"
  32. :key="item.siteCode"
  33. :label="item.siteName"
  34. :value="item.siteCode">
  35. </el-option>
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item>
  39. <el-button class="login-btn-submit" type="primary" @click="dataFormSubmit()">{{ $t('button.login') }}</el-button>
  40. </el-form-item>
  41. </el-form>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </template>
  47. <script>
  48. import { getUUID } from '@/utils'
  49. import {getConfigParams} from '@/api/sysConfig.js'
  50. import {getUserAuthorizedSites} from '@/api/factory/accessSite.js'
  51. import {searchSysLanguage} from '@/api/sysLanguage.js'
  52. export default {
  53. data () {
  54. return {
  55. src: 'http://192.168.1.83/upload/ifs.png',
  56. dataForm: {
  57. userName: '',
  58. password: '',
  59. uuid: '',
  60. captcha: ''
  61. },
  62. siteList: [],
  63. selectedSite: '',
  64. selectedLanguage: 'cn',
  65. languageList: [],
  66. captchaPath: ''
  67. }
  68. },
  69. computed: {
  70. dataRule() {
  71. return {
  72. userName: [
  73. { required: true, message: this.$t('login.accountRequired'), trigger: 'blur' }
  74. ],
  75. password: [
  76. { required: true, message: this.$t('login.passwordRequired'), trigger: 'blur' }
  77. ]
  78. }
  79. },
  80. multiLanguage: {
  81. get() {
  82. return this.$store.state.user.multiLanguage
  83. },
  84. set(val) {
  85. this.$store.commit('user/updateMultiLanguage', val)
  86. }
  87. },
  88. authControl: {
  89. get() {
  90. return this.$store.state.user.authControl
  91. },
  92. set(val) {
  93. this.$store.commit('user/updateAuthControl', val)
  94. }
  95. }
  96. },
  97. created () {
  98. this.initLoginLanguage()
  99. this.getLanguageList()
  100. this.userName();
  101. },
  102. methods: {
  103. normalizeLanguageCode(languageCode) {
  104. const locale = (languageCode || '').toLowerCase()
  105. return (locale === 'en' || locale === 'en-us') ? 'en' : 'cn'
  106. },
  107. // 登录页默认中文,但保留用户上一次选择的语言
  108. initLoginLanguage() {
  109. const locale = this.normalizeLanguageCode(localStorage.getItem('locale') || 'cn')
  110. this.applyLoginLanguage(locale)
  111. },
  112. // 登录页多语言下拉兜底选项,避免接口异常时无法切换
  113. buildFallbackLanguageList() {
  114. return [
  115. { languageCode: 'cn', languageName: this.$t('login.languageOptionCn') },
  116. { languageCode: 'en', languageName: this.$t('login.languageOptionEn') }
  117. ]
  118. },
  119. // 获取多语言列表,接口异常时保留默认中英文选项
  120. getLanguageList() {
  121. this.languageList = this.buildFallbackLanguageList()
  122. searchSysLanguage({ languageCode: this.$i18n.locale }).then(({data}) => {
  123. const rows = (data && data.rows) ? data.rows : []
  124. if (rows.length > 0) {
  125. this.languageList = rows
  126. if (!this.languageList.find(item => this.normalizeLanguageCode(item.languageCode) === this.selectedLanguage)) {
  127. this.selectedLanguage = this.languageList[0].languageCode
  128. }
  129. this.selectedLanguage = this.normalizeLanguageCode(this.selectedLanguage)
  130. }
  131. }).catch(() => {
  132. })
  133. },
  134. // 统一处理登录页语言生效,保证请求头与页面语言一致
  135. applyLoginLanguage(languageCode) {
  136. const locale = this.normalizeLanguageCode(languageCode)
  137. this.selectedLanguage = locale
  138. this.$i18n.locale = locale
  139. localStorage.setItem('locale', locale)
  140. },
  141. switchLoginLanguage(languageCode) {
  142. this.applyLoginLanguage(languageCode)
  143. this.getLanguageList()
  144. },
  145. // 获取上次登陆的用户名
  146. userName(){
  147. this.dataForm.userName = localStorage.getItem('userName')
  148. this.handleUsernameBlur()
  149. this.dataForm.selectedSite = localStorage.getItem('site')
  150. },
  151. // 用户名失焦时获取工厂列表
  152. handleUsernameBlur() {
  153. if (this.dataForm.userName && this.dataForm.userName.trim()) {
  154. this.getUserSiteList(this.dataForm.userName);
  155. } else {
  156. this.siteList = [];
  157. this.selectedSite = '';
  158. }
  159. },
  160. // 根据用户名获取授权的工厂列表
  161. getUserSiteList(userName) {
  162. if (!userName || !userName.trim()) {
  163. this.siteList = [];
  164. this.selectedSite = '';
  165. return;
  166. }
  167. getUserAuthorizedSites({ userName: userName.trim() }).then(({data}) => {
  168. if (data && data.code === 0) {
  169. this.siteList = data.data || data.list || [];
  170. // 清空之前选择的工厂
  171. this.selectedSite = '';
  172. // 如果只有一个工厂,自动选中
  173. if (this.siteList.length === 1) {
  174. this.selectedSite = this.siteList[0].siteCode;
  175. }
  176. } else {
  177. this.siteList = [];
  178. this.selectedSite = '';
  179. this.$message.error(data.msg || this.$t('login.getSiteListFailed'));
  180. }
  181. }).catch(error => {
  182. this.siteList = [];
  183. this.selectedSite = '';
  184. console.error('获取工厂列表失败:', error);
  185. this.$message.error(this.$t('login.getSiteListFailed'));
  186. })
  187. },
  188. // 提交表单
  189. dataFormSubmit () {
  190. // 如果有工厂列表但未选择工厂,提示用户
  191. if (this.siteList.length > 0 && !this.selectedSite) {
  192. this.$message.error(this.$t('login.siteRequired'));
  193. return;
  194. }
  195. this.$refs['dataForm'].validate((valid) => {
  196. if (valid) {
  197. this.$http({
  198. url: this.$http.adornUrl('/sys/login'),
  199. method: 'post',
  200. data: this.$http.adornData({
  201. 'username': this.dataForm.userName,
  202. 'password': this.dataForm.password,
  203. 'uuid': this.dataForm.uuid,
  204. 'site': this.selectedSite
  205. })
  206. }).then(({data}) => {
  207. if (data && data.code === 0) {
  208. // 设置Cookie过期时间为8小时,与后端token同步 - rqrq
  209. this.$cookie.set('token_wms', data.token, { expires: '8h' })
  210. this.$router.replace({ name: 'home' })
  211. const loginLanguage = this.normalizeLanguageCode(this.selectedLanguage || data.language || 'cn')
  212. this.applyLoginLanguage(loginLanguage)
  213. localStorage.setItem('refresh', "0")
  214. localStorage.setItem('userName', this.dataForm.userName)
  215. localStorage.setItem('site', this.selectedSite) // 保存选择的工厂
  216. this.getConfigParams()
  217. } else {
  218. this.$message.error(data.msg)
  219. }
  220. })
  221. }
  222. })
  223. },
  224. // 获取全局参数变量
  225. getConfigParams() {
  226. getConfigParams().then(({data}) => {
  227. if (data && data.code == 0) {
  228. localStorage.setItem('configParams', JSON.stringify(data.data))
  229. // this.multiLanguage = JSON.parse(localStorage.getItem('configParams')).multiLanguage
  230. // this.authControl = JSON.parse(localStorage.getItem('configParams')).authControl
  231. }
  232. })
  233. }
  234. }
  235. }
  236. </script>
  237. <style lang="scss" scoped>
  238. .site-wrapper.site-page--login {
  239. position: absolute;
  240. top: 0;
  241. right: 0;
  242. bottom: 0;
  243. left: 0;
  244. background-color: rgba(38, 50, 56, 0);
  245. overflow: hidden;
  246. &:before {
  247. position: fixed;
  248. top: 0;
  249. left: 0;
  250. z-index: -1;
  251. width: 80%;
  252. height: 100%;
  253. content: "";
  254. background-image: url(~@/assets/img/login_bg.jpg);
  255. background-size: cover;
  256. }
  257. .site-content__wrapper {
  258. position: absolute;
  259. top: 0;
  260. right: 0;
  261. bottom: 0;
  262. left: 0;
  263. padding: 0;
  264. margin: 0;
  265. overflow-x: hidden;
  266. overflow-y: auto;
  267. background-color: transparent;
  268. }
  269. .site-content {
  270. min-height: 100%;
  271. padding: 15% 500px 30px 30px;
  272. }
  273. .brand-info {
  274. margin: 220px 100px 0 90px;
  275. color: #fff;
  276. }
  277. .brand-info__text {
  278. margin: 0 0 22px 0;
  279. font-size: 48px;
  280. font-weight: 400;
  281. text-transform : uppercase;
  282. }
  283. .brand-info__intro {
  284. margin: 10px 0;
  285. font-size: 16px;
  286. line-height: 1.58;
  287. opacity: .6;
  288. }
  289. .login-main {
  290. position: absolute;
  291. top: 0;
  292. right: 0;
  293. padding: 15% 60px 180px;
  294. width: 350px;
  295. min-height: 100%;
  296. background-color: #fff;
  297. box-sizing: border-box;
  298. }
  299. .login-title {
  300. font-size: 30px;
  301. margin: 0 0 18px 0;
  302. text-align: center;
  303. }
  304. .login-language-wrapper {
  305. position: absolute;
  306. top: 24px;
  307. right: 24px;
  308. z-index: 2;
  309. }
  310. .login-language-select {
  311. width: 140px;
  312. .el-input__inner {
  313. margin-top: 0 !important;
  314. height: 32px;
  315. line-height: 32px;
  316. }
  317. }
  318. .login-captcha {
  319. overflow: hidden;
  320. > img {
  321. width: 100%;
  322. cursor: pointer;
  323. }
  324. }
  325. .login-btn-submit {
  326. width: 100%;
  327. }
  328. .login-main .el-input__inner{
  329. margin-top: 10px;
  330. height: 45px;
  331. }
  332. .el-button--medium {
  333. margin-top: 0px;
  334. padding: 5px 11px;
  335. font-size: 16px;
  336. border-radius: 4px;
  337. }
  338. .el-form-item {
  339. margin-bottom: 5px;
  340. }
  341. }
  342. </style>