| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- <template>
- <view class="acct-pwd-page">
- <view class="acct-pwd-nav" :style="{ paddingTop: statusBar + 'px' }">
- <view class="acct-pwd-nav-row">
- <view class="acct-pwd-back" @tap="goBack">
- <text class="acct-pwd-back-icon">←</text>
- </view>
- <text class="acct-pwd-nav-title">{{ copy.pageTitle }}</text>
- <view class="acct-pwd-nav-placeholder" />
- </view>
- </view>
- <scroll-view
- scroll-y
- class="acct-pwd-scroll"
- :style="{ height: scrollHeight + 'px' }"
- >
- <view class="acct-pwd-body" :style="{ paddingBottom: footerPad + 'px' }">
- <view class="acct-pwd-hero">
- <view class="acct-pwd-hero-icon-wrap">
- <text class="acct-pwd-hero-icon">🚩</text>
- </view>
- <text class="acct-pwd-hero-title">{{ copy.heroTitle }}</text>
- <text class="acct-pwd-hero-desc">{{ heroDesc }}</text>
- </view>
- <text class="cp-section">{{ copy.sectionReason }}</text>
- <view class="acct-pwd-card cp-picker-card">
- <picker
- mode="selector"
- :range="reasonLabels"
- :value="reasonIndex >= 0 ? reasonIndex : 0"
- :disabled="!reasonLabels.length"
- @change="onReasonPick"
- >
- <view class="cp-picker-row">
- <text
- class="cp-picker-value"
- :class="{ 'cp-picker-value--placeholder': reasonIndex < 0 }"
- >{{ reasonLabel }}</text>
- <text class="cp-picker-chevron">›</text>
- </view>
- </picker>
- </view>
- <text class="cp-section">{{ copy.sectionScreenshots }}</text>
- <view class="acct-pwd-card">
- <view class="cp-img-head">
- <text class="cp-img-head-label">{{ copy.previewImages }}</text>
- <text class="cp-img-head-count">{{ form.images.length }}/8</text>
- </view>
- <view class="cp-img-grid">
- <view
- v-for="(image, index) in form.images"
- :key="index"
- class="cp-img-cell"
- >
- <image
- class="cp-img-thumb"
- :src="thumb(image)"
- mode="aspectFill"
- @tap="previewImages(index)"
- />
- <view class="cp-img-remove" @tap.stop="removeImage(index)">
- <text class="cp-img-remove-icon">×</text>
- </view>
- </view>
- <view
- v-if="form.images.length < 8"
- class="cp-img-cell cp-img-cell--add"
- @tap="pickImages"
- >
- <text class="cp-img-add-icon">+</text>
- <text class="cp-img-add-txt">{{ copy.addImage }}</text>
- </view>
- </view>
- </view>
- <text class="cp-section">{{ copy.sectionDetails }}</text>
- <view class="acct-pwd-card">
- <textarea
- v-model="form.content"
- class="cp-textarea"
- maxlength="-1"
- :placeholder="copy.placeholder"
- placeholder-class="cp-textarea-placeholder"
- />
- </view>
- </view>
- </scroll-view>
- <view class="cp-footer" :style="{ paddingBottom: safeBottom + 'px' }">
- <button
- class="acct-pwd-submit"
- :disabled="submitting"
- :loading="submitting"
- :class="{ 'acct-pwd-submit--busy': submitting }"
- @tap="submit"
- >
- <text class="acct-pwd-submit__text">{{ submitting ? copy.submitting : copy.submit }}</text>
- </button>
- </view>
- </view>
- </template>
- <script>
- import {
- buildComplaintDraft,
- fetchComplaintReasons,
- submitComplaint,
- uploadComplaintImage
- } from '@/features/account/complaint-gateway'
- export default {
- data() {
- return {
- statusBar: 0,
- scrollHeight: 600,
- safeBottom: 0,
- footerPad: 120,
- submitting: false,
- uploading: false,
- typeName: '',
- targetId: 0,
- reasonIndex: -1,
- reasonOptions: [],
- form: {
- type: 0,
- complaint_user_id: 0,
- complaint_shop_id: 0,
- complaint_goods_id: 0,
- images: [],
- content: '',
- reason: -1
- }
- }
- },
- computed: {
- copy() {
- const t = this.$t.bind(this)
- return {
- pageTitle: t('user.panelReport'),
- heroTitle: t('complaint.heroTitle'),
- sectionReason: t('complaint.reason'),
- sectionScreenshots: t('complaint.screenshots'),
- sectionDetails: t('complaint.details'),
- previewImages: t('complaint.preview-images'),
- addImage: t('complaint.add-image'),
- placeholder: t('complaint.placeholder'),
- submit: t('complaint.submit'),
- submitting: t('complaint.submitting'),
- selectReason: t('complaint.select-reason'),
- reasonRequired: t('complaint.reason-required'),
- contentRequired: t('complaint.content-required'),
- submitOk: t('complaint.submit-ok'),
- network: t('user.realnameNetworkError')
- }
- },
- heroDesc() {
- if (this.targetId) {
- return this.$t('complaint.targetHint', {
- typeName: this.typeName,
- id: this.targetId
- })
- }
- return this.$t('complaint.generalHint')
- },
- reasonLabels() {
- return this.reasonOptions.map((item) => item.title)
- },
- reasonLabel() {
- if (this.reasonIndex < 0 || !this.reasonOptions[this.reasonIndex]) {
- return this.copy.selectReason
- }
- return this.reasonOptions[this.reasonIndex].title
- }
- },
- onLoad(option) {
- const sys = uni.getSystemInfoSync()
- this.statusBar = sys.statusBarHeight || 0
- this.safeBottom = sys.safeAreaInsets ? sys.safeAreaInsets.bottom : 0
- const navH = this.statusBar + uni.upx2px(88)
- this.scrollHeight = (sys.windowHeight || 667) - navH - uni.upx2px(120)
- this.footerPad = uni.upx2px(120) + this.safeBottom
- const built = buildComplaintDraft(option || {}, this.$t.bind(this))
- this.form = { ...built.draft }
- this.typeName = built.typeName
- this.targetId = built.targetId
- this.loadReasons()
- },
- methods: {
- goBack() {
- if (getCurrentPages().length > 1) {
- uni.navigateBack({ delta: 1 })
- } else {
- uni.switchTab({
- url: '/pages/mine/index',
- fail: () => uni.reLaunch({ url: '/pages/mine/index' })
- })
- }
- },
- thumb(url) {
- return this.$appKit && this.$appKit.oss ? this.$appKit.oss(url, 200, 200) : url
- },
- async loadReasons() {
- try {
- const list = await fetchComplaintReasons()
- if (list.length) {
- this.reasonOptions = list
- }
- } catch (_) {}
- },
- onReasonPick(e) {
- const idx = Number(e.detail.value)
- if (Number.isNaN(idx) || idx < 0) {
- this.reasonIndex = -1
- this.form.reason = -1
- return
- }
- this.reasonIndex = idx
- const row = this.reasonOptions[idx]
- this.form.reason = row ? row.code_num : idx
- },
- pickImages() {
- if (this.uploading) return
- const remain = 8 - this.form.images.length
- if (remain <= 0) return
- uni.chooseImage({
- sourceType: ['camera', 'album'],
- sizeType: ['compressed'],
- count: remain,
- success: (res) => {
- this.uploadChosen(res.tempFilePaths || [])
- }
- })
- },
- async uploadChosen(paths) {
- if (!paths.length) return
- this.uploading = true
- uni.showLoading({ mask: true, title: this.$t('complaint.uploading') })
- try {
- for (const path of paths) {
- const url = await uploadComplaintImage(path)
- if (url) this.form.images.push(url)
- }
- } catch (err) {
- this.$appKit.msg((err && err.message) || this.copy.network)
- } finally {
- this.uploading = false
- uni.hideLoading()
- }
- },
- removeImage(index) {
- this.form.images.splice(index, 1)
- },
- previewImages(index) {
- const urls = this.form.images.map((item) =>
- this.$appKit.oss ? this.$appKit.oss(item, 500) : item
- )
- uni.previewImage({
- urls,
- current: urls[index],
- indicator: 'number'
- })
- },
- async submit() {
- if (this.submitting) return
- if (this.form.reason === -1) {
- this.$appKit.msg(this.copy.reasonRequired)
- return
- }
- if (!String(this.form.content || '').trim()) {
- this.$appKit.msg(this.copy.contentRequired)
- return
- }
- this.submitting = true
- uni.showLoading({ mask: true })
- try {
- await submitComplaint({ ...this.form })
- this.$appKit.msg(this.copy.submitOk)
- setTimeout(() => {
- uni.navigateTo({
- url: '/pages/account/complaint-lists',
- fail: () => this.goBack()
- })
- }, 400)
- } catch (err) {
- this.$appKit.msg((err && err.message) || this.copy.network)
- } finally {
- this.submitting = false
- uni.hideLoading()
- }
- }
- }
- }
- </script>
- <style scoped>
- @import './account-flow.css';
- .cp-section {
- display: block;
- padding: 0 8rpx 16rpx;
- font-size: 26rpx;
- color: #8a8d9e;
- }
- .cp-picker-card {
- padding: 0 28rpx;
- }
- .cp-picker-row {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- min-height: 96rpx;
- }
- .cp-picker-value {
- flex: 1;
- font-size: 30rpx;
- color: #1a1d26;
- }
- .cp-picker-value--placeholder {
- color: #b8bcc8;
- }
- .cp-picker-chevron {
- font-size: 36rpx;
- color: #c5cad6;
- line-height: 1;
- }
- .cp-img-head {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 20rpx;
- }
- .cp-img-head-label {
- font-size: 28rpx;
- color: #1a1d26;
- font-weight: 500;
- }
- .cp-img-head-count {
- font-size: 24rpx;
- color: #8a8d9e;
- }
- .cp-img-grid {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- margin: -8rpx;
- }
- .cp-img-cell {
- position: relative;
- width: calc(25% - 16rpx);
- height: 152rpx;
- margin: 8rpx;
- border-radius: 16rpx;
- overflow: hidden;
- background-color: #f0f3f8;
- }
- .cp-img-cell--add {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- border: 2rpx dashed #d5dae6;
- background-color: #f7f9fc;
- }
- .cp-img-thumb {
- width: 100%;
- height: 100%;
- }
- .cp-img-remove {
- position: absolute;
- top: 0;
- right: 0;
- width: 40rpx;
- height: 40rpx;
- background: rgba(239, 68, 68, 0.92);
- display: flex;
- align-items: center;
- justify-content: center;
- border-bottom-left-radius: 12rpx;
- }
- .cp-img-remove-icon {
- color: #ffffff;
- font-size: 28rpx;
- line-height: 1;
- }
- .cp-img-add-icon {
- font-size: 44rpx;
- color: #4a8cff;
- line-height: 1;
- }
- .cp-img-add-txt {
- margin-top: 6rpx;
- font-size: 20rpx;
- color: #8a8d9e;
- }
- .cp-textarea {
- width: 100%;
- min-height: 220rpx;
- font-size: 28rpx;
- color: #1a1d26;
- line-height: 1.5;
- }
- .cp-textarea-placeholder {
- color: #b8bcc8;
- }
- .cp-footer {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 16rpx 28rpx 0;
- background: linear-gradient(180deg, rgba(244, 246, 251, 0) 0%, #f4f6fb 28%);
- box-sizing: border-box;
- }
- </style>
|