| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067 |
- <!-- 付款申请流程专用表单组件 -->
- <template>
- <view class="payment-form-component">
- <!-- 基本信息 -->
- <uni-card>
- <uni-section titleFontSize="1.3rem" title="基本信息" type="line"></uni-section>
- <uni-forms ref="baseFormRef" :modelValue="baseForm" :rules="baseFormRules" label-position="left" :label-width="120" :border="true">
- <uni-forms-item name="department" label="申请部门">
- <uni-easyinput v-model="baseForm.department" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="applyDate" label="申请日期">
- <uni-easyinput v-model="baseForm.applyDate" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="contractNumber" label="合同">
- <view v-if="isInitiateOrFieldEditable('contract_number')" class="selector-wrapper" @click="openContractSelector">
- <text v-if="baseForm.contractNumber">{{ baseForm.contractNumber }}</text>
- <text v-else class="placeholder">选择合同</text>
- </view>
- <uni-easyinput v-else v-model="baseForm.contractNumber" disabled></uni-easyinput>
- <button v-if="isInitiateOrFieldEditable('contract_number') && baseForm.contractId" type="warn" size="mini" @click="clearContract" style="margin-left: 10px;">清除</button>
- </uni-forms-item>
- <uni-forms-item name="payerName" label="单位" required>
- <uni-easyinput v-if="isInitiateOrFieldEditable('payer_name')"
- v-model="baseForm.payerName"
- placeholder="请输入单位"></uni-easyinput>
- <uni-easyinput v-else v-model="baseForm.payerName" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="payeeName" label="收款单位" required>
- <view v-if="isInitiateOrFieldEditable('payee_name') && !baseForm.contractId" class="payee-input-wrapper">
- <uni-easyinput
- v-model="baseForm.payeeName"
- placeholder="请输入或选择收款单位"
- @input="onPayeeInputChange"
- ></uni-easyinput>
- <button
- type="primary"
- size="mini"
- @click="openSupplierSelector"
- class="select-supplier-btn"
- >
- 选择供应商
- </button>
- </view>
- <uni-easyinput v-else v-model="baseForm.payeeName" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="payeeBankAccount" label="开户行及账号" required>
- <uni-easyinput v-if="isInitiateOrFieldEditable('payee_bank_account')"
- v-model="baseForm.payeeBankAccount"
- placeholder="请输入开户行及账号"></uni-easyinput>
- <uni-easyinput v-else v-model="baseForm.payeeBankAccount" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="paymentType" label="付款类型" required>
- <picker v-if="isInitiateOrFieldEditable('payment_type')"
- @change="onPaymentTypeChange"
- :value="paymentTypeIndex"
- :range="paymentTypeList"
- range-key="name">
- <view class="picker-wrapper">
- <text v-if="baseForm.paymentTypeName">{{ baseForm.paymentTypeName }}</text>
- <text v-else class="placeholder">请选择付款类型</text>
- </view>
- </picker>
- <uni-easyinput v-else v-model="baseForm.paymentTypeName" disabled></uni-easyinput>
- </uni-forms-item>
- <!-- 预付款:显示采购订单编号 -->
- <uni-forms-item v-if="baseForm.paymentType === '1'" name="purchaseOrderNo" label="采购订单编号">
- <view v-if="isInitiateOrFieldEditable('purchase_order_no')" class="selector-wrapper" @click="openPurchaseOrderSelector">
- <text v-if="baseForm.purchaseOrderNo">{{ baseForm.purchaseOrderNo }}</text>
- <text v-else class="placeholder">选择采购订单</text>
- </view>
- <uni-easyinput v-else v-model="baseForm.purchaseOrderNo" disabled></uni-easyinput>
- <button v-if="isInitiateOrFieldEditable('purchase_order_no') && baseForm.purchaseOrderNo" type="warn" size="mini" @click="clearPurchaseOrder" style="margin-left: 10px;">清除</button>
- </uni-forms-item>
-
- <!-- 到付款:显示入库单编号 -->
- <uni-forms-item v-if="baseForm.paymentType === '2'" name="storageOrderNo" label="入库单编号">
- <view v-if="isInitiateOrFieldEditable('storage_order_no')" class="selector-wrapper" @click="openStorageOrderSelector">
- <text v-if="baseForm.storageOrderNo">{{ baseForm.storageOrderNo }}</text>
- <text v-else class="placeholder">选择入库单</text>
- </view>
- <uni-easyinput v-else v-model="baseForm.storageOrderNo" disabled></uni-easyinput>
- <button v-if="isInitiateOrFieldEditable('storage_order_no') && baseForm.storageOrderNo" type="warn" size="mini" @click="clearStorageOrder" style="margin-left: 10px;">清除</button>
- </uni-forms-item>
- <uni-forms-item name="paymentMethod" label="付款方式" required>
- <uni-easyinput v-if="isInitiateOrFieldEditable('payment_method')"
- v-model="baseForm.paymentMethod"
- placeholder="请输入付款方式"></uni-easyinput>
- <uni-easyinput v-else v-model="baseForm.paymentMethod" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="paymentDate" label="付款日期" required>
- <picker v-if="isInitiateOrFieldEditable('payment_date')"
- mode="date"
- :value="baseForm.paymentDate"
- @change="onPaymentDateChange">
- <view class="picker-wrapper">
- <text v-if="baseForm.paymentDate">{{ baseForm.paymentDate }}</text>
- <text v-else class="placeholder">请选择付款日期</text>
- </view>
- </picker>
- <uni-easyinput v-else v-model="baseForm.paymentDate" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="amountUpper" label="付款金额(大写)">
- <uni-easyinput v-model="baseForm.amountUpper" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="amountLower" label="付款金额(小写)" required>
- <uni-easyinput v-if="isInitiateOrFieldEditable('amount_lower')"
- v-model="baseForm.amountLower"
- placeholder="请输入付款金额"
- type="digit"
- @input="onAmountLowerInput"></uni-easyinput>
- <uni-easyinput v-else v-model="baseForm.amountLower" disabled></uni-easyinput>
- </uni-forms-item>
- <uni-forms-item name="purpose" label="用途或理由" required>
- <textarea v-if="isInitiateOrFieldEditable('purpose')"
- v-model="baseForm.purpose"
- placeholder="请输入用途或理由"
- class="textarea-input"></textarea>
- <view v-else class="textarea-display">{{ baseForm.purpose || '-' }}</view>
- </uni-forms-item>
- <uni-forms-item name="operator" label="经办人" required>
- <uni-easyinput v-model="baseForm.operator" disabled></uni-easyinput>
- </uni-forms-item>
- <!-- 部门负责人签名 -->
- <uni-forms-item label="部门负责人" name="deptApprover">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(deptApproverElem)" class="element_value">
- <view v-if="deptApproverElem && (!deptApproverElem.defaultValue || deptApproverElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('dept_approver')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('dept_approver')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="deptApproverElem && deptApproverElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('dept_approver')"
- :src="config.baseUrlPre + deptApproverElem.sealImgPath"
- :alt="deptApproverElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="deptApproverElem && typeof deptApproverElem.sealImgPath === 'string' && deptApproverElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + deptApproverElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 经办会计签名 -->
- <uni-forms-item label="经办会计" name="accountant">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(accountantElem)" class="element_value">
- <view v-if="accountantElem && (!accountantElem.defaultValue || accountantElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('accountant')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('accountant')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="accountantElem && accountantElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('accountant')"
- :src="config.baseUrlPre + accountantElem.sealImgPath"
- :alt="accountantElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="accountantElem && typeof accountantElem.sealImgPath === 'string' && accountantElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + accountantElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 财务经理签名 -->
- <uni-forms-item label="财务经理" name="financeManager">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(financeManagerElem)" class="element_value">
- <view v-if="financeManagerElem && (!financeManagerElem.defaultValue || financeManagerElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('finance_manager')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('finance_manager')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="financeManagerElem && financeManagerElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('finance_manager')"
- :src="config.baseUrlPre + financeManagerElem.sealImgPath"
- :alt="financeManagerElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="financeManagerElem && typeof financeManagerElem.sealImgPath === 'string' && financeManagerElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + financeManagerElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 分管副总部门签名 -->
- <uni-forms-item label="分管副总(部门)" name="deputyManagerDept">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(deputyManagerDeptElem)" class="element_value">
- <view v-if="deputyManagerDeptElem && (!deputyManagerDeptElem.defaultValue || deputyManagerDeptElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('deputy_manager_dept')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('deputy_manager_dept')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="deputyManagerDeptElem && deputyManagerDeptElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('deputy_manager_dept')"
- :src="config.baseUrlPre + deputyManagerDeptElem.sealImgPath"
- :alt="deputyManagerDeptElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="deputyManagerDeptElem && typeof deputyManagerDeptElem.sealImgPath === 'string' && deputyManagerDeptElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + deputyManagerDeptElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 分管副总审计签名 -->
- <uni-forms-item label="分管副总(审计)" name="deputyManagerAudit">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(deputyManagerAuditElem)" class="element_value">
- <view v-if="deputyManagerAuditElem && (!deputyManagerAuditElem.defaultValue || deputyManagerAuditElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('deputy_manager_audit')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('deputy_manager_audit')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="deputyManagerAuditElem && deputyManagerAuditElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('deputy_manager_audit')"
- :src="config.baseUrlPre + deputyManagerAuditElem.sealImgPath"
- :alt="deputyManagerAuditElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="deputyManagerAuditElem && typeof deputyManagerAuditElem.sealImgPath === 'string' && deputyManagerAuditElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + deputyManagerAuditElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 公司总经理签名 -->
- <uni-forms-item label="公司总经理" name="generalManager">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(generalManagerElem)" class="element_value">
- <view v-if="generalManagerElem && (!generalManagerElem.defaultValue || generalManagerElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('general_manager')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('general_manager')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="generalManagerElem && generalManagerElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('general_manager')"
- :src="config.baseUrlPre + generalManagerElem.sealImgPath"
- :alt="generalManagerElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="generalManagerElem && typeof generalManagerElem.sealImgPath === 'string' && generalManagerElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + generalManagerElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- <!-- 董事长签名 -->
- <uni-forms-item label="董事长" name="chairman">
- <view class="element_value_container">
- <view v-if="isApprovalFieldEditable(chairmanElem)" class="element_value">
- <view v-if="chairmanElem && (!chairmanElem.defaultValue || chairmanElem.defaultValue == '')">
- <uni-row>
- <uni-col :span="24">
- <button type="primary" @click="handleApprovalSignature('chairman')">手动签名</button>
- </uni-col>
- <uni-col :span="24">
- <button style="margin-top: 5px;" type="primary" @click="handleAutoSeal('chairman')">一键签名</button>
- </uni-col>
- </uni-row>
- </view>
- <view v-else-if="chairmanElem && chairmanElem.defaultValue" class="signature_img">
- <img style="width: 100%;" mode="widthFix" @click="handleApprovalSignature('chairman')"
- :src="config.baseUrlPre + chairmanElem.sealImgPath"
- :alt="chairmanElem.elementName + '签名'" />
- </view>
- </view>
- <view v-else-if="chairmanElem && typeof chairmanElem.sealImgPath === 'string' && chairmanElem.sealImgPath.startsWith('/shares')" class="signature_img">
- <img style="width: 100%;" mode="widthFix"
- :src="config.baseUrlPre + chairmanElem.sealImgPath" />
- </view>
- </view>
- </uni-forms-item>
- </uni-forms>
- </uni-card>
-
- <!-- 签名板弹出层 -->
- <uni-popup ref="signaturePopup" @maskClick="closeSignature">
- <view class="signature_container" :class="{ 'signature_container_landscape': isLandscape }">
- <view class="signature_content">
- <l-signature ref="signatureRef" v-if="signaturePopupShow" :landscape="isLandscape" :penSize="8"
- :minLineWidth="4" :maxLineWidth="12" :openSmooth="true" :preferToDataURL="true"
- backgroundColor="#ffffff" penColor="black"></l-signature>
- </view>
- <view class="signature_button_container">
- <uni-row :gutter="10">
- <uni-col :span="6">
- <button type="warn" @click="onclickSignatureButton('undo')">撤销</button>
- </uni-col>
- <uni-col :span="6">
- <button type="warn" @click="onclickSignatureButton('clear')">清空</button>
- </uni-col>
- <uni-col :span="6">
- <button type="primary" @click="onclickSignatureButton('save')">保存</button>
- </uni-col>
- <uni-col :span="6">
- <button @click="onclickSignatureButton('landscape')">全屏</button>
- </uni-col>
- </uni-row>
- </view>
- </view>
- </uni-popup>
- <!-- 选择器弹出层(供应商/合同/采购订单/入库单) -->
- <uni-popup ref="selectorPopup" type="center">
- <view class="selector-popup">
- <view class="popup-header">
- <text class="popup-title">{{ selectorTitle }}</text>
- <uni-icons type="closeempty" size="20" @click="closePopup"></uni-icons>
- </view>
-
- <!-- 选择器内容 -->
- <view class="popup-content-wrapper">
- <!-- 搜索栏 -->
- <view class="search-bar">
- <uni-easyinput
- v-model="searchKeyword"
- :placeholder="searchPlaceholder"
- clearable
- @confirm="handleSearch"
- />
- <button type="primary" size="mini" @click="handleSearch">搜索</button>
- </view>
-
- <!-- 合同类型筛选 -->
- <view v-if="selectorType === 'contract'" class="filter-bar">
- <picker @change="onContractTypeChange" :range="contractTypeList" range-key="name">
- <view class="picker-filter">
- {{ selectedContractTypeName || '全部合同类型' }}
- </view>
- </picker>
- </view>
-
- <!-- 入库单多选提示 -->
- <view v-if="selectorType === 'storageOrder' && selectedStorageOrders.length > 0" class="selected-tip">
- 已选择 {{ selectedStorageOrders.length }} 个入库单
- </view>
-
- <scroll-view
- scroll-y
- class="popup-content"
- refresher-enabled
- :refresher-triggered="isRefreshing"
- @refresherrefresh="onRefresh"
- @scrolltolower="loadMore"
- >
- <view v-for="(item, index) in selectorList" :key="index"
- class="selector-item"
- :class="{ 'selected': isStorageOrderSelected(item) }"
- @click="toggleStorageOrderSelection(item)">
- <view class="selector-item-content">
- <!-- 入库单显示复选框 -->
- <view v-if="selectorType === 'storageOrder'" class="checkbox-wrapper">
- <text class="checkbox-icon">{{ isStorageOrderSelected(item) ? '✓' : '' }}</text>
- </view>
-
- <view class="item-info">
- <!-- 名称(合同名称/采购订单名称/入库单名称) -->
- <text class="item-name">{{ getSelectorItemName(item) }}</text>
-
- <!-- 编号(合同编号/采购订单编号/入库单编号) -->
- <text v-if="getItemCode(item)" class="item-code">{{ getItemCode(item) }}</text>
-
- <!-- 供应商(采购订单/入库单) -->
- <text v-if="getItemVendor(item)" class="item-vendor">{{ getItemVendor(item) }}</text>
-
- <!-- 总金额(采购订单/入库单) -->
- <text v-if="getItemAmount(item)" class="item-amount">金额:¥{{ getItemAmount(item) }}</text>
-
- <!-- 单据状态(采购订单/入库单) -->
- <text v-if="getItemStatus(item)" class="item-status" :class="getStatusClass(item)">{{ getItemStatus(item) }}</text>
-
- <!-- 创建时间(采购订单/入库单) -->
- <text v-if="getItemCreateTime(item)" class="item-time">{{ getItemCreateTime(item) }}</text>
-
- <!-- 合同类型显示(仅合同) -->
- <text v-if="selectorType === 'contract' && getContractTypeName(item)" class="item-type">
- 【{{ getContractTypeName(item) }}】
- </text>
- </view>
- </view>
- </view>
-
- <view v-if="isLoading && selectorList.length > 0" class="loading-text">
- <uni-load-more status="loading" />
- </view>
-
- <view v-else-if="!hasMore && selectorList.length > 0" class="no-more-text">
- <text>没有更多了</text>
- </view>
-
- <view v-if="selectorList.length === 0 && !isLoading" class="empty-data">
- <text>{{ searchKeyword ? '暂无相关数据' : '暂无数据' }}</text>
- </view>
- </scroll-view>
- </view>
-
- <!-- 入库单确认按钮(固定在底部) -->
- <view v-if="selectorType === 'storageOrder'" class="popup-footer-fixed">
- <button class="cancel-btn" @click="closePopup">取消</button>
- <button class="confirm-btn" @click="confirmStorageOrderSelection">确定</button>
- </view>
- </view>
- </uni-popup>
- </view>
- </template>
- <script setup lang="ts">
- import { ref, watch, computed, nextTick, onMounted } from 'vue'
- import { useUserStore } from '@/store/user.js'
- import config from '@/config.js'
- import { uploadSignatureBoardImg, getSeal } from '@/api/process.js'
- import { getSupplierList, getContractListForPayment, getPurchaseOrderList, getStorageOrderList } from '@/api/payment.js'
- import $modal from '@/plugins/modal.js'
- const userStore = useUserStore()
- const props = defineProps({
- formData: {
- type: Object,
- default: () => ({})
- },
- formElements: {
- type: Array,
- default: () => []
- },
- repeatingForm: {
- type: Object,
- default: () => ({ elementItem: [], elements: [] })
- },
- isInitiate: {
- type: Boolean,
- default: false
- },
- editableFields: {
- type: Array,
- default: () => []
- },
- currentTacheOpinion: {
- type: Object,
- default: null
- }
- })
- const emits = defineEmits(['update', 'signature-change'])
- // 表单数据
- const baseForm = ref<any>({
- payerName: '',
- payeeName: '',
- vendorCode: '',
- contractId: '',
- contractNumber: '',
- contractName: '',
- purchaseOrderNo: '',
- storageOrderNo: '',
- orderIdFromMes: '',
- amountLower: '',
- amountUpper: '',
- paymentType: '',
- paymentTypeName: '',
- paymentMethod: '',
- paymentDate: '',
- purpose: '',
- payeeBankAccount: '',
- bankName: '',
- bankAccount: '',
- accountId: '',
- accountName: '',
- applyDate: '',
- initiator: '',
- department: '',
- depid: null,
- operator: '',
- operatorId: ''
- })
- const baseFormRules = ref({
- payerName: [
- {
- required: true,
- errorMessage: '请输入单位'
- }
- ],
- payeeName: [
- {
- required: true,
- errorMessage: '请选择收款单位'
- }
- ],
- amountLower: [
- {
- required: true,
- errorMessage: '请输入付款金额'
- }
- ],
- paymentType: [
- {
- required: true,
- errorMessage: '请选择付款类型'
- }
- ],
- paymentMethod: [
- {
- required: true,
- errorMessage: '请输入付款方式'
- }
- ],
- paymentDate: [
- {
- required: true,
- errorMessage: '请选择付款日期'
- }
- ],
- purpose: [
- {
- required: true,
- errorMessage: '请输入用途或理由'
- }
- ],
- payeeBankAccount: [
- {
- required: true,
- errorMessage: '请输入开户行及账号'
- }
- ],
- operator: [
- {
- required: true,
- errorMessage: '请选择经办人'
- }
- ]
- })
- const signaturePopup = ref(null)
- const signatureRef = ref(null)
- const signatureImg = ref('')
- const currentApprovalText = ref('')
- const approvals = ref<any[]>([])
- const signaturePopupShow = ref(false)
- const isLandscape = ref(false)
- // 获取指定的审批意见元素
- const getApprovalElement = (fieldName: string) => {
- if (!props.formElements || !Array.isArray(props.formElements)) {
- return null
- }
- // 从 formElements 中找到对应的字段
- const elem = props.formElements.find(e => e.tableField === fieldName || e.elementName.includes(fieldName.replace(/_/g, '')))
- return elem || null
- }
- const deptApproverElem = computed(() => getApprovalElement('dept_approver'))
- const accountantElem = computed(() => getApprovalElement('accountant'))
- const financeManagerElem = computed(() => getApprovalElement('finance_manager'))
- const deputyManagerDeptElem = computed(() => getApprovalElement('deputy_manager_dept'))
- const deputyManagerAuditElem = computed(() => getApprovalElement('deputy_manager_audit'))
- const generalManagerElem = computed(() => getApprovalElement('general_manager'))
- const chairmanElem = computed(() => getApprovalElement('chairman'))
- const isSeModel = computed(() => props.isInitiate)
- const isApprovalFieldEditable = (elem: any) => {
- if (!elem) return false
- return props.editableFields && props.editableFields.includes(elem.tableField)
- }
- let lastFormInsId = ''
- const getFieldEditable = (fieldName: string) => {
- if (!props.editableFields || props.editableFields.length === 0) {
- return false
- }
- return props.editableFields.includes(fieldName)
- }
- const isInitiateOrFieldEditable = (fieldName: string) => {
- return props.isInitiate || getFieldEditable(fieldName)
- }
- // 监听表单数据变化
- watch(() => props.formData, (newVal) => {
- if (!newVal || Object.keys(newVal).length === 0) {
- return
- }
- const currentFormInsId = newVal.lFormInsId || newVal.universalid || ''
- if (currentFormInsId && currentFormInsId !== lastFormInsId) {
- lastFormInsId = currentFormInsId
-
- baseForm.value = {
- payerName: newVal.payerName || '',
- payeeName: newVal.payeeName || '',
- vendorCode: newVal.vendorCode || '',
- contractId: newVal.contractId || '',
- contractNumber: newVal.contractNumber || '',
- contractName: newVal.contractName || '',
- purchaseOrderNo: newVal.purchaseOrderNo || '',
- storageOrderNo: newVal.storageOrderNo || '',
- orderIdFromMes: newVal.orderIdFromMes || '',
- amountLower: (newVal.amountLower !== undefined && newVal.amountLower !== null) ? String(newVal.amountLower) : '',
- amountUpper: newVal.amountUpper || '',
- paymentType: newVal.paymentType || '',
- paymentTypeName: getPaymentTypeName(newVal.paymentType),
- paymentMethod: newVal.paymentMethod || '',
- paymentDate: newVal.paymentDate || '',
- purpose: newVal.purpose || '',
- payeeBankAccount: newVal.payeeBankAccount || '',
- bankName: newVal.bankName || '',
- bankAccount: newVal.bankAccount || '',
- accountId: newVal.accountId || '',
- accountName: newVal.accountName || '',
- applyDate: newVal.applyDate || '',
- initiator: newVal.initiator || '',
- department: newVal.department || '',
- depid: newVal.depid || null,
- operator: newVal.operator || '',
- operatorId: newVal.operatorId || ''
- }
- }
- }, { immediate: true, deep: true })
- // 监听收款单位变化,如果手动修改则清空关联信息
- let lastPayeeName = ''
- watch(() => baseForm.value.payeeName, (newVal, oldVal) => {
- // 只在发起或字段可编辑时生效
- if (!isInitiateOrFieldEditable('payee_name')) return
-
- // 如果有合同ID,不允许手动修改
- if (baseForm.value.contractId) return
-
- // 如果是从有值变为空,不处理
- if (!newVal && oldVal) return
-
- // 如果是通过选择器选择的(有vendorCode),不处理
- if (baseForm.value.vendorCode) return
-
- // 手动输入时,清空所有关联信息和供应商编码
- clearRelatedOrders()
- baseForm.value.vendorCode = ''
- })
- // 收款单位输入处理
- function onPayeeInputChange(value: string) {
- // 如果有合同ID,不允许手动修改
- if (baseForm.value.contractId) return
-
- // 手动输入时,立即清空所有关联信息和供应商编码
- clearRelatedOrders()
- baseForm.value.vendorCode = ''
- }
- function getPaymentTypeName(type: string): string {
- const typeMap: any = {
- '1': '预付款',
- '2': '到付款'
- }
- return typeMap[type] || type || '-'
- }
- // 打开合同选择器
- async function openContractSelector() {
- if (!isInitiateOrFieldEditable('contract_number')) return
- // 检查是否已选择采购订单或入库单
- if (baseForm.value.purchaseOrderNo || baseForm.value.storageOrderNo) {
- $modal.msg('已选择采购单或入库单,不能同时选择合同!请先清除。')
- return
- }
-
- selectorType.value = 'contract'
- selectedContractType.value = '' // 重置合同类型筛选
- searchKeyword.value = ''
- currentPage.value = 1
- hasMore.value = true
- selectorList.value = []
- await loadContracts(1, false)
- selectorPopup.value.open()
- }
- // 打开采购订单选择器
- async function openPurchaseOrderSelector() {
- if (!isInitiateOrFieldEditable('purchase_order_no')) return
- // 检查是否已选择合同或入库单
- if (baseForm.value.contractId || baseForm.value.storageOrderNo) {
- $modal.msg('已选择合同或入库单,不能同时选择采购订单!请先清除。')
- return
- }
-
- if (!baseForm.value.vendorCode) {
- $modal.msg('请先选择收款单位(供应商)!')
- return
- }
-
- selectorType.value = 'purchaseOrder'
- searchKeyword.value = ''
- currentPage.value = 1
- hasMore.value = true
- selectorList.value = []
- await loadPurchaseOrders(1, false)
- selectorPopup.value.open()
- }
- // 打开入库单选择器
- async function openStorageOrderSelector() {
- if (!isInitiateOrFieldEditable('storage_order_no')) return
- // 检查是否已选择合同或采购订单
- if (baseForm.value.contractId || baseForm.value.purchaseOrderNo) {
- $modal.msg('已选择合同或采购订单,不能同时选择入库单!请先清除。')
- return
- }
-
- if (!baseForm.value.vendorCode) {
- $modal.msg('请先选择收款单位(供应商)!')
- return
- }
-
- selectorType.value = 'storageOrder'
- selectedStorageOrders.value = [] // 重置多选列表
- searchKeyword.value = ''
- currentPage.value = 1
- hasMore.value = true
- selectorList.value = []
- await loadStorageOrders(1, false)
- selectorPopup.value.open()
- }
- // 打开经办人选择器
- async function openOperatorSelector() {
- if (!isInitiateOrFieldEditable('operator')) return
- $modal.msg('人员选择功能待实现')
- }
- // 付款类型变化
- function onPaymentTypeChange(e: any) {
- const index = e.detail.value
- baseForm.value.paymentType = paymentTypeList.value[index].value
- baseForm.value.paymentTypeName = paymentTypeList.value[index].name
-
- // 根据付款类型切换显示字段并清空被隐藏的字段
- togglePaymentFields(baseForm.value.paymentType)
- }
- // 根据付款类型切换显示字段
- function togglePaymentFields(paymentType: string) {
- if (paymentType === '1') { // 预付款
- // 清空入库单编号
- baseForm.value.storageOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- } else if (paymentType === '2') { // 到付款
- // 清空采购订单编号
- baseForm.value.purchaseOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- }
- }
- // 付款日期变化
- function onPaymentDateChange(e: any) {
- baseForm.value.paymentDate = e.detail.value
- }
- // 金额小写输入
- function onAmountLowerInput(value: string) {
- // 限制只能输入数字和小数点(参考PC端restrictToNumber函数)
- const restricted = restrictToNumber(value)
- // 如果值被修改了,更新表单值
- if (restricted !== value) {
- baseForm.value.amountLower = restricted
- }
- // 转换为大写
- convertToChinese()
- }
- // 限制输入框只能输入数字和小数点(参考PC端)
- function restrictToNumber(value: string): string {
- if (!value) return value
-
- // 只允许数字、小数点,且小数点只能有一个
- let newValue = value.replace(/[^0-9.]/g, '')
-
- // 确保小数点不超过一个
- const dotIndex = newValue.indexOf('.')
- if (dotIndex !== -1) {
- newValue = newValue.substring(0, dotIndex + 1) + newValue.substring(dotIndex + 1).replace(/\./g, '')
- }
-
- // 如果第一个字符是小数点,则在前面加0
- if (newValue.charAt(0) === '.') {
- newValue = '0' + newValue
- }
-
- return newValue
- }
- // 金额转大写
- function convertToChinese() {
- // 先清理输入值
- if (baseForm.value.amountLower) {
- baseForm.value.amountLower = restrictToNumber(baseForm.value.amountLower)
- }
-
- const amount = parseFloat(baseForm.value.amountLower)
- if (isNaN(amount) || amount <= 0) {
- baseForm.value.amountUpper = ''
- return
- }
-
- const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
- const cnIntRadice = ['', '拾', '佰', '仟']
- const cnIntUnits = ['', '万', '亿', '兆']
- const cnDecUnits = ['角', '分']
- const cnInteger = '整'
- const cnIntLast = '元'
-
- let integerNum = Math.floor(amount)
- let decimalNum = Math.round((amount - integerNum) * 100)
-
- let chineseStr = ''
-
- if (integerNum === 0) {
- chineseStr = cnNums[0] + cnIntLast
- } else {
- let intLen = integerNum.toString().length
- let zeroCount = 0
- for (let i = 0; i < intLen; i++) {
- let n = integerNum.toString().charAt(i)
- let p = intLen - i - 1
- let q = Math.floor(p / 4)
- let m = p % 4
-
- if (n === '0') {
- zeroCount++
- } else {
- if (zeroCount > 0) {
- chineseStr += cnNums[0]
- }
- zeroCount = 0
- chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
- }
-
- if (m === 0 && zeroCount < 4) {
- chineseStr += cnIntUnits[q]
- }
- }
- chineseStr += cnIntLast
- }
-
- if (decimalNum !== 0) {
- let jiao = Math.floor(decimalNum / 10)
- let fen = decimalNum % 10
-
- if (jiao !== 0) {
- chineseStr += cnNums[jiao] + cnDecUnits[0]
- }
- if (fen !== 0) {
- chineseStr += cnNums[fen] + cnDecUnits[1]
- }
- } else {
- chineseStr += cnInteger
- }
-
- baseForm.value.amountUpper = chineseStr
- }
- // 打开供应商选择器
- async function openSupplierSelector() {
- if (baseForm.value.contractId) {
- $modal.msg('已选择合同,收款单位由合同自动填充,如需修改请先清除合同!')
- return
- }
-
- selectorType.value = 'supplier'
- selectorList.value = []
- searchKeyword.value = ''
- await loadSuppliers(1, false)
- selectorPopup.value.open()
- }
- // 加载供应商列表
- async function loadSuppliers(page: number, append: boolean = false) {
- if (isLoading.value) return
-
- isLoading.value = true
- if (page === 1) {
- isRefreshing.value = true
- }
-
- try {
- const res = await getSupplierList(
- userStore.user.useId,
- page,
- pageSize,
- searchKeyword.value
- )
-
- if (res.returnCode === '1') {
- const result = res.returnParams
- const newList = result.list || []
-
- if (append) {
- selectorList.value = [...selectorList.value, ...newList]
- } else {
- selectorList.value = newList
- }
-
- hasMore.value = selectorList.value.length < result.total
- }
- } catch (error) {
- console.error('加载供应商失败', error)
- } finally {
- isLoading.value = false
- isRefreshing.value = false
- }
- }
- // 加载合同列表
- async function loadContracts(page: number, append: boolean = false) {
- if (isLoading.value) return
-
- isLoading.value = true
- if (page === 1) {
- isRefreshing.value = true
- }
-
- try {
- const res = await getContractListForPayment(
- userStore.user.useId,
- page,
- pageSize,
- searchKeyword.value,
- '', // supplierCode 不传,由后端根据其他条件筛选
- selectedContractType.value // 合同类型筛选
- )
-
- if (res.returnCode === '1') {
- const result = res.returnParams
- const newList = result.list || []
-
- if (append) {
- selectorList.value = [...selectorList.value, ...newList]
- } else {
- selectorList.value = newList
- }
-
- hasMore.value = selectorList.value.length < result.total
- }
- } catch (error) {
- console.error('加载合同失败', error)
- } finally {
- isLoading.value = false
- isRefreshing.value = false
- }
- }
- // 加载采购订单列表
- async function loadPurchaseOrders(page: number, append: boolean = false) {
- if (isLoading.value) return
-
- isLoading.value = true
- if (page === 1) {
- isRefreshing.value = true
- }
-
- try {
- const res = await getPurchaseOrderList(
- userStore.user.useId,
- page,
- pageSize,
- baseForm.value.vendorCode
- )
-
- if (res.returnCode === '1') {
- const result = res.returnParams
- const newList = result.list || []
-
- if (append) {
- selectorList.value = [...selectorList.value, ...newList]
- } else {
- selectorList.value = newList
- }
-
- hasMore.value = selectorList.value.length < result.total
- }
- } catch (error) {
- console.error('加载采购订单失败', error)
- } finally {
- isLoading.value = false
- isRefreshing.value = false
- }
- }
- // 加载入库单列表
- async function loadStorageOrders(page: number, append: boolean = false) {
- if (isLoading.value) return
-
- isLoading.value = true
- if (page === 1) {
- isRefreshing.value = true
- }
-
- try {
- const res = await getStorageOrderList(
- userStore.user.useId,
- page,
- pageSize,
- baseForm.value.vendorCode
- )
-
- if (res.returnCode === '1') {
- const result = res.returnParams
- const newList = result.list || []
-
- if (append) {
- selectorList.value = [...selectorList.value, ...newList]
- } else {
- selectorList.value = newList
- }
-
- hasMore.value = selectorList.value.length < result.total
- }
- } catch (error) {
- console.error('加载入库单失败', error)
- } finally {
- isLoading.value = false
- isRefreshing.value = false
- }
- }
- // 付款类型列表
- const paymentTypeList = ref([
- { value: '1', name: '预付款' },
- { value: '2', name: '到付款' }
- ])
- const paymentTypeIndex = computed(() => {
- const index = paymentTypeList.value.findIndex(item => item.value === baseForm.value.paymentType)
- return index >= 0 ? index : 0
- })
- // 选择器相关
- const selectorPopup = ref(null)
- const selectorType = ref('supplier') // supplier, contract, purchaseOrder, storageOrder
- const selectorList = ref<any[]>([])
- const currentPage = ref(1)
- const pageSize = 20
- const hasMore = ref(true)
- const isLoading = ref(false)
- const isRefreshing = ref(false)
- const searchKeyword = ref('')
- // 入库单多选相关
- const selectedStorageOrders = ref<any[]>([])
- // 合同类型相关
- const contractTypeList = ref([
- { value: '', name: '全部' },
- { value: '1', name: '销售合同' },
- { value: '2', name: '采购合同' },
- { value: '3', name: '技术服务合同' }
- ])
- const selectedContractType = ref('')
- const selectedContractTypeName = computed(() => {
- if (!selectedContractType.value) return ''
- const type = contractTypeList.value.find(t => t.value === selectedContractType.value)
- return type ? type.name : ''
- })
- // 选择器标题
- const selectorTitle = computed(() => {
- const titles: Record<string, string> = {
- supplier: '选择供应商',
- contract: '选择合同',
- purchaseOrder: '选择采购订单',
- storageOrder: '选择入库单'
- }
- return titles[selectorType.value] || '选择'
- })
- // 搜索框提示
- const searchPlaceholder = computed(() => {
- const placeholders: Record<string, string> = {
- supplier: '输入供应商名称搜索',
- contract: '输入合同名称搜索',
- purchaseOrder: '输入采购订单编号搜索',
- storageOrder: '输入入库单编号搜索'
- }
- return placeholders[selectorType.value] || '请输入搜索内容'
- })
- function closePopup() {
- selectorPopup.value.close()
- }
- function handleSearch() {
- currentPage.value = 1
- if (selectorType.value === 'supplier') {
- loadSuppliers(1, false)
- } else if (selectorType.value === 'contract') {
- loadContracts(1, false)
- } else if (selectorType.value === 'purchaseOrder') {
- loadPurchaseOrders(1, false)
- } else if (selectorType.value === 'storageOrder') {
- loadStorageOrders(1, false)
- }
- }
- function onRefresh() {
- currentPage.value = 1
- if (selectorType.value === 'supplier') {
- loadSuppliers(1, false)
- } else if (selectorType.value === 'contract') {
- loadContracts(1, false)
- } else if (selectorType.value === 'purchaseOrder') {
- loadPurchaseOrders(1, false)
- } else if (selectorType.value === 'storageOrder') {
- loadStorageOrders(1, false)
- }
- }
- function loadMore() {
- if (!hasMore.value || isLoading.value) return
- currentPage.value++
-
- if (selectorType.value === 'supplier') {
- loadSuppliers(currentPage.value, true)
- } else if (selectorType.value === 'contract') {
- loadContracts(currentPage.value, true)
- } else if (selectorType.value === 'purchaseOrder') {
- loadPurchaseOrders(currentPage.value, true)
- } else if (selectorType.value === 'storageOrder') {
- loadStorageOrders(currentPage.value, true)
- }
- }
- // 合同类型变化
- function onContractTypeChange(e: any) {
- const selectedIndex = e.detail.value
- selectedContractType.value = contractTypeList.value[selectedIndex].value
- // 重新加载合同列表
- loadContracts(1, false)
- }
- // 获取选择器项名称
- function getSelectorItemName(item: any): string {
- if (selectorType.value === 'supplier') {
- return item.vendorName || item.name || ''
- } else if (selectorType.value === 'contract') {
- return item.contract_name || item.contractName || ''
- } else if (selectorType.value === 'purchaseOrder') {
- return item.purchaseCode || item.purchase_code || ''
- } else if (selectorType.value === 'storageOrder') {
- return item.recptCode || item.recpt_code || ''
- }
- return ''
- }
- function getItemCode(item: any): string {
- if (selectorType.value === 'supplier') {
- return item.vendorCode || item.code || ''
- } else if (selectorType.value === 'contract') {
- return item.contract_number || item.contractNumber || ''
- }
- return ''
- }
- // 获取供应商名称(采购订单/入库单)
- function getItemVendor(item: any): string {
- if (selectorType.value === 'purchaseOrder' || selectorType.value === 'storageOrder') {
- return item.vendorName || item.vendor_name || ''
- }
- return ''
- }
- // 获取总金额(采购订单/入库单)
- function getItemAmount(item: any): string {
- if (selectorType.value === 'purchaseOrder' || selectorType.value === 'storageOrder') {
- const amount = item.totalAmount || item.total_amount
- if (amount) {
- return Number(amount).toFixed(2)
- }
- }
- return ''
- }
- // 获取单据状态(采购订单/入库单)
- function getItemStatus(item: any): string {
- if (selectorType.value === 'purchaseOrder' || selectorType.value === 'storageOrder') {
- const status = item.status
- if (status === 'CONFIRMED') {
- return '已确认'
- } else if (status === 'FINISHED') {
- return '已完成'
- }
- }
- return ''
- }
- // 获取状态样式类
- function getStatusClass(item: any): string {
- const status = item.status
- if (status === 'CONFIRMED') {
- return 'status-confirmed'
- } else if (status === 'FINISHED') {
- return 'status-finished'
- }
- return ''
- }
- // 获取创建时间(采购订单/入库单)
- function getItemCreateTime(item: any): string {
- if (selectorType.value === 'purchaseOrder' || selectorType.value === 'storageOrder') {
- return item.createTime || item.create_time || ''
- }
- return ''
- }
- // 获取合同类型名称(根据 contract_type 值)
- function getContractTypeName(item: any): string {
- const type = item.contract_type
- if (!type) return ''
-
- const typeMap: Record<string, string> = {
- '1': '销售合同',
- '2': '采购合同',
- '3': '技术服务合同'
- }
-
- // 优先使用后端返回的 contract_type_name,如果没有则根据 contract_type 转换
- return item.contract_type_name || typeMap[String(type)] || ''
- }
- // 检查入库单是否已选中
- function isStorageOrderSelected(item: any): boolean {
- if (selectorType.value !== 'storageOrder') return false
- return selectedStorageOrders.value.some(order =>
- order.recptCode === (item.recptCode || item.recpt_code)
- )
- }
- // 切换入库单选择状态
- function toggleStorageOrderSelection(item: any) {
- if (selectorType.value !== 'storageOrder') {
- // 非入库单类型,直接选择并关闭
- selectItem(item)
- return
- }
-
- const recptCode = item.recptCode || item.recpt_code
- const index = selectedStorageOrders.value.findIndex(order => order.recptCode === recptCode)
-
- if (index > -1) {
- // 已选中,取消选择
- selectedStorageOrders.value.splice(index, 1)
- } else {
- // 未选中,添加到选择列表
- selectedStorageOrders.value.push({
- recptCode: recptCode,
- recptId: item.recptId || item.recpt_id,
- recptName: item.recptName || item.recpt_name,
- vendorName: item.vendorName || item.vendor_name,
- totalAmount: item.totalAmount || item.total_amount
- })
- }
- }
- // 确认入库单选择
- function confirmStorageOrderSelection() {
- if (selectedStorageOrders.value.length === 0) {
- $modal.msg('请至少选择一个入库单!')
- return
- }
-
- // 将选中的入库单编号拼接(用逗号分隔)
- const storageOrderNos = selectedStorageOrders.value.map(order => order.recptCode).join(',')
- const storageOrderIds = selectedStorageOrders.value.map(order => order.recptId).join(',')
-
- baseForm.value.storageOrderNo = storageOrderNos
- baseForm.value.orderIdFromMes = storageOrderIds
-
- // 清空合同、采购订单
- baseForm.value.contractId = ''
- baseForm.value.contractNumber = ''
- baseForm.value.contractName = ''
- baseForm.value.purchaseOrderNo = ''
-
- closePopup()
- }
- function selectItem(item: any) {
- // 入库单使用多选逻辑,不走这里
- if (selectorType.value === 'storageOrder') return
-
- if (selectorType.value === 'supplier') {
- baseForm.value.payeeName = item.vendorName || item.name || ''
- baseForm.value.vendorCode = item.vendorCode || item.code || ''
- // 清空合同、采购订单、入库单
- clearRelatedOrders()
- } else if (selectorType.value === 'contract') {
- // 检查合同类型,只允许采购合同(2)和技术服务合同(3)
- const contractType = item.contract_type
- if (contractType !== 2 && contractType !== 3) {
- $modal.msg('只能选择采购合同或技术服务合同!')
- return
- }
-
- baseForm.value.contractId = item.universalid || item.id || ''
- baseForm.value.contractNumber = item.contract_number || item.contractNumber || ''
- baseForm.value.contractName = item.contract_name || item.contractName || ''
- // 回填供应商信息
- baseForm.value.payeeName = item.supplierName || item.supplier_name || ''
- baseForm.value.vendorCode = item.supplierCode || item.supplier_code || ''
- // 清空采购订单、入库单
- baseForm.value.purchaseOrderNo = ''
- baseForm.value.storageOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- } else if (selectorType.value === 'purchaseOrder') {
- baseForm.value.purchaseOrderNo = item.purchaseCode || item.purchase_code || ''
- baseForm.value.orderIdFromMes = item.purchaseId || item.purchase_id || ''
- // 清空合同、入库单
- baseForm.value.contractId = ''
- baseForm.value.contractNumber = ''
- baseForm.value.contractName = ''
- baseForm.value.storageOrderNo = ''
- }
-
- closePopup()
- }
- // 清除合同
- function clearContract() {
- baseForm.value.contractId = ''
- baseForm.value.contractNumber = ''
- baseForm.value.contractName = ''
- // 注意:不清空收款单位和供应商编码
- }
- // 清除采购订单
- function clearPurchaseOrder() {
- baseForm.value.purchaseOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- }
- // 清除入库单
- function clearStorageOrder() {
- baseForm.value.storageOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- // 清空多选列表
- selectedStorageOrders.value = []
- }
- // 清空所有关联信息
- function clearRelatedOrders() {
- baseForm.value.contractId = ''
- baseForm.value.contractNumber = ''
- baseForm.value.contractName = ''
- baseForm.value.purchaseOrderNo = ''
- baseForm.value.storageOrderNo = ''
- baseForm.value.orderIdFromMes = ''
- }
- // 处理审批意见签名
- const currentApprovalFieldName = ref('')
- const approvalSealInfo = ref<Record<string, any>>({})
- function handleApprovalSignature(fieldName: string) {
- currentApprovalFieldName.value = fieldName
- signaturePopupShow.value = false
- nextTick(() => {
- signaturePopupShow.value = true
- })
- signaturePopup.value.open()
- }
- function handleAutoSeal(fieldName: string) {
- const elem = getApprovalElement(fieldName)
- if (elem) {
- getSeal(userStore.user.useId).then(({ returnParams }) => {
- const elem = getApprovalElement(fieldName)
- elem.defaultValue = returnParams.sealFileId.universalid
- elem.sealImgPath = returnParams.sealFileId.path
- approvalSealInfo.value[fieldName] = {
- sealInsId: returnParams.sealFileId.universalid,
- sealFileId: returnParams.sealFileId.universalid,
- left: 0,
- top: 0
- }
- }).catch(err => {
- $modal.msgError('获取签名失败:' + err)
- })
- }
- }
- function initSignature() {
- signaturePopupShow.value = false
- setTimeout(() => {
- signaturePopupShow.value = true
- }, 100)
- }
- function onclickSignatureButton(event: string) {
- switch (event) {
- case 'undo':
- signatureRef.value.undo()
- break
- case 'clear':
- signatureRef.value.clear()
- break
- case 'save':
- signatureRef.value.canvasToTempFilePath({
- success: (res: any) => {
- if (res.isEmpty) {
- $modal.msgError('签名不能为空!')
- return
- }
- if (res.tempFilePath.substring(0, 'data:image/png;base64,'.length) == 'data:image/png;base64,') {
- const _fileData = res.tempFilePath
- uploadSignatureBoardImg(userStore.user.useId, _fileData, getApprovalElement(currentApprovalFieldName.value).tableField)
- .then(({ returnParams }) => {
- const elem = getApprovalElement(currentApprovalFieldName.value)
- elem.defaultValue = returnParams.sealInsID
- elem.sealImgPath = returnParams.path
- // 保存印章信息(用于后端处理)
- // sealInsID 是手写签名的实例 ID,但 imgval 需要使用印章模板 ID
- // 对于手写签名,印章模板 ID 与签名实例 ID 相同
- approvalSealInfo.value[currentApprovalFieldName.value] = {
- sealInsId: returnParams.sealInsID, // 签名实例 ID
- sealFileId: returnParams.sealInsID, // 印章模板 ID(手写签名时与实例 ID 相同)
- left: 0, // 默认左边距为 0
- top: 0 // 默认上边距为 0
- }
- currentApprovalFieldName.value = ''
- signaturePopupShow.value = false
- signaturePopup.value.close()
- })
- } else {
- uni.getFileSystemManager().readFile({
- filePath: res.tempFilePath,
- encoding: 'base64',
- success: (fileData: any) => {
- const _fileData = 'data:image/png;base64,' + fileData.data
- uploadSignatureBoardImg(userStore.user.useId, _fileData, getApprovalElement(currentApprovalFieldName.value).tableField)
- .then(({ returnParams }) => {
- const elem = getApprovalElement(currentApprovalFieldName.value)
- elem.defaultValue = returnParams.sealInsID
- elem.sealImgPath = returnParams.path
- // 保存印章信息(用于后端处理)
- // sealInsID 是手写签名的实例 ID,但 imgval 需要使用印章模板 ID
- // 对于手写签名,印章模板 ID 与签名实例 ID 相同
- approvalSealInfo.value[currentApprovalFieldName.value] = {
- sealInsId: returnParams.sealInsID, // 签名实例 ID
- sealFileId: returnParams.sealInsID, // 印章模板 ID(手写签名时与实例 ID 相同)
- left: 0, // 默认左边距为 0
- top: 0 // 默认上边距为 0
- }
- currentApprovalFieldName.value = ''
- signaturePopupShow.value = false
- signaturePopup.value.close()
- })
- }
- })
- }
- }
- })
- break
- case 'landscape':
- isLandscape.value = !isLandscape.value
- initSignature()
- break
- }
- }
- function clearSignature() {
- onclickSignatureButton('clear')
- }
- function saveSignature() {
- onclickSignatureButton('save')
- }
- function closeSignature() {
- signaturePopupShow.value = false
- signaturePopup.value.close()
- }
- // 暴露验证方法给父组件
- defineExpose({
- validate: async () => {
- if (!baseForm.value.payerName) {
- return Promise.reject(new Error('请输入单位'))
- }
- if (!baseForm.value.payeeName) {
- return Promise.reject(new Error('请选择收款单位'))
- }
- if (!baseForm.value.amountLower || Number(baseForm.value.amountLower) <= 0) {
- return Promise.reject(new Error('请输入有效的付款金额'))
- }
- if (!baseForm.value.paymentType) {
- return Promise.reject(new Error('请选择付款类型'))
- }
- if (!baseForm.value.paymentMethod) {
- return Promise.reject(new Error('请输入付款方式'))
- }
- if (!baseForm.value.paymentDate) {
- return Promise.reject(new Error('请选择付款日期'))
- }
- if (!baseForm.value.purpose) {
- return Promise.reject(new Error('请输入用途或理由'))
- }
- if (!baseForm.value.payeeBankAccount) {
- return Promise.reject(new Error('请输入开户行及账号'))
- }
- if (!baseForm.value.operator) {
- return Promise.reject(new Error('请选择经办人'))
- }
- if (!baseForm.value.accountId) {
- return Promise.reject(new Error('没有默认付款账户!请检查是否已设置默认账户。'))
- }
-
- // 验证审批意见字段
- const approvalFields = [
- { fieldName: 'dept_approver', msg: '部门负责人签名' },
- { fieldName: 'accountant', msg: '经办会计签名' },
- { fieldName: 'finance_manager', msg: '财务经理签名' },
- { fieldName: 'deputy_manager_dept', msg: '分管副总部门签名' },
- { fieldName: 'deputy_manager_audit', msg: '分管副总审计签名' },
- { fieldName: 'general_manager', msg: '公司总经理签名' },
- { fieldName: 'chairman', msg: '董事长签名' }
- ]
-
- for (const field of approvalFields) {
- const elem = getApprovalElement(field.fieldName)
- if (elem) {
- if (props.editableFields && props.editableFields.includes(field.fieldName)) {
- if (!elem.defaultValue || elem.defaultValue === '') {
- return Promise.reject(new Error(field.msg + '不能为空!'))
- }
- }
- }
- }
-
- return Promise.resolve()
- },
- getFormElements: () => {
- const formElements: any[] = []
-
- Object.keys(baseForm.value).forEach(key => {
- const value = baseForm.value[key]
- if (value !== undefined && value !== null) {
- formElements.push({
- name: key,
- value: String(value),
- type: '0'
- })
- }
- })
-
- const approvalFields = ['dept_approver', 'accountant', 'finance_manager', 'deputy_manager_dept', 'deputy_manager_audit', 'general_manager', 'chairman']
- approvalFields.forEach(fieldName => {
- const elem = getApprovalElement(fieldName)
- if (elem) {
- formElements.push({
- name: fieldName,
- value: elem.defaultValue || '',
- type: elem.type || '0'
- })
- // 添加签名图片的 imgval 值(用于后端处理)
- // 格式:sealFileId_left_top(必须使用印章模板 ID,而不是签名实例 ID)
- if (approvalSealInfo.value[fieldName]) {
- const sealInfo = approvalSealInfo.value[fieldName]
- formElements.push({
- name: fieldName + '_imgval',
- value: `${sealInfo.sealFileId}_${sealInfo.left}_${sealInfo.top}`,
- type: '0'
- })
- } else if (elem.sealImgPath && elem.defaultValue) {
- // 兼容旧数据:如果有 sealImgPath 和 defaultValue,提取 sealId 构建 imgval
- // sealImgPath 格式:/shares/document/seal/593268258724500.png
- const sealIdMatch = elem.sealImgPath.match(/\/seal\/(\d+)\.png$/)
- if (sealIdMatch) {
- const sealId = sealIdMatch[1]
- formElements.push({
- name: fieldName + '_imgval',
- value: `${sealId}_0_0`,
- type: '0'
- })
- }
- }
- }
- })
-
- return formElements
- },
- getFormData: () => {
- const formData: any = {
- ...baseForm.value
- }
-
- const approvalFields = ['dept_approver', 'accountant', 'finance_manager', 'deputy_manager_dept', 'deputy_manager_audit', 'general_manager', 'chairman']
- approvalFields.forEach(fieldName => {
- const elem = getApprovalElement(fieldName)
- if (elem) {
- formData[fieldName] = elem.defaultValue || ''
- // 添加签名图片的 imgval 值(用于后端处理)
- // 格式:sealFileId_left_top(必须使用印章模板 ID,而不是签名实例 ID)
- if (approvalSealInfo.value[fieldName]) {
- const sealInfo = approvalSealInfo.value[fieldName]
- formData[fieldName + '_imgval'] = `${sealInfo.sealFileId}_${sealInfo.left}_${sealInfo.top}`
- } else if (elem.sealImgPath && elem.defaultValue) {
- // 兼容旧数据:如果有 sealImgPath 和 defaultValue,提取 sealId 构建 imgval
- // sealImgPath 格式:/shares/document/seal/593268258724500.png
- const sealIdMatch = elem.sealImgPath.match(/\/seal\/(\d+)\.png$/)
- if (sealIdMatch) {
- const sealId = sealIdMatch[1]
- formData[fieldName + '_imgval'] = `${sealId}_0_0`
- }
- }
- }
- })
-
- return formData
- }
- })
- </script>
- <style lang="scss" scoped>
- .payment-form-component {
- ::v-deep .uni-forms {
- .uni-forms-item__content {
- .uni-easyinput__content-input {
- font-size: calc(14px + 1.2*(1rem - 16px)) !important;
- font-weight: 500;
- color: #333;
- }
- }
- }
-
- .selector-wrapper {
- padding: 8px 10px;
- border: 1px solid #e5e5e5;
- border-radius: 4px;
- min-height: 36px;
- display: flex;
- align-items: center;
- cursor: pointer;
-
- &:active {
- background-color: #f5f5f5;
- }
-
- .placeholder {
- color: #999;
- }
- }
-
- // 收款单位输入框和按钮的布局样式
- .payee-input-wrapper {
- display: flex;
- flex-direction: column;
- gap: 8px;
-
- ::v-deep .uni-easyinput {
- width: 100%;
- }
-
- .select-supplier-btn {
- width: 100%;
- }
- }
-
- .picker-wrapper {
- padding: 8px 10px;
- border: 1px solid #e5e5e5;
- border-radius: 4px;
- min-height: 36px;
- display: flex;
- align-items: center;
-
- .placeholder {
- color: #999;
- }
- }
-
- .textarea-input {
- width: 100%;
- min-height: 80px;
- padding: 8px 10px;
- border: 1px solid #e5e5e5;
- border-radius: 4px;
- font-size: 14px;
- }
-
- .textarea-display {
- width: 100%;
- min-height: 36px;
- padding: 8px 10px;
- border: 1px solid #e5e5e5;
- border-radius: 4px;
- font-size: 14px;
- color: #333;
- line-height: 1.5;
- }
-
- .element_value_container {
- .signature_img {
- width: 180px;
- }
- }
-
- .signature_container {
- background-color: #f5f5f5;
- height: 40vh;
- width: 90vw;
- .signature_content {
- height: 80%;
- width: 100%;
- }
- .signature_button_container {
- height: 20%;
- width: 100%;
- button {
- height: 100%;
- }
- }
- }
- .signature_container_landscape {
- height: 100vh;
- width: 100vw;
- .signature_content {
- height: 85%;
- width: 100%;
- }
- .signature_button_container {
- margin-top: 10%;
- height: 15%;
- width: 100%;
- button {
- height: 100%;
- width: 100%;
- transform: rotate(90deg);
- }
- }
- }
-
- .selector-popup {
- width: 90%;
- max-width: 500px;
- height: 60vh; // 固定高度
- background-color: #fff;
- border-radius: 12px;
- overflow: hidden;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
-
- position: relative;
- margin: 0 auto;
- display: flex;
- flex-direction: column; // 垂直布局
-
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 15px;
- border-bottom: 1px solid #e5e5e5;
-
- .popup-title {
- font-size: 16px;
- font-weight: bold;
- }
- }
-
- .popup-content-wrapper {
- flex: 1;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- padding-bottom: 50px; // 为固定底部按钮留出空间
-
- .search-bar {
- display: flex;
- gap: 10px;
- padding: 10px 15px;
- align-items: center;
- }
-
- .filter-bar {
- padding: 10px 15px;
- background-color: #fff;
- border-bottom: 1px solid #e5e5e5;
-
- .picker-filter {
- padding: 8px 12px;
- background-color: #f5f5f5;
- border-radius: 4px;
- font-size: 14px;
- color: #333;
- }
- }
- .selected-tip {
- padding: 10px 15px;
- background-color: #f0f9eb;
- border-bottom: 1px solid #e5e5e5;
- color: #67c23a;
- font-size: 13px;
- }
- .popup-content {
- flex: 1;
- overflow-y: auto;
-
- .selector-item {
- padding: 10px 12px;
- border-bottom: 1px solid #f0f0f0;
-
- &:active {
- background-color: #f5f5f5;
- }
-
- &.selected {
- background-color: #f0f9eb;
- }
-
- .selector-item-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 8px;
-
- // 入库单复选框样式
- .checkbox-wrapper {
- width: 24px;
- height: 24px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
-
- .checkbox-icon {
- font-size: 18px;
- color: #4caf50;
- font-weight: bold;
- }
- }
-
- .item-info {
- flex: 1;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 4px;
-
- .item-name {
- font-size: 15px;
- font-weight: bold;
- color: #333;
- flex-basis: 100%;
- margin-bottom: 4px;
- }
-
- .item-code,
- .item-spec {
- font-size: 13px;
- color: #666;
- white-space: nowrap;
- font-weight: 500;
- }
-
- .item-vendor {
- font-size: 13px;
- color: #999;
- white-space: nowrap;
- }
-
- .item-amount {
- font-size: 13px;
- color: #f76560;
- white-space: nowrap;
- font-weight: 500;
- }
-
- .item-status {
- font-size: 12px;
- padding: 2px 8px;
- border-radius: 4px;
- white-space: nowrap;
-
- &.status-confirmed {
- background-color: #ffecdb;
- color: #ff8800;
- }
-
- &.status-finished {
- background-color: #e8f5e9;
- color: #4caf50;
- }
- }
-
- .item-time {
- font-size: 12px;
- color: #999;
- white-space: nowrap;
- flex-basis: 100%;
- margin-top: 2px;
- }
-
- .item-type {
- font-size: 12px;
- color: #ff6b6b;
- white-space: nowrap;
- margin-left: 4px;
- }
-
- .item-code::after {
- content: ' | ';
- margin: 0 4px;
- color: #ddd;
- }
- }
- }
- }
-
- .loading-text {
- text-align: center;
- padding: 12px;
- color: #909399;
- font-size: 13px;
- }
-
- .no-more-text {
- text-align: center;
- padding: 12px;
- color: #909399;
- font-size: 13px;
- }
-
- .empty-data {
- text-align: center;
- padding: 30px;
- color: #909399;
- }
-
- // 入库单多选提示
- .selected-tip {
- padding: 8px 12px;
- background-color: #e8f5e9;
- color: #4caf50;
- font-size: 13px;
- text-align: center;
- border-bottom: 1px solid #c8e6c9;
- }
- }
- }
- }
-
- // 入库单确认按钮区域(固定在底部)
- .popup-footer-fixed {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 12px;
- border-top: 1px solid #e5e5e5;
- background-color: #fff;
- display: flex;
- gap: 12px;
- z-index: 10;
- box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
- }
-
- .popup-footer-fixed .cancel-btn {
- flex: 1 !important;
- height: 44px !important;
- line-height: 44px !important;
- font-size: 16px !important;
- background-color: #f5f5f5 !important;
- color: #333 !important;
- border: none !important;
- border-radius: 8px !important;
- margin: 0 !important;
- padding: 0 !important;
- }
-
- .popup-footer-fixed .confirm-btn {
- flex: 1 !important;
- height: 44px !important;
- line-height: 44px !important;
- font-size: 16px !important;
- background-color: #007aff !important;
- color: #fff !important;
- border: none !important;
- border-radius: 8px !important;
- margin: 0 !important;
- padding: 0 !important;
- }
- }
- // 基本信息中的禁用字段样式优化(参考 edit/index.vue)
- ::v-deep .uni-forms {
- .uni-forms-item__content {
- .uni-easyinput__content-input {
- font-size: calc(14px + 1.2*(1rem - 16px)) !important;
- font-weight: 500;
- color: #333;
- }
- .uni-date {
- .uni-icons {
- font-size: calc(22px + 1.2*(1rem - 16px)) !important;
- font-weight: 500;
- }
- .uni-date__x-input {
- height: auto;
- font-size: calc(14px + 1.2*(1rem - 16px)) !important;
- font-weight: 500;
- color: #333;
- }
- }
- }
- }
- </style>
|