congming_huose-apk/pages/company/apply.vue

497 lines
12 KiB
Vue
Raw Normal View History

<template>
<view class="page">
<app-top-push-notice />
<view class="tabback">
<view class="rtjt" @click="back"></view>
<view class="name">{{ $i18n.t('companyApplyTitle') }}</view>
<view class="tabback-placeholder"></view>
</view>
<scroll-view scroll-y class="form-scroll" :show-scrollbar="false">
<view class="form">
<!-- logo -->
<view class="field">
<text class="label">{{ $i18n.t('companyFieldLogo') }}</text>
<view class="logo-box" @click="openSheet">
<image v-if="logo" class="logo-img" :src="logo" mode="aspectFill" />
<text v-else class="logo-placeholder">{{ $i18n.t('companyTapUploadLogo') }}</text>
</view>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldName') }}</text>
<input
class="input"
v-model="name"
:placeholder="$i18n.t('companyFieldNamePlaceholder')"
placeholder-style="color:#BFBFBF"
/>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldType') }}</text>
<picker mode="selector" :range="typeLabels" :value="typeIndex" @change="onTypeChange">
<view class="picker-val">{{ typeLabels[typeIndex] }}</view>
</picker>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldDescription') }}</text>
<textarea
class="textarea"
v-model="description"
:placeholder="$i18n.t('companyFieldDescriptionPlaceholder')"
placeholder-style="color:#BFBFBF"
auto-height
/>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldEmail') }}</text>
<input
class="input"
v-model="email"
type="text"
:placeholder="$i18n.t('companyFieldEmailPlaceholder')"
placeholder-style="color:#BFBFBF"
/>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldWebsite') }}</text>
<input
class="input"
v-model="website"
:placeholder="$i18n.t('companyFieldWebsitePlaceholder')"
placeholder-style="color:#BFBFBF"
/>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldPhoneCode') }}</text>
<picker mode="selector" :range="phoneCodeLabels" :value="phoneCodeIndex" @change="onPhoneCodeChange">
<view class="picker-val">{{ phoneCodeLabels[phoneCodeIndex] }}</view>
</picker>
</view>
<view class="field">
<text class="label">{{ $i18n.t('companyFieldPhone') }}</text>
<input
class="input"
v-model="phone"
type="number"
:placeholder="$i18n.t('companyFieldPhonePlaceholder')"
placeholder-style="color:#BFBFBF"
/>
</view>
</view>
</scroll-view>
<view class="submit-footer">
<view class="submit-btn" :class="{ disabled: submitting }" @click="submit">{{ $i18n.t('companyApplySubmit') }}</view>
</view>
<view class="action-sheet" v-if="showActionSheet" @click="hideActionSheet">
<view class="action-sheet-content" @click.stop>
<view class="action-sheet-item" @click="takePhoto">
<text class="action-sheet-text">{{ $i18n.t('takePhoto') }}</text>
</view>
<view class="action-sheet-item" @click="chooseFromAlbum">
<text class="action-sheet-text">{{ $i18n.t('chooseFromAlbum') }}</text>
</view>
<view class="action-sheet-cancel" @click="hideActionSheet">
<text class="action-sheet-text">{{ $i18n.t('actionSheetCancel') }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
const TYPE_OPTS = () => [
{ value: 1, labelKey: 'companyTypeSecurity' },
{ value: 2, labelKey: 'companyTypeInstall' }
]
const PHONE_CODES = () => [
{ code: '+86', regionKey: 'regionCN' },
{ code: '+852', regionKey: 'regionHK' },
{ code: '+853', regionKey: 'regionMO' },
{ code: '+886', regionKey: 'regionTW' },
{ code: '+81', regionKey: 'regionJP' },
{ code: '+82', regionKey: 'regionKorea' },
{ code: '+1', regionKey: 'regionUS' },
{ code: '+1', regionKey: 'regionCA' },
{ code: '+44', regionKey: 'regionGB' },
{ code: '+7', regionKey: 'regionRU' },
{ code: '+65', regionKey: 'regionSG' },
{ code: '+61', regionKey: 'regionAU' },
{ code: '+49', regionKey: 'regionDE' },
{ code: '+33', regionKey: 'regionFR' },
{ code: '+39', regionKey: 'regionIT' },
{ code: '+34', regionKey: 'regionES' }
]
export default {
data() {
return {
logo: '',
name: '',
description: '',
email: '',
website: '',
phone: '',
typeIndex: 0,
phoneCodeIndex: 0,
typeOptions: TYPE_OPTS(),
phoneCodes: PHONE_CODES(),
qiniuToken: '',
showActionSheet: false,
submitting: false
}
},
computed: {
typeLabels() {
const t = this.$i18n.t.bind(this.$i18n)
return this.typeOptions.map((o) => t(o.labelKey))
},
phoneCodeLabels() {
const t = this.$i18n.t.bind(this.$i18n)
const lang = this.$i18n.getCurrentLanguage && this.$i18n.getCurrentLanguage()
return this.phoneCodes.map((p) => {
let region = t(p.regionKey)
// 日语下韩国名称使用 Unicode避免 ja 语言包该行编码异常
if (p.regionKey === 'regionKorea' && lang === 'ja') {
region = '\u97d3\u56fd'
}
return `${p.code} ${region}`
})
}
},
onLoad() {
this.getQiniuToken()
},
methods: {
back() {
uni.navigateBack({ delta: 1 })
},
onTypeChange(e) {
const i = Number(e.detail.value)
if (!Number.isNaN(i)) this.typeIndex = i
},
onPhoneCodeChange(e) {
const i = Number(e.detail.value)
if (!Number.isNaN(i)) this.phoneCodeIndex = i
},
openSheet() {
this.showActionSheet = true
},
hideActionSheet() {
this.showActionSheet = false
},
generateGuid(length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length))
}
return result
},
getQiniuToken() {
this.$http.get('/common/qiniuToken').then((res) => {
if (res.code == 200) {
this.qiniuToken = res.data
}
})
},
uploadPath(tempPath) {
if (!this.qiniuToken) {
uni.showToast({ title: this.$i18n.t('uploadFailed'), icon: 'none' })
return
}
const math = 'static/' + this.generateGuid(20)
uni.uploadFile({
url: 'https://up-z2.qiniup.com',
name: 'file',
filePath: tempPath,
formData: {
token: this.qiniuToken,
key: 'smartmeter/img/' + math
},
success: (res) => {
try {
const str = JSON.parse(res.data)
this.logo = 'https://api.ccttiot.com/' + str.key
uni.showToast({ title: this.$i18n.t('imageSelectedSuccess'), icon: 'success' })
} catch (err) {
uni.showToast({ title: this.$i18n.t('uploadFailed'), icon: 'none' })
}
},
fail: () => {
uni.showToast({ title: this.$i18n.t('uploadFailed'), icon: 'none' })
}
})
},
takePhoto() {
this.hideActionSheet()
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: (imgRes) => {
this.uploadPath(imgRes.tempFilePaths[0])
},
fail: () => {
uni.showToast({ title: this.$i18n.t('imageOperationCancelled'), icon: 'none' })
}
})
},
chooseFromAlbum() {
this.hideActionSheet()
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album'],
success: (imgRes) => {
this.uploadPath(imgRes.tempFilePaths[0])
},
fail: () => {
uni.showToast({ title: this.$i18n.t('imageOperationCancelled'), icon: 'none' })
}
})
},
submit() {
if (this.submitting) return
const name = (this.name || '').trim()
if (!name) {
uni.showToast({ title: this.$i18n.t('companyPleaseName'), icon: 'none' })
return
}
if (!this.logo) {
uni.showToast({ title: this.$i18n.t('companyPleaseLogo'), icon: 'none' })
return
}
const email = (this.email || '').trim()
if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
uni.showToast({ title: this.$i18n.t('companyEmailInvalid'), icon: 'none' })
return
}
const type = this.typeOptions[this.typeIndex].value
const phoneCode = this.phoneCodes[this.phoneCodeIndex].code
const payload = {
logo: this.logo,
name,
type,
description: (this.description || '').trim(),
email,
website: (this.website || '').trim(),
phoneCode,
phone: (this.phone || '').trim()
}
this.submitting = true
this.$http
.post('/bst/company', payload)
.then((res) => {
if (res.code == 200) {
uni.showToast({
title: res.msg || this.$i18n.t('companyApplySuccess'),
icon: 'success'
})
setTimeout(() => {
uni.navigateBack({ delta: 1 })
}, 1500)
} else {
uni.showToast({ title: res.msg || this.$i18n.t('requestFailed'), icon: 'none' })
}
})
.catch(() => {
uni.showToast({ title: this.$i18n.t('requestFailed'), icon: 'none' })
})
.finally(() => {
this.submitting = false
})
}
}
}
</script>
<style scoped lang="scss">
.page {
min-height: 100vh;
background-color: #f3f5f6;
box-sizing: border-box;
}
.tabback {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 160rpx;
padding: 0 20rpx;
padding-top: 80rpx;
box-sizing: border-box;
position: fixed;
top: 0;
left: 0;
z-index: 999;
background-color: #fff;
.rtjt {
font-size: 36rpx;
color: #333;
min-width: 48rpx;
}
.name {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.tabback-placeholder {
width: 48rpx;
height: 1rpx;
}
}
.form-scroll {
height: calc(100vh - 160rpx);
margin-top: 160rpx;
box-sizing: border-box;
}
.form {
padding: 24rpx;
/* 为底部固定按钮留出可滚动空间(按钮区约 96+40+40rpx + 安全区) */
padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
}
.field {
margin-bottom: 28rpx;
}
.label {
display: block;
font-size: 26rpx;
color: #5c6370;
margin-bottom: 12rpx;
}
.logo-box {
width: 200rpx;
height: 200rpx;
border-radius: 16rpx;
background: #fff;
border: 2rpx dashed #d0d4dc;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.logo-img {
width: 100%;
height: 100%;
}
.logo-placeholder {
font-size: 24rpx;
color: #8b9199;
padding: 16rpx;
text-align: center;
}
.input {
background: #fff;
border-radius: 12rpx;
padding: 24rpx 28rpx;
font-size: 28rpx;
color: #1a1a1a;
}
.textarea {
background: #fff;
border-radius: 12rpx;
padding: 24rpx 28rpx;
font-size: 28rpx;
color: #1a1a1a;
min-height: 160rpx;
width: 100%;
box-sizing: border-box;
}
.picker-val {
background: #fff;
border-radius: 12rpx;
padding: 24rpx 28rpx;
font-size: 28rpx;
color: #1a1a1a;
}
.submit-footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 998;
padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
background-color: #fff;
box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.06);
box-sizing: border-box;
}
.submit-btn {
height: 96rpx;
line-height: 96rpx;
text-align: center;
background: #0f0f0f;
color: #fff;
font-size: 32rpx;
font-weight: 600;
border-radius: 48rpx;
}
.submit-btn.disabled {
opacity: 0.5;
}
.action-sheet {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
align-items: flex-end;
justify-content: center;
}
.action-sheet-content {
width: 100%;
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
padding-bottom: 40rpx;
}
.action-sheet-item {
padding: 30rpx 40rpx;
border-bottom: 1rpx solid #f0f0f0;
text-align: center;
}
.action-sheet-cancel {
padding: 30rpx 40rpx;
text-align: center;
margin-top: 20rpx;
background-color: #f8f8f8;
}
.action-sheet-text {
font-size: 32rpx;
color: #333;
}
</style>