shish 3 дней назад
Родитель
Сommit
cdd7c56d1d

+ 12 - 5
ghsApp/src/admin/billing/forwardResult.vue

@@ -7,7 +7,7 @@
 <template>
   <view class="forward-result-page">
     <!-- fundType=2:展示凭证海报 -->
-    <appResult v-if="Number(fundType) === 2" title="冲销成功">
+    <appResult v-if="Number(fundType) === 2" :title="Number(orderId) === 0 ? '退款成功' : '冲销成功'">
       <view v-if="posterLoading" class="status-text">凭证生成中...</view>
       <view v-else-if="posterFail" class="fail-box">
         <text class="status-text fail-text">凭证生成失败,请重试</text>
@@ -90,17 +90,24 @@ export default {
     /** 非返余额时的页面标题 */
     pageTitle() {
       const t = Number(this.fundType)
+      // 无原单退款(orderId=0)用「退款」文案
+      const free = Number(this.orderId) === 0
       if (t === 1) return '原路退回成功'
-      if (t === 3) return '冲销成功'
-      return '冲销成功'
+      if (t === 3) return free ? '退款成功' : '冲销成功'
+      return free ? '退款成功' : '冲销成功'
     },
     /** 非返余额时的说明文案 */
     simpleSuccessText() {
       const t = Number(this.fundType)
       const amt = this.formatMoney(this.amount)
+      const free = Number(this.orderId) === 0
       if (t === 1) return `已原路退回 ¥${amt}`
-      if (t === 3) return `冲销 ¥${amt},仅记账(资金未变动)`
-      return `冲销成功,金额 ¥${amt}`
+      if (t === 3) {
+        return free
+          ? `退款 ¥${amt},仅记账(资金未变动)`
+          : `冲销 ¥${amt},仅记账(资金未变动)`
+      }
+      return free ? `退款成功,金额 ¥${amt}` : `冲销成功,金额 ¥${amt}`
     }
   },
   onLoad(option) {

+ 370 - 0
ghsApp/src/admin/billing/freeRefund.vue

@@ -0,0 +1,370 @@
+<!--
+  无原单退款 · 选花材页
+  用途:工作台「退款」选客户后选花材(含单价/数量),不改动开单 index2 / product2;不走多颜色专用页。
+  谁用:selectCustom?refund=1 → 本页 → freeRefundConfirm。
+-->
+<template>
+	<view class="app-content">
+		<view class="billing_box_bg">
+			<view class="input-wrap">
+				<view class="header-action-wrap header-action-wrap--left">
+					<button class="admin-button-com blue header-action-btn" @click="selectFlowerNumFn()">图片分类</button>
+				</view>
+				<view class="search-bar">
+					<app-search-module ref="globalSearchRef" v-model="globalPy" placeholder="这里搜索" @input="globalSearch" />
+				</view>
+				<view class="header-action-wrap header-action-wrap--right">
+					<button class="admin-button-com blue header-action-btn header-action-btn--clear" @click="removeFromSave(0)">清除花材</button>
+				</view>
+			</view>
+
+			<button class="admin-button-com middle blue next-btn" @click="confirmToSave">选好了</button>
+
+			<view class="scroll-middle_bx">
+				<scroll-view scroll-y scroll-with-animation class="tab-view">
+					<div
+						v-for="(item, index) in globalClassData"
+						:key="index"
+						class="tab-bar-item"
+						:class="globalClassIndex == index ? 'active' : ''"
+						:data-current="index"
+						@tap.stop="globalSwitchClass(index, item)"
+					>
+						<text style="text-align: center;">{{ item.name || '' }}</text>
+					</div>
+					<view style="height: 120upx"></view>
+				</scroll-view>
+				<scroll-view
+					scroll-y
+					class="right-box"
+					:scroll-top="globalScrollTopPlace"
+					@scroll="globalGetScroll"
+					:scroll-into-view="scroll_into_view"
+					scroll-with-animation="true"
+					lower-threshold="100"
+					@scrolltolower="globalScrollBottom"
+				>
+					<block v-if="!$util.isEmpty(globalItemData)">
+						<view class="item_list_bx selectAll">
+							<template v-for="(productItem, productIndex) in globalItemData">
+								<view class="item_list_title" v-if="productItem.className && productItem.className!=''">{{ productItem.className }}</view>
+								<view class="item-row item-row--h175" :class="{ 'item-row--remark': productItem.itemRemark }" :key="productIndex">
+									<!-- 不传 selectJobType=bill,避免多颜色进开单专用页 -->
+									<Commondity
+										:globalCheckStock="false"
+										:selectJobType="selectJobType"
+										:info="productItem"
+										@showAddModelFn="showAddModelFn"
+										@replaceItemFn="replaceItemFn"
+									></Commondity>
+								</view>
+							</template>
+						</view>
+						<view style="height: 200upx;"></view>
+					</block>
+					<block v-else>
+						<app-wrapper-empty title="加载中" :is-empty="$util.isEmpty(globalItemData)" />
+					</block>
+				</scroll-view>
+			</view>
+
+			<!-- 退款选花:本页自管单价/数量弹框,不改 product2 -->
+			<modal-module :show="isAddModel" @cancel="addItemModelHidden" @click="confirmAddItemModel" :title="customData.name" color="#333" :size="32" padding="30rpx 30rpx">
+				<template slot="customContent">
+					<view class="select-cmd_bx" v-if="customData">
+						<view class="kc">
+							<text>库存 {{ customData.stock ? parseFloat(customData.stock) : 0 }}</text>
+							<text style="margin-left:14upx;">¥{{ parseFloat(customData.price || 0) }}</text>
+							<text style="margin-left:14upx;">{{ customData.ratio }}{{ customData.smallUnit }}/{{ customData.bigUnit }}</text>
+						</view>
+						<view class="num_bx">
+							<input
+								style="width:280upx"
+								v-model="customData.userPrice"
+								@focus="customData.userPrice = null"
+								type="digit"
+								placeholder="退款单价"
+							/>
+							<text style="font-size:35upx;font-weight:bold;color:#666666;">元</text>
+						</view>
+						<view class="num_bx">
+							<!-- #ifdef APP-PLUS -->
+							<input style="width: 280upx" v-model="customData.bigCount" v-if="globalUnitType == 0" type="number" />
+							<text style="font-size:35upx;font-weight:bold;color:#666666;" v-if="globalUnitType == 0">{{ customData.bigUnit }}</text>
+							<input style="width: 280upx" v-model="customData.smallCount" v-if="globalUnitType == 1" type="number" />
+							<text style="font-size:35upx;font-weight:bold;color:#666666;" v-if="globalUnitType == 1">{{ customData.smallUnit }}</text>
+							<!-- #endif -->
+							<!-- #ifdef MP-WEIXIN -->
+							<input style="width: 280upx" v-model="customData.bigCount" v-if="globalUnitType == 0" :focus="isAddInputFocus" type="number" />
+							<text style="font-size:35upx;font-weight:bold;color:#666666;" v-if="globalUnitType == 0">{{ customData.bigUnit }}</text>
+							<input style="width: 280upx" v-model="customData.smallCount" v-if="globalUnitType == 1" :focus="isAddInputFocus" type="number" />
+							<text style="font-size:35upx;font-weight:bold;color:#666666;" v-if="globalUnitType == 1">{{ customData.smallUnit }}</text>
+							<!-- #endif -->
+							<image
+								@click="switchGlobalUnitType"
+								:src="`${constant.imgUrl}/icon/switch/switch128.png`"
+								style="width:86upx;height:86upx;"
+								mode="widthFix"
+							></image>
+						</view>
+					</view>
+				</template>
+			</modal-module>
+
+			<footer-cart :price="allPrice" :count="allCount" @confirm="confirmToSave"></footer-cart>
+
+			<uni-popup ref="globalClassImgRef" background-color="#fff" type="center" :animation="false" class="class-popup-style">
+				<view class="class-img-wrap">
+					<view v-for="(item, index) in globalClassData" :key="index" @tap.stop="globalChangeClass(index, item)" class="class-img-item">
+						<image :src="item.cover" class="class-cover"></image>
+						<view class="class-name">{{ item.name }}</view>
+					</view>
+				</view>
+			</uni-popup>
+		</view>
+	</view>
+</template>
+
+<script>
+import AppSearchModule from '@/components/module/app-search'
+import AppWrapperEmpty from '@/components/app-wrapper-empty'
+import Commondity from '@/components/module/app-commodity'
+import FooterCart from '@/components/module/app-footer-cart'
+import ModalModule from '@/components/plugin/modal'
+import productMins from '@/mixins/product2'
+import { copyObject } from '@/utils/util'
+
+export default {
+	name: 'freeRefund',
+	components: {
+		AppSearchModule,
+		AppWrapperEmpty,
+		Commondity,
+		ModalModule,
+		FooterCart
+	},
+	mixins: [productMins],
+	data() {
+		return {
+			// 独立购物车键,与开单 bill 隔离
+			selectJobType: 'freeRefund',
+			autoLoad: false,
+			globalCheckStock: false
+		}
+	},
+	onLoad() {
+		const name = this.option && this.option.customName ? this.option.customName : ''
+		uni.setNavigationBarTitle({ title: name ? (name + ' · 退款选花材') : '退款选花材' })
+		if (this.option && this.option.customId) {
+			this.selectJobId = this.option.customId
+			this.globalCustomId = this.option.customId
+		}
+		// 可选无库存花材(退货回库)
+		this.globalCheckStock = false
+		this.globalRequestType = 'book'
+		this.initData()
+	},
+	methods: {
+		selectFlowerNumFn() {
+			this.$refs.globalClassImgRef.open('top')
+		},
+		switchGlobalUnitType() {
+			if (this.globalUnitType == 0) {
+				this.globalUnitType = 1
+				this.customData.bigCount = null
+			} else {
+				this.globalUnitType = 0
+				this.customData.smallCount = null
+			}
+		},
+		/**
+		 * 打开加购弹框:默认带单价;不校验库存;不进多颜色流程
+		 */
+		showAddModelFn(info) {
+			if (Number(info.smallCount) > 0) {
+				this.globalUnitType = 1
+			} else {
+				this.globalUnitType = 0
+			}
+			this.isAddModel = true
+			this.customData = copyObject(info)
+			this.isAddInputFocus = false
+			this.$nextTick(() => {
+				this.customData.smallCount = this.customData.smallCount == 0 ? null : this.customData.smallCount
+				this.customData.bigCount = this.customData.bigCount == 0 ? null : this.customData.bigCount
+				if (this.customData.userPrice == null || this.customData.userPrice == 0) {
+					this.customData.userPrice = parseFloat(this.customData.bigPrice || this.customData.price || 0)
+				}
+				this.isAddInputFocus = true
+			})
+		},
+		/**
+		 * 确认加购:本页校验数量+单价(不依赖 product2 的 bill 分支)
+		 */
+		confirmAddItemModel(val) {
+			if (val.index === 0) {
+				this.addItemModelHidden()
+				return false
+			}
+			const bigOk = /(^[1-9]\d*$)/.test(this.customData.bigCount)
+			const smallOk = /(^[1-9]\d*$)/.test(this.customData.smallCount)
+			if (!bigOk && !smallOk) {
+				uni.showToast({ title: '请填写数量', icon: 'none' })
+				return
+			}
+			if (bigOk && Number(this.customData.bigCount) <= 0) {
+				uni.showToast({ title: '数量要大于0', icon: 'none' })
+				return
+			}
+			if (smallOk && Number(this.customData.smallCount) <= 0) {
+				uni.showToast({ title: '数量要大于0', icon: 'none' })
+				return
+			}
+			const priceReg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/
+			if (!priceReg.test(this.customData.userPrice)) {
+				uni.showToast({ title: '金额错误', icon: 'none' })
+				return
+			}
+			if (Number(this.customData.userPrice) <= 0) {
+				uni.showToast({ title: '金额要大于0', icon: 'none' })
+				return
+			}
+			this.replaceItemFn(this.customData, 1)
+			this.addItemModelHidden()
+		},
+		confirmToSave() {
+			if (this.$util.isEmpty(this.selectList)) {
+				this.$msg('请选择花材')
+				return false
+			}
+			if (this.$util.isEmpty(this.option.customId)) {
+				this.$msg('请选择客户')
+				return
+			}
+			const customName = this.option.customName ? this.option.customName : ''
+			this.$util.pageTo({
+				url: '/admin/billing/freeRefundConfirm',
+				type: 2,
+				query: {
+					customId: this.option.customId,
+					customName: customName,
+					refund: 1
+				}
+			})
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/static/css/item-list-row.scss';
+
+.billing_box_bg {
+	background: white;
+	height: 100%;
+	display: flex;
+	flex-direction: column;
+	.input-wrap {
+		display: flex;
+		padding: 22upx 20upx 22upx 13upx;
+		align-items: center;
+		.search-bar {
+			flex: 1;
+		}
+	}
+	.header-action-wrap {
+		flex-shrink: 0;
+	}
+	.header-action-wrap--left {
+		margin-right: 10upx;
+	}
+	.header-action-wrap--right {
+		margin-left: 10upx;
+	}
+	.next-btn {
+		position: absolute;
+		top: 140upx;
+		right: 24upx;
+		z-index: 99;
+	}
+	.scroll-middle_bx {
+		flex: 1;
+		display: flex;
+		width: 100%;
+		height: 100%;
+		overflow: hidden;
+	}
+	.tab-view {
+		position: relative;
+		height: calc(100vh - 140upx);
+		width: 170upx;
+		flex-shrink: 0;
+		background-color: #f0f2f6;
+		.tab-bar-item {
+			width: 170upx;
+			height: 90upx;
+			box-sizing: border-box;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-size: 26upx;
+			color: #444;
+			&:last-child {
+				margin-bottom: 110upx;
+			}
+		}
+		.active {
+			color: $mainColor;
+			background: #fff;
+			font-weight: bold;
+		}
+	}
+	.right-box {
+		flex: 1;
+		height: calc(100vh - 140upx);
+	}
+}
+.select-cmd_bx {
+	.kc {
+		font-size: 24upx;
+		color: #666;
+		margin-bottom: 20upx;
+	}
+	.num_bx {
+		display: flex;
+		align-items: center;
+		margin-top: 20upx;
+		input {
+			border: 1upx solid #ccc;
+			height: 70upx;
+			padding: 0 16upx;
+			margin-right: 12upx;
+		}
+	}
+}
+.class-img-wrap {
+	display: flex;
+	padding: 20upx;
+	justify-content: space-between;
+	align-items: center;
+	flex-wrap: wrap;
+	max-height: 100vh;
+	overflow: auto;
+}
+.class-img-item {
+	margin-bottom: 20upx;
+	margin-left: 3upx;
+}
+.class-cover {
+	width: 120upx;
+	height: 120upx;
+	border-radius: 10upx;
+}
+.class-name {
+	margin-top: 5upx;
+	overflow: hidden;
+	white-space: nowrap;
+	width: 120upx;
+	text-align: center;
+}
+</style>

+ 360 - 0
ghsApp/src/admin/billing/freeRefundConfirm.vue

@@ -0,0 +1,360 @@
+<!--
+  无原单退款确认页
+  用途:工作台「退款」选客户、选花材后,确认金额/资金方式并提交;生成无关联销售单的售后单(sameDay=0)。
+  谁用:admin/billing/freeRefund → 本页 → forwardResult 或成功提示。
+-->
+<template>
+  <view class="app-content">
+    <view class="affirm-page">
+      <view class="affirm-view overscroll">
+        <view class="module-com">
+          <view class="commodity-view">
+            <view class="commodity-list">
+              <template v-if="!$util.isEmpty(selectList)">
+                <view class="commodity-item" v-for="(item, index) in selectList" :key="index">
+                  <image class="item-icon" :src="item.cover" />
+                  <view class="item-info">
+                    <view class="info-line">
+                      <text class="item-name">{{ item.name || '' }}</text>
+                      <text class="item-price">
+                        <text class="price">¥{{ getUnitPrice(item) }}</text>
+                      </text>
+                    </view>
+                    <view class="info-line">
+                      <text class="item-type">
+                        <text v-if="item.bigCount > 0">{{ item.bigCount }}{{ item.bigUnit }}</text>
+                        <text v-if="item.smallCount > 0">{{ item.smallCount }}{{ item.smallUnit }}</text>
+                      </text>
+                      <text class="item-count">小计 ¥{{ getLineAmount(item) }}</text>
+                    </view>
+                  </view>
+                </view>
+              </template>
+            </view>
+            <view class="summary-bar">
+              <view class="operate-view" @click="gobackEvent">
+                <text class="iconfont icongouwuche"></text>
+                返回修改
+              </view>
+              <view class="describe-view">共{{ selectList.length }}种 · ¥{{ allPrice }}</view>
+            </view>
+          </view>
+        </view>
+
+        <view class="module-com input-line-wrap">
+          <tui-list-cell class="line-cell" :hover="false" :arrow="false">
+            <view class="tui-title">客户</view>
+            <text class="cell-value">{{ form.customName || '-' }}</text>
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" :arrow="false">
+            <view class="tui-title">退款金额</view>
+            <input type="digit" v-model="form.price" placeholder="必填" />
+          </tui-list-cell>
+          <tui-list-cell class="line-cell" :hover="false" :arrow="false">
+            <view class="tui-title">备注</view>
+            <input type="text" v-model="form.remark" placeholder="选填" />
+          </tui-list-cell>
+        </view>
+
+        <view class="tip-box">
+          此退款不关联销售单:退货将回库;资金可选返充客户余额或仅记账。
+        </view>
+      </view>
+
+      <view class="under-bar">
+        <view class="price-view">¥{{ form.price || '0' }}</view>
+        <button class="admin-button-com blue big" style="width:220upx;" @click="onSubmitTap">确认退款</button>
+      </view>
+    </view>
+
+    <!-- 无原单:不可原路退,只选返余额/仅记账 -->
+    <forward-options-popup
+      :show="showFundPop"
+      :allow-original="false"
+      :force-balance="false"
+      mode="free"
+      @cancel="showFundPop = false"
+      @confirm="onFundConfirm"
+    />
+  </view>
+</template>
+
+<script>
+import TuiListCell from '@/components/plugin/list-cell'
+import productMins from '@/mixins/product2'
+import ForwardOptionsPopup from '@/components/forward-options-popup'
+import { createFreeRefund } from '@/api/refund'
+
+export default {
+  name: 'freeRefundConfirm',
+  components: { TuiListCell, ForwardOptionsPopup },
+  mixins: [productMins],
+  data() {
+    return {
+      autoLoad: false,
+      selectJobType: 'freeRefund',
+      showFundPop: false,
+      form: {
+        customId: '',
+        customName: '',
+        price: '',
+        remark: '',
+        fundType: 2
+      }
+    }
+  },
+  onLoad(option) {
+    this.selectJobType = 'freeRefund'
+    if (option.customId) {
+      this.form.customId = option.customId
+      this.selectJobId = option.customId
+    }
+    if (option.customName) {
+      this.form.customName = decodeURIComponent(option.customName)
+      uni.setNavigationBarTitle({ title: '退款确认 · ' + this.form.customName })
+    } else {
+      uni.setNavigationBarTitle({ title: '退款确认' })
+    }
+    // 默认退款金额=已选花材合计
+    this.$nextTick(() => {
+      this.form.price = this.allPrice > 0 ? String(this.allPrice) : ''
+    })
+  },
+  methods: {
+    /** 行单价展示 */
+    getUnitPrice(item) {
+      if (item.userPrice > 0) return parseFloat(item.userPrice).toFixed(2)
+      return parseFloat(item.bigPrice || item.price || 0).toFixed(2)
+    },
+    /** 行小计 */
+    getLineAmount(item) {
+      const unit = Number(this.getUnitPrice(item))
+      const big = Number(item.bigCount) || 0
+      const small = Number(item.smallCount) || 0
+      return ((big + small) * unit).toFixed(2)
+    },
+    gobackEvent() {
+      uni.navigateBack({})
+    },
+    /** 先弹资金选项再提交 */
+    onSubmitTap() {
+      if (this.$util.isEmpty(this.selectList)) {
+        this.$msg('请选择花材')
+        return
+      }
+      if (this.$util.isEmpty(this.form.customId)) {
+        this.$msg('请选择客户')
+        return
+      }
+      const price = Number(this.form.price)
+      if (!(price > 0)) {
+        this.$msg('请填写退款金额')
+        return
+      }
+      this.showFundPop = true
+    },
+    /**
+     * 资金确认后提交无原单退款
+     * @param {{fundType:number}} opt
+     */
+    onFundConfirm(opt) {
+      this.showFundPop = false
+      this.form.fundType = opt.fundType
+      this.submitFreeRefund()
+    },
+    /** 组装花材明细并调 create-free-refund */
+    submitFreeRefund() {
+      const that = this
+      const product = []
+      this.selectList.forEach((ele) => {
+        const unitPrice = ele.userPrice > 0 ? ele.userPrice : (ele.bigPrice || ele.price || 0)
+        if (Number(ele.bigCount) > 0) {
+          product.push({
+            productId: ele.id,
+            num: ele.bigCount,
+            unitType: 0,
+            unitName: ele.bigUnit || '扎',
+            unitPrice: unitPrice
+          })
+        }
+        if (Number(ele.smallCount) > 0) {
+          product.push({
+            productId: ele.id,
+            num: ele.smallCount,
+            unitType: 1,
+            unitName: ele.smallUnit || '支',
+            unitPrice: unitPrice
+          })
+        }
+      })
+      if (this.$util.isEmpty(product)) {
+        this.$msg('请选择花材数量')
+        return
+      }
+      uni.showLoading({ title: '提交中', mask: true })
+      createFreeRefund({
+        customId: this.form.customId,
+        price: this.form.price,
+        remark: this.form.remark,
+        refundType: 1,
+        fundType: this.form.fundType,
+        product: JSON.stringify(product)
+      }).then((res) => {
+        uni.hideLoading()
+        if (res.code != 1) {
+          return
+        }
+        // 清空购物车记忆,避免下次误带
+        that.removeFromSaveDirect && that.removeFromSaveDirect()
+        const data = res.data || {}
+        if (Number(data.fundType) === 2) {
+          uni.setStorageSync('forwardResultPayload', {
+            fundType: data.fundType,
+            amount: data.refundPrice || that.form.price,
+            customId: data.customId || that.form.customId,
+            customBalance: data.customBalance != null ? data.customBalance : '',
+            customName: data.customName || that.form.customName || '',
+            forwardSn: data.orderSn || '',
+            forwardId: data.id || 0,
+            orderId: 0
+          })
+          that.$util.pageTo({
+            url: '/admin/billing/forwardResult',
+            type: 2,
+            query: {
+              fundType: data.fundType,
+              amount: data.refundPrice || that.form.price,
+              customId: data.customId || that.form.customId,
+              customBalance: data.customBalance != null ? data.customBalance : '',
+              customName: encodeURIComponent(data.customName || that.form.customName || ''),
+              forwardSn: data.orderSn || '',
+              forwardId: data.id || 0,
+              orderId: 0
+            }
+          })
+          return
+        }
+        that.$util.pageTo({
+          url: '/admin/billing/forwardResult',
+          type: 2,
+          query: {
+            fundType: data.fundType || that.form.fundType,
+            amount: data.refundPrice || that.form.price,
+            customId: data.customId || that.form.customId,
+            customName: encodeURIComponent(data.customName || that.form.customName || ''),
+            forwardSn: data.orderSn || '',
+            forwardId: data.id || 0
+          }
+        })
+      }).catch(() => {
+        uni.hideLoading()
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.affirm-page {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  background: #f5f5f5;
+}
+.affirm-view {
+  flex: 1;
+  overflow: auto;
+  padding-bottom: 140upx;
+}
+.module-com {
+  background: #fff;
+  margin-bottom: 20upx;
+}
+.commodity-item {
+  display: flex;
+  padding: 24upx 30upx;
+  border-bottom: 1upx solid #f0f0f0;
+}
+.item-icon {
+  width: 100upx;
+  height: 100upx;
+  border-radius: 8upx;
+  margin-right: 20upx;
+  flex-shrink: 0;
+}
+.item-info {
+  flex: 1;
+}
+.info-line {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8upx;
+}
+.item-name {
+  font-size: 28upx;
+  color: #333;
+  font-weight: bold;
+  flex: 1;
+}
+.item-price,
+.item-count {
+  font-size: 26upx;
+  color: #3385ff;
+}
+.item-type {
+  font-size: 24upx;
+  color: #999;
+}
+.summary-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20upx 30upx;
+}
+.operate-view {
+  color: #3385ff;
+  font-size: 26upx;
+}
+.describe-view {
+  font-size: 26upx;
+  color: #666;
+}
+.input-line-wrap {
+  padding: 0 10upx;
+}
+.tui-title {
+  width: 160upx;
+  font-size: 28upx;
+  color: #333;
+}
+.cell-value {
+  font-size: 28upx;
+  color: #333;
+}
+.tip-box {
+  margin: 20upx 30upx;
+  font-size: 24upx;
+  color: #999;
+  line-height: 1.5;
+}
+.under-bar {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  height: 110upx;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 30upx;
+  padding-bottom: env(safe-area-inset-bottom);
+  box-shadow: 0 -2upx 10upx rgba(0, 0, 0, 0.06);
+}
+.price-view {
+  font-size: 36upx;
+  color: #ff2842;
+  font-weight: bold;
+}
+</style>

+ 14 - 0
ghsApp/src/admin/custom/selectCustom.vue

@@ -97,6 +97,10 @@ export default {
     }
   },
   onLoad(option) {
+    // 工作台「退款」入口:选客户后进无原单退款流程
+    if (option && Number(option.refund) === 1) {
+      uni.setNavigationBarTitle({ title: '退款 · 选择客户' })
+    }
     // #ifdef APP-PLUS
     if(plus.device.vendor == 'Newland'){
       this.couldScan = true
@@ -115,8 +119,18 @@ export default {
       let book = this.option.book ? this.option.book : 0
       //显示所有花材,包括没库存的花材
       let getAll = this.option.getAll ? this.option.getAll : 0
+      // 工作台「退款」:无原单退款,选客后进选花材(refund=1)
+      let refund = this.option.refund ? this.option.refund : 0
       this.selectStyle = style
       if(style == 1){
+        // 无原单退款走独立选花页,不进开单 index2
+        if (Number(refund) === 1) {
+          this.$util.pageTo({
+            url: '/admin/billing/freeRefund?customId=' + item.id + '&customName=' + item.name,
+            type: 2
+          })
+          return
+        }
         //选择客户并开单情况
         if(this.$util.isScanEnv() || scanEnv == 1){
           this.$util.pageTo({url: '/admin/billing/affirm='+item.id+'&customName='+item.name,type:2})

+ 0 - 13
ghsApp/src/admin/home/components/OrderItem.vue

@@ -7,8 +7,6 @@
         <image class="avatar" mode="aspectFit" :src="item.customAvatarUrl"></image>
         <view class="tit"> {{ item.customName || '' }}</view>
         <view class="other-refund" v-if="item.refund == 2">有售后</view>
-        <!-- 隔天累计退款:有冲销角标 -->
-        <view class="other-forward" v-if="Number(item.nextDayTkPrice) > 0">有冲销</view>
         <view class="other-status" v-if="item.debt == 1">挂账</view>
         <text class="other-book" v-if="item.book == 1">预订单</text>
         <text class="other-presell" v-if="item.presell == 1">预售单</text>
@@ -727,17 +725,6 @@ export default {
     margin-right: 20upx;
     width: auto;
   }
-  & > .other-forward {
-    text-align: center;
-    color: white;
-    background-color: #e67e22;
-    border: 2upx solid #e67e22;
-    border-radius: 30upx;
-    padding: 5upx 12upx;
-    font-size: 20upx;
-    margin-right: 20upx;
-    width: auto;
-  }
   & > .other-status {
     text-align: center;
     color: white;

+ 5 - 0
ghsApp/src/api/refund/index.js

@@ -48,4 +48,9 @@ export const changeRefundOption = data => {
 /** 原单是否可走隔天冲销 */
 export const checkNextDayEligible = data => {
 	return https.get('/refund/check-next-day-eligible', data)
+}
+
+/** 无原单退款(工作台「退款」:选客户+花材,不关联销售单) */
+export const createFreeRefund = data => {
+	return https.post('/refund/create-free-refund', data)
 }

+ 43 - 9
ghsApp/src/components/forward-options-popup.vue

@@ -1,11 +1,11 @@
 <!--
-  隔天冲销选项弹框
-  用途:售后页确认隔天冲销时选择资金处理方式(原路/返余额/仅记账)
+  隔天冲销 / 无原单退款 资金选项弹框
+  用途:售后隔天冲销或工作台「退款」时选择资金处理方式(原路/返余额/仅记账)
 -->
 <template>
 	<view v-if="show" class="mask" @click="onCancel">
 		<view class="panel" @click.stop>
-			<view class="title">冲销确认</view>
+			<view class="title">{{ panelTitle }}</view>
 			<view class="tip">{{ tipText }}</view>
 			<view class="label">资金处理</view>
 			<view
@@ -18,8 +18,8 @@
 				<text>{{ opt.label }}</text>
 			</view>
 			<view class="btns">
-				<button class="admin-button-com" @click="onCancel">取消</button>
-				<button class="admin-button-com blue" @click="onOk">确认冲销</button>
+				<button class="popup-btn cancel" @click="onCancel">取消</button>
+				<button class="popup-btn confirm" @click="onOk">{{ confirmText }}</button>
 			</view>
 		</view>
 	</view>
@@ -35,7 +35,9 @@ export default {
 		// 挂账/余额强制返余额时隐藏其它选项
 		forceBalance: { type: Boolean, default: false },
 		// 已结账单当天售后也走冲销
-		orderCleared: { type: Boolean, default: false }
+		orderCleared: { type: Boolean, default: false },
+		// free=无原单退款文案;默认隔天冲销
+		mode: { type: String, default: '' }
 	},
 	data() {
 		return {
@@ -43,7 +45,16 @@ export default {
 		}
 	},
 	computed: {
+		panelTitle() {
+			return this.mode === 'free' ? '退款确认' : '冲销确认'
+		},
+		confirmText() {
+			return this.mode === 'free' ? '确认退款' : '确认冲销'
+		},
 		tipText() {
+			if (this.mode === 'free') {
+				return '无关联销售单:退货回库;资金按下方选择处理。'
+			}
 			if (this.orderCleared) {
 				return '订单已结账,按冲销处理:不扣减订单实付,金额记入隔天累计退款。'
 			}
@@ -133,13 +144,36 @@ export default {
 .btns {
 	display: flex;
 	flex-direction: row;
+	align-items: stretch;
 	margin-top: 30upx;
 }
-.btns button {
+/* 底部按钮固定高度,避免 uni button 默认过扁 */
+.popup-btn {
 	flex: 1;
-	margin-left: 16upx;
+	height: 88upx;
+	line-height: 88upx;
+	padding: 0;
+	margin: 0;
+	margin-left: 20upx;
+	font-size: 30upx;
+	border-radius: 12upx;
+	box-sizing: border-box;
+	text-align: center;
 }
-.btns button:first-child {
+.popup-btn:first-child {
 	margin-left: 0;
 }
+.popup-btn::after {
+	border: none;
+}
+.popup-btn.cancel {
+	color: #3385ff;
+	background: #fff;
+	border: 2upx solid #3385ff;
+}
+.popup-btn.confirm {
+	color: #fff;
+	background: #3385ff;
+	border: 2upx solid #3385ff;
+}
 </style>

+ 3 - 1
ghsApp/src/pages.json

@@ -335,7 +335,9 @@
 				{ "path": "confirm", "style": { "navigationBarTitleText": "待确认" } },
 				{"path": "toPay","style": {"navigationBarTitleText": "等待付款"}},
 				{"path": "affirmGhsBook","style": {"navigationBarTitleText": "等待付款"}},
-				{ "path": "forwardResult", "style": { "navigationBarTitleText": "冲销凭证" } }
+				{ "path": "forwardResult", "style": { "navigationBarTitleText": "冲销凭证" } },
+				{ "path": "freeRefund", "style": { "navigationBarTitleText": "退款选花材" } },
+				{ "path": "freeRefundConfirm", "style": { "navigationBarTitleText": "退款确认" } }
 			]
 		},
 		{

+ 0 - 1
hdApp/src/pagesPurchase/orderItem.vue

@@ -9,7 +9,6 @@
         </text>
       </view>
       <view v-if="info.refund == 2" class="status" style="color:red;border:1px solid red;border-radius:20upx;font-size:20upx;padding:5upx 12upx;margin-right:40upx;">有退款</view>
-      <view v-if="Number(info.nextDayTkPrice) > 0" class="status" style="color:#e67e22;border:1px solid #e67e22;border-radius:20upx;font-size:20upx;padding:5upx 12upx;margin-right:40upx;">有冲销</view>
       <view v-if="info.debt == 1" class="status" style="color:red;border:1px solid red;border-radius:20upx;font-size:20upx;padding:5upx 12upx;margin-right:40upx;">挂账</view>
       <text v-if="info.book == 1" class="status"  style="color:white;border:1px solid #657cac;border-radius:20upx;font-size:20upx;padding:5upx 12upx;margin-right:40upx;background:#657cac;">预订单</text>
       <view class="status" v-if="info.status == 3" style="color:green;font-weight:bold;">{{ getStatusName }} </view>