| | |
| | | { |
| | | "path": "pages/mine", |
| | | "style": { |
| | | "navigationBarTitleText": "æç" |
| | | "navigationBarTitleText": "æç", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/sales/receiptPayment/edit", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¿®æ¹å款ç»è®°", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/sales/receiptPaymentHistory/index", |
| | | "style": { |
| | | "navigationBarTitleText": "忬¾æµæ°´", |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/procurementInvoiceLedger/index", |
| | | "style": { |
| | | "navigationBarTitleText": "æ¥ç¥¨å°è´¦", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/procurementInvoiceLedger/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¿®æ¹æ¥ç¥¨å°è´¦", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/paymentEntry/index", |
| | | "style": { |
| | | "navigationBarTitleText": "仿¬¾ç»è®°", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/paymentEntry/add", |
| | | "style": { |
| | | "navigationBarTitleText": "æ°å¢ä»æ¬¾ç»è®°", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/paymentEntry/edit", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¿®æ¹ä»æ¬¾ç»è®°", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/receiptPaymentHistory/index", |
| | | "style": { |
| | | "navigationBarTitleText": "仿¬¾æµæ°´", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/paymentLedger/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¾åºå徿¥", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/procurementManagement/paymentLedger/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¾åºå徿¥è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/common/webview/index", |
| | | "style": { |
| | | "navigationBarTitleText": "æµè§ç½é¡µ" |
| | |
| | | <view class="header-section"> |
| | | <view class="currentFactory"> |
| | | <up-text type="primary" :text="userStore.currentFactoryName" @click="show = true" size="18" |
| | | class="factoryName" suffixIcon="arrow-right" :iconStyle="iconStyle"></up-text> |
| | | class="factoryName" suffixIcon="arrow-right" :iconStyle="iconStyle"></up-text> |
| | | </view> |
| | | <up-picker :show="show" :columns="factoryList" @confirm="changeFactory" @cancel="show = false"></up-picker> |
| | | </view> |
| | |
| | | <view class="bg-img"> |
| | | <view class="hero-content"> |
| | | <text class="hero-title">产ååºå管çç³»ç»</text> |
| | | <text class="hero-subtitle">髿ã便æ·çä¸å¡ç®¡çå
¥å£</text> |
| | | </view> |
| | | <view class="hero-wave"></view> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | const factoryList = ref([]); |
| | | const factoryListTem = ref([]); |
| | | const iconStyle = { |
| | | fontSize: '18px', |
| | | fontSize: '1.125rem', |
| | | color: '#2979ff' |
| | | } |
| | | |
| | |
| | | url: '/pages/procurementManagement/invoiceEntry/index' |
| | | }); |
| | | break; |
| | | case 'æ¥ç¥¨å°è´¦': |
| | | uni.navigateTo({ |
| | | url: '/pages/procurementManagement/procurementInvoiceLedger/index' |
| | | }); |
| | | break; |
| | | case '仿¬¾ç»è®°': |
| | | uni.navigateTo({ |
| | | url: '/pages/procurementManagement/paymentEntry/index' |
| | | }); |
| | | break; |
| | | case '仿¬¾æµæ°´': |
| | | uni.navigateTo({ |
| | | url: '/pages/procurementManagement/receiptPaymentHistory/index' |
| | | }); |
| | | break; |
| | | case 'ä¾åºå徿¥': |
| | | uni.navigateTo({ |
| | | url: '/pages/procurementManagement/paymentLedger/index' |
| | | }); |
| | | break; |
| | | case 'åå审æ¹': |
| | | uni.navigateTo({ |
| | | url: '/pages/cooperativeOffice/collaborativeApproval/index' |
| | |
| | | .content { |
| | | background: linear-gradient(135deg, #f8f9fa 0%, #e3f2fd 100%); |
| | | min-height: 100vh; |
| | | padding: 20px; |
| | | padding: 1.25rem; |
| | | padding-top: env(safe-area-inset-top); |
| | | position: relative; |
| | | |
| | |
| | | /* æ¬é¡µä¸åå®ä¹ .safe-area-topï¼å·²ç§»è³å
¨å±æ ·å¼ */ |
| | | |
| | | .header-section { |
| | | margin-bottom: 16px; |
| | | margin-bottom: 1rem; |
| | | animation: fadeInDown 0.6s ease-out; |
| | | } |
| | | |
| | | .currentFactory { |
| | | margin-top: 8px; |
| | | margin-left: 4px; |
| | | margin-top: 0.5rem; |
| | | margin-left: 0.25rem; |
| | | font-weight: 500; |
| | | display: flex; |
| | | } |
| | |
| | | } |
| | | |
| | | .hero-section { |
| | | margin-bottom: 16px; |
| | | margin-bottom: 1rem; |
| | | animation: fadeInUp 0.6s ease-out 0.1s both; |
| | | } |
| | | |
| | | .bg-img { |
| | | width: 100%; |
| | | height: 120px; |
| | | height: 8.75rem; |
| | | background: linear-gradient(135deg, #2979ff 0%, #1565c0 100%); |
| | | border-radius: 12px; |
| | | border-radius: 0.75rem; |
| | | position: relative; |
| | | overflow: hidden; |
| | | box-shadow: 0 4px 20px rgba(41, 121, 255, 0.15); |
| | | box-shadow: 0 0.25rem 1.25rem rgba(41, 121, 255, 0.15); |
| | | |
| | | &::before { |
| | | content: ''; |
| | |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | width: 120px; |
| | | height: 120px; |
| | | width: 7.5rem; |
| | | height: 7.5rem; |
| | | background: radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 70%); |
| | | border-radius: 50%; |
| | | transform: translate(40px, -40px); |
| | | transform: translate(2.5rem, -2.5rem); |
| | | } |
| | | } |
| | | |
| | | .hero-content { |
| | | position: relative; |
| | | z-index: 1; |
| | | padding: 20px; |
| | | padding: 1.25rem; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .hero-title { |
| | | color: #ffffff; |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | font-size: 1.625rem; |
| | | font-weight: 700; |
| | | letter-spacing: 0.03125rem; |
| | | } |
| | | .hero-subtitle { font-size: 0.8125rem; margin-top: 0.375rem; } |
| | | .hero-wave { height: 2.75rem; } |
| | | |
| | | .hero-subtitle { |
| | | color: rgba(255, 255, 255, 0.9); |
| | | font-size: 0.8125rem; |
| | | margin-top: 0.375rem; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | .hero-wave { |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 2.75rem; |
| | | background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'><path fill='%23ffffff' fill-opacity='0.2' d='M0,224L48,218.7C96,213,192,203,288,197.3C384,192,480,192,576,176C672,160,768,128,864,122.7C960,117,1056,139,1152,144C1248,149,1344,139,1392,133.3L1440,128L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'></path></svg>") no-repeat bottom center/cover; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | |
| | | |
| | | .notice-section { |
| | | margin-bottom: 16px; |
| | | margin-bottom: 1rem; |
| | | animation: fadeInUp 0.6s ease-out 0.2s both; |
| | | } |
| | | |
| | | .notice { |
| | | width: 100%; |
| | | background: linear-gradient(135deg, #EAF2FF 0%, #BBDEFB 100%); |
| | | border: 1px solid #e3f2fd; |
| | | border-radius: 12px; |
| | | padding: 16px; |
| | | box-shadow: 0 4px 20px rgba(41, 121, 255, 0.08); |
| | | border: 0.0625rem solid #e3f2fd; |
| | | border-radius: 0.75rem; |
| | | padding: 1rem; |
| | | box-shadow: 0 0.25rem 1.25rem rgba(41, 121, 255, 0.08); |
| | | position: relative; |
| | | overflow: hidden; |
| | | |
| | |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | width: 80px; |
| | | height: 80px; |
| | | width: 5rem; |
| | | height: 5rem; |
| | | background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%); |
| | | border-radius: 50%; |
| | | transform: translate(30px, -30px); |
| | | transform: translate(1.875rem, -1.875rem); |
| | | } |
| | | |
| | | &:hover { |
| | | transform: translateY(-0.125rem); |
| | | box-shadow: 0 0.5rem 1.875rem rgba(0, 0, 0, 0.1); |
| | | } |
| | | } |
| | | |
| | |
| | | @keyframes fadeInDown { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(-20px); |
| | | transform: translateY(-1.25rem); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | |
| | | @keyframes fadeInUp { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(20px); |
| | | transform: translateY(1.25rem); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | |
| | | } |
| | | } |
| | | |
| | | @keyframes rotate { |
| | | from { |
| | | transform: rotate(0deg); |
| | | } |
| | | to { |
| | | transform: rotate(360deg); |
| | | } |
| | | @keyframes fadeInScale { |
| | | 0% { opacity: 0; transform: translateY(0.5rem) scale(0.96); } |
| | | 100% { opacity: 1; transform: translateY(0) scale(1); } |
| | | } |
| | | |
| | | .notice-content { |
| | |
| | | } |
| | | |
| | | .notice-left { |
| | | margin-right: 16px; |
| | | margin-right: 1rem; |
| | | } |
| | | |
| | | .notice-status { |
| | | font-weight: 600; |
| | | font-size: 16px; |
| | | font-size: 1rem; |
| | | color: #1976d2; |
| | | } |
| | | |
| | | .notice-separator { |
| | | width: 1px; |
| | | height: 24px; |
| | | width: 0.0625rem; |
| | | height: 1.5rem; |
| | | background: #e0e0e0; |
| | | margin-right: 16px; |
| | | margin-right: 1rem; |
| | | } |
| | | |
| | | .notice-right { |
| | |
| | | |
| | | .notice-label { |
| | | color: #333; |
| | | font-size: 14px; |
| | | font-size: 0.875rem; |
| | | font-weight: 500; |
| | | margin-right: 12px; |
| | | margin-right: 0.75rem; |
| | | } |
| | | |
| | | .notice-text { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | font-size: 0.875rem; |
| | | color: #666666; |
| | | } |
| | | |
| | | .notice-number { |
| | | font-weight: 600; |
| | | font-size: 16px; |
| | | font-size: 1rem; |
| | | color: #1976d2; |
| | | margin-left: 4px; |
| | | margin-left: 0.25rem; |
| | | } |
| | | |
| | | .notice-unit { |
| | | color: #666666; |
| | | font-size: 14px; |
| | | margin-left: 2px; |
| | | font-size: 0.875rem; |
| | | margin-left: 0.125rem; |
| | | } |
| | | |
| | | /* åè½æ¨¡åæ ·å¼ */ |
| | | .common-module { |
| | | margin-bottom: 24px; |
| | | margin-bottom: 1.5rem; |
| | | background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%); |
| | | border-radius: 16px; |
| | | padding: 16px; |
| | | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06); |
| | | border-radius: 1rem; |
| | | padding: 1rem; |
| | | box-shadow: 0 0.25rem 1.25rem rgba(0, 0, 0, 0.06); |
| | | border: none; |
| | | position: relative; |
| | | overflow: hidden; |
| | |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | width: 60px; |
| | | height: 60px; |
| | | width: 3.75rem; |
| | | height: 3.75rem; |
| | | background: radial-gradient(circle, rgba(0,0,0,0.02) 0%, transparent 70%); |
| | | border-radius: 50%; |
| | | transform: translate(30px, -30px); |
| | | } |
| | | |
| | | &:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); |
| | | |
| | | &::after { |
| | | background: radial-gradient(circle, rgba(0,0,0,0.04) 0%, transparent 70%); |
| | | } |
| | | transform: translate(1.875rem, -1.875rem); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .module-header { |
| | | margin-bottom: 24px; |
| | | margin-bottom: 1.5rem; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | |
| | | |
| | | .module-title { |
| | | color: #333333; |
| | | font-size: 18px; |
| | | font-size: 1.125rem; |
| | | font-weight: 600; |
| | | position: relative; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | bottom: -4px; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, var(--module-color), rgba(255,255,255,0.9)); |
| | | border-radius: 1px; |
| | | transition: all 0.3s ease; |
| | | box-shadow: 0 0 8px rgba(0,0,0,0.1); |
| | | } |
| | | |
| | | &:hover::after { |
| | | width: 30px; |
| | | box-shadow: 0 0 12px rgba(0,0,0,0.15); |
| | | } |
| | | } |
| | | |
| | | .module-subtitle { |
| | | color: #666666; |
| | | font-size: 12px; |
| | | font-size: 0.75rem; |
| | | font-weight: 400; |
| | | margin-left: 8px; |
| | | margin-left: 0.5rem; |
| | | } |
| | | |
| | | .module-content { |
| | | width: 100%; |
| | | display: grid; |
| | | gap: 16px; |
| | | gap: 1rem; |
| | | } |
| | | |
| | | .icon-container { |
| | | width: 52px; |
| | | height: 52px; |
| | | border-radius: 12px; |
| | | width: 3.25rem; |
| | | height: 3.25rem; |
| | | border-radius: 0.75rem; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 6px; |
| | | box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); |
| | | transition: all 0.3s ease; |
| | | margin-bottom: 0.375rem; |
| | | box-shadow: 0 0.1875rem 0.75rem rgba(0, 0, 0, 0.12); |
| | | transition: all 0.2s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | animation: fadeInScale 0.5s ease both; |
| | | |
| | | &::before { |
| | | content: ''; |
| | |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | border-radius: 12px; |
| | | border-radius: 0.75rem; |
| | | background: linear-gradient(45deg, transparent, rgba(255,255,255,0.2), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | &:hover { |
| | | transform: translateY(-3px) scale(1.02); |
| | | box-shadow: 0 8px 25px rgba(0, 0, 0, 0.18); |
| | | transform: translateY(-0.1875rem) scale(1.02); |
| | | box-shadow: 0 0.5rem 1.5625rem rgba(0, 0, 0, 0.18); |
| | | |
| | | &::before, |
| | | &::after { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | &:active { |
| | | transform: scale(0.97); |
| | | box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.18); |
| | | } |
| | | } |
| | | |
| | | .item-label { |
| | | font-size: 13px; |
| | | font-size: 0.8125rem; |
| | | color: #555555; |
| | | text-align: center; |
| | | display: block; |
| | | line-height: 1.4; |
| | | font-weight: 500; |
| | | margin-top: 4px; |
| | | margin-bottom: 10px; |
| | | margin-top: 0.25rem; |
| | | margin-bottom: 0.625rem; |
| | | } |
| | | |
| | | .grid-text { |
| | | font-size: 14px; |
| | | font-size: 0.875rem; |
| | | color: #909399; |
| | | padding: 10rpx 0 20rpx 0rpx; |
| | | padding: 0.625rem 0 1.25rem 0; |
| | | /* #ifndef APP-PLUS */ |
| | | box-sizing: border-box; |
| | | /* #endif */ |
| | | } |
| | | |
| | | /* æè²æ¨¡å¼éé
*/ |
| | | @media (prefers-color-scheme: dark) { |
| | | .content { |
| | | background: linear-gradient(135deg, #121317 0%, #161a20 100%); |
| | | } |
| | | .content::before { |
| | | background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="1" fill="rgba(255, 255, 255, 0.05)"/></pattern></defs><rect width="100" height="100" fill="url(%23dots)"/></svg>'); |
| | | } |
| | | .common-module { |
| | | background: linear-gradient(135deg, #1e1f24 0%, #23252b 100%); |
| | | box-shadow: 0 0.375rem 1.5rem rgba(0,0,0,0.35); |
| | | } |
| | | .module-title { |
| | | color: #e9edf3; |
| | | } |
| | | .module-subtitle, .item-label, .notice-text, .notice-unit, .notice-label { |
| | | color: #c7cbd3; |
| | | } |
| | | .notice { |
| | | background: linear-gradient(135deg, #1b2330 0%, #1a2432 100%); |
| | | border-color: rgba(255,255,255,0.06); |
| | | box-shadow: 0 0.375rem 1.25rem rgba(0,0,0,0.4); |
| | | } |
| | | .notice-status, .notice-number { |
| | | color: #8ab4ff; |
| | | } |
| | | .bg-img { |
| | | background: linear-gradient(135deg, #1f4fb9 0%, #0e3a8a 100%); |
| | | } |
| | | } |
| | | |
| | | @keyframes rotate { |
| | | from { transform: rotate(0deg); } |
| | | to { transform: rotate(360deg); } |
| | | } |
| | | |
| | | @keyframes fadeInDown { |
| | | from { opacity: 0; transform: translateY(-1.25rem); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | @keyframes fadeInUp { |
| | | from { opacity: 0; transform: translateY(1.25rem); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | @keyframes fadeInScale { |
| | | 0% { opacity: 0; transform: translateY(0.5rem) scale(0.96); } |
| | | 100% { opacity: 1; transform: translateY(0) scale(1); } |
| | | } |
| | | |
| | | .notice-left { margin-right: 1rem; } |
| | | .notice-status { font-size: 1rem; } |
| | | .notice-separator { width: 0.0625rem; height: 1.5rem; margin-right: 1rem; } |
| | | .notice-label { font-size: 0.875rem; margin-right: 0.75rem; } |
| | | .notice-text { font-size: 0.875rem; } |
| | | .notice-number { font-size: 1rem; margin-left: 0.25rem; } |
| | | .notice-unit { font-size: 0.875rem; margin-left: 0.125rem; } |
| | | |
| | | .common-module { |
| | | margin-bottom: 1.5rem; |
| | | background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%); |
| | | border-radius: 1rem; |
| | | padding: 1rem; |
| | | box-shadow: 0 0.25rem 1.25rem rgba(0, 0, 0, 0.06); |
| | | border: none; |
| | | position: relative; |
| | | overflow: hidden; |
| | | transition: all 0.3s ease; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | width: 3.75rem; |
| | | height: 3.75rem; |
| | | background: radial-gradient(circle, rgba(0,0,0,0.02) 0%, transparent 70%); |
| | | border-radius: 50%; |
| | | transform: translate(1.875rem, -1.875rem); |
| | | } |
| | | } |
| | | |
| | | .marketing-module { |
| | | --module-color: #2979ff; |
| | | } |
| | | |
| | | .purchase-module { |
| | | --module-color: #1976d2; |
| | | } |
| | | |
| | | .collaboration-module { |
| | | --module-color: #4caf50; |
| | | } |
| | | |
| | | .equipment-module { |
| | | --module-color: #9c27b0; |
| | | } |
| | | |
| | | .module-header { |
| | | margin-bottom: 1.5rem; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .module-title-container { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .module-title { |
| | | color: #333333; |
| | | font-size: 1.125rem; |
| | | font-weight: 600; |
| | | position: relative; |
| | | } |
| | | |
| | | .module-subtitle { |
| | | color: #666666; |
| | | font-size: 0.75rem; |
| | | font-weight: 400; |
| | | margin-left: 0.5rem; |
| | | } |
| | | |
| | | .module-content { |
| | | width: 100%; |
| | | display: grid; |
| | | gap: 1rem; |
| | | } |
| | | |
| | | .icon-container { |
| | | width: 3.25rem; |
| | | height: 3.25rem; |
| | | border-radius: 0.75rem; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 0.375rem; |
| | | box-shadow: 0 0.1875rem 0.75rem rgba(0, 0, 0, 0.12); |
| | | transition: all 0.2s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | animation: fadeInScale 0.5s ease both; |
| | | |
| | | &:hover { |
| | | transform: translateY(-0.1875rem) scale(1.02); |
| | | box-shadow: 0 0.5rem 1.5625rem rgba(0, 0, 0, 0.18); |
| | | } |
| | | |
| | | &:active { |
| | | transform: scale(0.97); |
| | | box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.18); |
| | | } |
| | | } |
| | | |
| | | .item-label { font-size: 0.8125rem; margin-top: 0.25rem; margin-bottom: 0.625rem; } |
| | | .grid-text { font-size: 0.875rem; } |
| | | |
| | | @media (prefers-color-scheme: dark) { |
| | | .common-module { box-shadow: 0 0.375rem 1.5rem rgba(0,0,0,0.35); } |
| | | .notice { box-shadow: 0 0.375rem 1.25rem rgba(0,0,0,0.4); } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <view class="mine-container" :style="{ height: `${windowHeight}px` }"> |
| | | <!--é¡¶é¨ä¸ªäººä¿¡æ¯æ --> |
| | | <view class="header-section"> |
| | | <view class="flex padding justify-between"> |
| | | <view class="flex align-center"> |
| | | <view v-if="!avatar" class="cu-avatar xl round bg-white"> |
| | | <view class="iconfont icon-people text-gray icon"></view> |
| | | </view> |
| | | <image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix"> |
| | | </image> |
| | | <view v-if="!name" @click="handleToLogin" class="login-tip"> |
| | | ç¹å»ç»å½ |
| | | </view> |
| | | <view v-if="name" @click="handleToInfo" class="user-info"> |
| | | <view class="u_title"> |
| | | ç¨æ·åï¼{{ name }} |
| | | </view> |
| | | <view class="mine-page"> |
| | | <!-- é¡¶é¨ä¸ªäººä¿¡æ¯å¡ --> |
| | | <view class="profile-card"> |
| | | <view class="left"> |
| | | <view v-if="!avatar" class="avatar-placeholder"> |
| | | <view class="iconfont icon-people"></view> |
| | | </view> |
| | | <image |
| | | v-else |
| | | class="avatar" |
| | | :src="avatar" |
| | | mode="aspectFill" |
| | | @click="handleToAvatar" |
| | | /> |
| | | <view class="info"> |
| | | <view class="name-line"> |
| | | <text class="name" @click="name ? handleToInfo() : handleToLogin()"> |
| | | {{ name || 'ç¹å»ç»å½' }} |
| | | </text> |
| | | <text v-if="roleName" class="role-tag">{{ roleName }}</text> |
| | | </view> |
| | | </view> |
| | | <view @click="handleToInfo" class="flex align-center"> |
| | | <text>个人信æ¯</text> |
| | | <view class="iconfont icon-right"></view> |
| | | </view> |
| | | </view> |
| | | <view class="right" @click="handleToInfo"> |
| | | <text class="link">个人信æ¯</text> |
| | | <view class="iconfont icon-right"></view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="content-section"> |
| | | <view class="mine-actions grid col-4 text-center"> |
| | | <view class="action-item" @click="handleJiaoLiuQun"> |
| | | <view class="iconfont icon-friendfill text-pink icon"></view> |
| | | <text class="text">交æµç¾¤</text> |
| | | </view> |
| | | <view class="action-item" @click="handleBuilding"> |
| | | <view class="iconfont icon-service text-blue icon"></view> |
| | | <text class="text">å¨çº¿å®¢æ</text> |
| | | </view> |
| | | <view class="action-item" @click="handleBuilding"> |
| | | <view class="iconfont icon-community text-mauve icon"></view> |
| | | <text class="text">åé¦ç¤¾åº</text> |
| | | </view> |
| | | <view class="action-item" @click="handleBuilding"> |
| | | <view class="iconfont icon-dianzan text-green icon"></view> |
| | | <text class="text">ç¹èµæä»¬</text> |
| | | </view> |
| | | <!-- ä¸ä¸ªç®¡çèå --> |
| | | <view class="menu-card"> |
| | | <view class="menu-item" @click="handleUnitManage"> |
| | | <uni-icons type="home" size="22" color="#3C96F3" /> |
| | | <text class="label">åä½ç®¡ç</text> |
| | | <uni-icons class="arrow" type="right" size="18" color="#c0c4cc" /> |
| | | </view> |
| | | |
| | | <view class="menu-list"> |
| | | <view class="list-cell list-cell-arrow" @click="handleToEditInfo"> |
| | | <view class="menu-item-box"> |
| | | <view class="iconfont icon-user menu-icon"></view> |
| | | <view>ç¼è¾èµæ</view> |
| | | </view> |
| | | </view> |
| | | <view class="list-cell list-cell-arrow" @click="handleHelp"> |
| | | <view class="menu-item-box"> |
| | | <view class="iconfont icon-help menu-icon"></view> |
| | | <view>常è§é®é¢</view> |
| | | </view> |
| | | </view> |
| | | <view class="list-cell list-cell-arrow" @click="handleAbout"> |
| | | <view class="menu-item-box"> |
| | | <view class="iconfont icon-aixin menu-icon"></view> |
| | | <view>å
³äºæä»¬</view> |
| | | </view> |
| | | </view> |
| | | <view class="list-cell list-cell-arrow" @click="handleToSetting"> |
| | | <view class="menu-item-box"> |
| | | <view class="iconfont icon-setting menu-icon"></view> |
| | | <view>åºç¨è®¾ç½®</view> |
| | | </view> |
| | | </view> |
| | | <view class="menu-item" @click="handleUserManage"> |
| | | <uni-icons type="person" size="22" color="#3C96F3" /> |
| | | <text class="label">ç¨æ·ç®¡ç</text> |
| | | <uni-icons class="arrow" type="right" size="18" color="#c0c4cc" /> |
| | | </view> |
| | | |
| | | <view class="menu-item" @click="handleContractManage"> |
| | | <uni-icons type="compose" size="22" color="#3C96F3" /> |
| | | <text class="label">åå管ç</text> |
| | | <uni-icons class="arrow" type="right" size="18" color="#c0c4cc" /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- åºé¨ä¸¤ä¸ªä¿¡æ¯å¡ç --> |
| | | <!-- <view class="info-cards"> |
| | | <view class="info-card"> |
| | | <view class="card-left"> |
| | | <view class="title">å¸®å©ææ¡£</view> |
| | | <view class="desc">äºè§£å¹³å°åè½æ¨¡å</view> |
| | | <button class="card-btn" @click="handleHelp">ç¹å»æ¥ç</button> |
| | | </view> |
| | | <view class="card-illu note"></view> |
| | | </view> |
| | | |
| | | <view class="info-card"> |
| | | <view class="card-left"> |
| | | <view class="title">é®é¢åé¦</view> |
| | | <view class="desc">è§£å³å¹³å°ä½¿ç¨é®é¢</view> |
| | | <button class="card-btn warn" @click="handleFeedback">ç¹å»å¨è¯¢</button> |
| | | </view> |
| | | <view class="card-illu faq"></view> |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | <!-- <view> |
| | | <uni-popup ref="popup" type="dialog"> |
| | | <uni-popup-dialog type="info" cancelText="å
³é" confirmText="éåº" |
| | | title="éç¥" content="ç¡®å®æ³¨éå¹¶éåºç³»ç»å" |
| | | @confirm="dialogConfirm" |
| | | @close="dialogClose"> |
| | | </uni-popup-dialog> |
| | | </uni-popup> |
| | | </view> --> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import { ref, onMounted } from "vue"; |
| | | import config from '@/config.js' |
| | | import { getUserProfile } from "@/api/system/user"; |
| | | import useUserStore from '@/store/modules/user' |
| | | const userStore = useUserStore() |
| | | const name = userStore.name; |
| | | const roleName = userStore.roleName; |
| | | const version = config.appInfo.version; |
| | | |
| | | const avatar = ref(userStore.avatar); |
| | | const windowHeight = ref(uni.getSystemInfoSync().windowHeight - 50); |
| | | // rem åºåï¼1rem = 16pxï¼å¦æä¸åè¯·è°æ´ REM_BASE ææ ·å¼æ°å¼ï¼ |
| | | const REM_BASE = 16; |
| | | const windowHeightRem = ref((uni.getSystemInfoSync().windowHeight - 50) / REM_BASE); |
| | | const popup = ref(null); |
| | | |
| | | uni.$on('refresh', () => { |
| | |
| | | function handleToInfo() { |
| | | uni.navigateTo({ |
| | | url: '/pages_mine/pages/info/index' |
| | | }); |
| | | }; |
| | | function handleToEditInfo() { |
| | | uni.navigateTo({ |
| | | url: '/pages_mine/pages/info/edit' |
| | | }); |
| | | }; |
| | | function handleToSetting() { |
| | | uni.navigateTo({ |
| | | url: '/pages_mine/pages/setting/index' |
| | | }); |
| | | }; |
| | | function handleToLogin() { |
| | |
| | | }); |
| | | }) |
| | | }; |
| | | function dialogClose() { |
| | | //console.log('ç¹å»å
³é') |
| | | }; |
| | | function handleHelp() { |
| | | uni.navigateTo({ |
| | | url: '/pages_mine/pages/help/index' |
| | | }); |
| | | }; |
| | | function handleAbout() { |
| | | uni.navigateTo({ |
| | | url: '/pages_mine/pages/about/index' |
| | | }); |
| | | }; |
| | | function handleJiaoLiuQun() { |
| | | uni.showToast({ |
| | | title: 'QQ群ï¼133713780', |
| | | mask: false, |
| | | icon: "none", |
| | | duration: 1000 |
| | | }); |
| | | }; |
| | | function handleBuilding() { |
| | | uni.showToast({ |
| | | title: '模å建设ä¸~', |
| | | mask: false, |
| | | icon: "none", |
| | | duration: 1000 |
| | | }); |
| | | } |
| | | |
| | | // ç°æè·³è½¬æ¹æ³ä¿çï¼handleToInfo / handleToLogin / handleToAvatar / handleHelp ç |
| | | function handleUnitManage() { |
| | | // TODO: æ¿æ¢ä¸ºçå®è·¯ç± |
| | | uni.showToast({ title: '模å建设ä¸~', icon: 'none' }); |
| | | } |
| | | function handleUserManage() { |
| | | // TODO: æ¿æ¢ä¸ºçå®è·¯ç± |
| | | uni.showToast({ title: '模å建设ä¸~', icon: 'none' }); |
| | | } |
| | | function handleContractManage() { |
| | | // TODO: æ¿æ¢ä¸ºçå®è·¯ç± |
| | | uni.showToast({ title: '模å建设ä¸~', icon: 'none' }); |
| | | } |
| | | onMounted(() => { |
| | | // è®¾ç½®ç¨æ·ä¿¡æ¯ |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | page { |
| | | background-color: #f5f6f7; |
| | | <style lang="scss" scoped> |
| | | /* 页é¢å®¹å¨ */ |
| | | .mine-page { |
| | | min-height: 100vh; |
| | | padding: 1.25rem; |
| | | padding-top: env(safe-area-inset-top); |
| | | position: relative; |
| | | background: linear-gradient( 225deg, #E7F1FF 0%, rgba(255,255,255,0) 74%, rgba(255,255,255,0) 100%); |
| | | } |
| | | |
| | | .mine-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | /* é¡¶é¨ä¸ªäººä¿¡æ¯å¡ */ |
| | | .profile-card { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | color: #333; |
| | | margin: 1.25rem 0; |
| | | |
| | | .left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 0.75rem; |
| | | |
| | | .header-section { |
| | | padding: 15px 15px 45px 15px; |
| | | background-color: #3c96f3; |
| | | color: white; |
| | | |
| | | .login-tip { |
| | | font-size: 18px; |
| | | margin-left: 10px; |
| | | .avatar { |
| | | width: 3.5rem; |
| | | height: 3.5rem; |
| | | border-radius: 50%; |
| | | border: 0.125rem solid #fff; |
| | | background: #fff; |
| | | object-fit: cover; |
| | | } |
| | | .avatar-placeholder { |
| | | width: 3.5rem; |
| | | height: 3.5rem; |
| | | border-radius: 50%; |
| | | background: #fff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border: 0.125rem solid #fff; |
| | | |
| | | .cu-avatar { |
| | | border: 2px solid #eaeaea; |
| | | |
| | | .icon { |
| | | font-size: 40px; |
| | | .iconfont { |
| | | font-size: 2rem; |
| | | color: #c0c4cc; |
| | | } |
| | | } |
| | | |
| | | .user-info { |
| | | margin-left: 15px; |
| | | .info { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .u_title { |
| | | font-size: 18px; |
| | | line-height: 30px; |
| | | .name-line { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | gap: 0.5rem; |
| | | |
| | | .name { |
| | | font-size: 1.125rem; |
| | | font-weight: 600; |
| | | color: #2c2c2c; |
| | | } |
| | | .role-tag { |
| | | font-size: 0.75rem; |
| | | color: #fff; |
| | | background: #ffa940; |
| | | padding: 0.125rem 0.5rem; |
| | | border-radius: 0.75rem; |
| | | } |
| | | } |
| | | |
| | | .phone { |
| | | margin-top: 0.25rem; |
| | | font-size: 0.8125rem; |
| | | color: #3c96f3; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .content-section { |
| | | .right { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 0.375rem; |
| | | color: #666; |
| | | |
| | | .link { |
| | | font-size: 0.875rem; |
| | | } |
| | | .iconfont { |
| | | font-size: 0.875rem; |
| | | color: #c0c4cc; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* èåå¡ç */ |
| | | .menu-card { |
| | | margin-top: 0.75rem; |
| | | background: #fff; |
| | | border-radius: 0.75rem; |
| | | overflow: hidden; |
| | | |
| | | .menu-item { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 3.5rem; |
| | | padding: 1.25rem; |
| | | position: relative; |
| | | top: -50px; |
| | | |
| | | .mine-actions { |
| | | margin: 15px 15px; |
| | | padding: 20px 0px; |
| | | border-radius: 8px; |
| | | background-color: white; |
| | | .label { |
| | | flex: 1; |
| | | margin-left: 0.625rem; |
| | | color: #303133; |
| | | font-size: 0.9375rem; |
| | | } |
| | | .arrow { |
| | | opacity: 0.6; |
| | | } |
| | | } |
| | | |
| | | .action-item { |
| | | .icon { |
| | | font-size: 28px; |
| | | .menu-item + .menu-item { |
| | | border-top: 0.0625rem solid #f2f3f5; |
| | | } |
| | | } |
| | | |
| | | /* åºé¨ä¿¡æ¯å¡ç */ |
| | | .info-cards { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 0.75rem; |
| | | margin-top: 0.75rem; |
| | | |
| | | .info-card { |
| | | position: relative; |
| | | background: #fff; |
| | | border-radius: 0.75rem; |
| | | padding: 0.875rem 0.75rem; |
| | | min-height: 7rem; |
| | | overflow: hidden; |
| | | |
| | | .card-left { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 0.375rem; |
| | | |
| | | .title { |
| | | font-size: 1rem; |
| | | font-weight: 600; |
| | | color: #2c2c2c; |
| | | } |
| | | .desc { |
| | | font-size: 0.75rem; |
| | | color: #8a8a8a; |
| | | } |
| | | .card-btn { |
| | | margin-top: 0.5rem; |
| | | width: 6rem; |
| | | height: 1.875rem; |
| | | line-height: 1.875rem; |
| | | border: none; |
| | | border-radius: 62.4375rem; |
| | | font-size: 0.8125rem; |
| | | color: #fff; |
| | | background: #3c96f3; |
| | | |
| | | &.warn { |
| | | background: #ffb03a; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .text { |
| | | display: block; |
| | | font-size: 13px; |
| | | margin: 8px 0px; |
| | | } |
| | | /* å³ä¾§è£
饰ï¼å¯æ¿æ¢ä¸ºå¾çï¼ */ |
| | | .card-illu { |
| | | position: absolute; |
| | | right: -0.375rem; |
| | | bottom: 0; |
| | | width: 4.875rem; |
| | | height: 4.875rem; |
| | | opacity: 0.9; |
| | | |
| | | &.note { |
| | | background: radial-gradient(closest-side, #e8f2ff, transparent), |
| | | linear-gradient(135deg, #d8eaff, #f5faff); |
| | | border-radius: 0.75rem 0 0 0; |
| | | } |
| | | &.faq { |
| | | background: radial-gradient(closest-side, #ffe9d0, transparent), |
| | | linear-gradient(135deg, #ffe0b2, #fff3e0); |
| | | border-radius: 0.75rem 0 0 0; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | setTimeout(() => { |
| | | uni.navigateBack() |
| | | }, 1500) |
| | | goBack() |
| | | }, 800) |
| | | |
| | | } catch (error) { |
| | | showToast('æäº¤å¤±è´¥ï¼è¯·éè¯') |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="account-detail"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="æ°å¢ä»æ¬¾" @back="onClickLeft" /> |
| | | |
| | | <!-- 表åå
容 --> |
| | | <van-form @submit="onSubmit" ref="formRef" label-width="110px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <van-cell-group title="åºæ¬ä¿¡æ¯" inset> |
| | | <van-field |
| | | v-model="form.purchaseContractNumber" |
| | | label="éè´ååå·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.salesContractNo" |
| | | label="éå®ååå·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.supplierName" |
| | | label="ä¾åºååç§°" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.invoiceNumber" |
| | | label="å票å·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.invoiceAmount" |
| | | label="å票éé¢(å
)" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <view class="tip-text">å¾
仿¬¾éé¢ï¼{{ currentNoReceiptAmount }} å
</view> |
| | | <van-field |
| | | v-model="form.currentPaymentAmount" |
| | | label="æ¬æ¬¡ä»æ¬¾éé¢" |
| | | type="number" |
| | | placeholder="请è¾å
¥" |
| | | @blur="changeNum" |
| | | :rules="[{ required: true, message: '请è¾å
¥ä»æ¬¾éé¢' }]" |
| | | clearable |
| | | /> |
| | | <van-field |
| | | v-model="form.paymentMethod" |
| | | label="仿¬¾å½¢å¼" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | @click="showPaymentTypePicker" |
| | | :rules="[{ required: true, message: 'è¯·éæ©ä»æ¬¾å½¢å¼' }]" |
| | | /> |
| | | <van-field |
| | | v-model="form.paymentDate" |
| | | label="仿¬¾æ¥æ" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | @click="showDatePicker" |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ¥æ¬¾æ¥æ' }]" |
| | | /> |
| | | <van-field |
| | | v-model="form.registrant" |
| | | label="ç»è®°äºº" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.registrationtDate" |
| | | label="ç»è®°æ¥æ" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ¥æ¬¾æ¥æ' }]" |
| | | /> |
| | | </van-cell-group> |
| | | |
| | | <!-- æäº¤æé® --> |
| | | <view class="footer-btns"> |
| | | <van-button class="cancel-btn" @click="onClickLeft">åæ¶</van-button> |
| | | <van-button class="save-btn" native-type="submit" form-type="submit" :loading="loading">ä¿å</van-button> |
| | | </view> |
| | | </van-form> |
| | | |
| | | <!-- 仿¬¾æ¹å¼éæ©å¨ --> |
| | | <van-popup v-model:show="showPaymentType" position="bottom"> |
| | | <van-picker |
| | | :model-value="pickerValue" |
| | | :columns="receipt_payment_type" |
| | | @confirm="onPaymentTypeConfirm" |
| | | @cancel="showPaymentType = false" |
| | | /> |
| | | </van-popup> |
| | | |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <van-popup v-model:show="showDate" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentDate" |
| | | title="éæ©æ¥æ" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDate = false" |
| | | /> |
| | | </van-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { showToast, showNotify } from 'vant' |
| | | import { useDict } from '@/utils/dict' |
| | | import {paymentRegistrationAdd} from "@/api/procurementManagement/paymentEntry"; |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // 表åå¼ç¨ |
| | | const formRef = ref() |
| | | |
| | | // ååºå¼æ°æ® |
| | | const loading = ref(false) |
| | | const showPaymentType = ref(false) |
| | | const pickerValue = ref([]) |
| | | const showDate = ref(false) |
| | | const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | purchaseContractNumber: '', |
| | | salesContractNo: '', |
| | | supplierName: '', |
| | | invoiceNumber: '', |
| | | invoiceAmount: '', |
| | | taxRate: '', |
| | | currentPaymentAmount: '', |
| | | receiptPaymentType: '', |
| | | paymentMethod: '', |
| | | registrant: '', |
| | | paymentDate: '', |
| | | registrationtDate: '', |
| | | ticketRegistrationId: '' |
| | | }) |
| | | const currentNoReceiptAmount = ref(0) |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { receipt_payment_type: dictReceiptPaymentType } = useDict('receipt_payment_type') |
| | | |
| | | // 转æ¢åå
¸æ°æ®æ ¼å¼ä¸ºéæ©å¨éè¦çæ ¼å¼ |
| | | const receipt_payment_type = computed(() => { |
| | | return dictReceiptPaymentType.value.map(item => ({ |
| | | text: item.label, |
| | | value: item.value |
| | | })) |
| | | }) |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const onClickLeft = () => { |
| | | uni.removeStorageSync('invoiceLedgerEditRow'); |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // æ¾ç¤ºä»æ¬¾æ¹å¼éæ©å¨ |
| | | const showPaymentTypePicker = () => { |
| | | showPaymentType.value = true |
| | | } |
| | | const changeNum = () => { |
| | | if (form.value.currentPaymentAmount > currentNoReceiptAmount.value) { |
| | | form.value.currentPaymentAmount = currentNoReceiptAmount.value |
| | | showToast('ä¸å¯å¤§äºå¾
仿¬¾éé¢') |
| | | } |
| | | } |
| | | |
| | | // ç¡®è®¤ä»æ¬¾æ¹å¼éæ© |
| | | const onPaymentTypeConfirm = ({ selectedValues, selectedOptions }) => { |
| | | form.value.receiptPaymentType = selectedOptions[0].value |
| | | form.value.paymentMethod = selectedOptions[0].text |
| | | pickerValue.value = selectedValues; |
| | | showPaymentType.value = false |
| | | } |
| | | |
| | | // æ¾ç¤ºæ¥æéæ©å¨ |
| | | const showDatePicker = () => { |
| | | showDate.value = true |
| | | } |
| | | |
| | | // ç¡®è®¤æ¥æéæ© |
| | | const onDateConfirm = ({ selectedValues }) => { |
| | | form.value.paymentDate = selectedValues.join('-') |
| | | currentDate.value = selectedValues |
| | | showDate.value = false |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const onSubmit = () => { |
| | | // 表åéªè¯ |
| | | if (!form.value.currentPaymentAmount) { |
| | | showNotify({ type: 'warning', message: '请è¾å
¥ä»æ¬¾éé¢' }) |
| | | return |
| | | } |
| | | if (!form.value.receiptPaymentType) { |
| | | showNotify({ type: 'warning', message: 'è¯·éæ©ä»æ¬¾å½¢å¼' }) |
| | | return |
| | | } |
| | | if (!form.value.paymentDate) { |
| | | showNotify({ type: 'warning', message: 'è¯·éæ©ä»æ¬¾æ¥æ' }) |
| | | return |
| | | } |
| | | loading.value = true |
| | | paymentRegistrationAdd(form.value) |
| | | .then(() => { |
| | | showToast('æäº¤æå') |
| | | onClickLeft() |
| | | }) |
| | | .catch((error) => { |
| | | loading.value = false |
| | | }) |
| | | } |
| | | |
| | | // åå§åæ°æ® |
| | | const initData = () => { |
| | | const rowStr = uni.getStorageSync('invoiceLedgerEditRow') |
| | | const row = JSON.parse(rowStr) |
| | | form.value = { ...row }; |
| | | form.value.ticketRegistrationId = row.id; |
| | | form.value.id = null; |
| | | form.value.id = ""; |
| | | currentNoReceiptAmount.value = row.unPaymentAmountTotal |
| | | form.value.registrant = userStore.nickName |
| | | form.value.registrationtDate = getCurrentDate(); |
| | | form.value.paymentDate = getCurrentDate(); |
| | | } |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | onMounted(() => { |
| | | initData() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .account-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 6.375rem; |
| | | background: #C7C9CC; |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .save-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 14rem; |
| | | background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | // ååºå¼è°æ´ |
| | | @media (max-width: 768px) { |
| | | .submit-section { |
| | | padding: 12px; |
| | | } |
| | | } |
| | | .tip-text { padding: 4px 16px 0 16px; font-size: 12px; color: #888; } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="account-detail"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="æ°å¢ä»æ¬¾" @back="onClickLeft" /> |
| | | |
| | | <!-- 表åå
容 --> |
| | | <van-form @submit="onSubmit" ref="formRef" label-width="110px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <van-cell-group title="åºæ¬ä¿¡æ¯" inset> |
| | | <van-field |
| | | v-model="form.purchaseContractNumber" |
| | | label="éè´ååå·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.supplierName" |
| | | label="ä¾åºååç§°" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.invoiceNumber" |
| | | label="å票å·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.invoiceAmount" |
| | | label="å票éé¢(å
)" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <view class="tip-text">å¾
仿¬¾éé¢ï¼{{ currentNoReceiptAmount }} å
</view> |
| | | <van-field |
| | | v-model="form.currentPaymentAmount" |
| | | label="æ¬æ¬¡ä»æ¬¾éé¢" |
| | | type="number" |
| | | placeholder="请è¾å
¥" |
| | | @blur="changeNum" |
| | | :rules="[{ required: true, message: '请è¾å
¥ä»æ¬¾éé¢' }]" |
| | | clearable |
| | | /> |
| | | <van-field |
| | | v-model="form.paymentMethod" |
| | | label="仿¬¾å½¢å¼" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | @click="showPaymentTypePicker" |
| | | :rules="[{ required: true, message: 'è¯·éæ©ä»æ¬¾å½¢å¼' }]" |
| | | /> |
| | | <van-field |
| | | v-model="form.paymentDate" |
| | | label="仿¬¾æ¥æ" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | @click="showDatePicker" |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ¥æ¬¾æ¥æ' }]" |
| | | /> |
| | | </van-cell-group> |
| | | |
| | | <!-- æäº¤æé® --> |
| | | <view class="footer-btns"> |
| | | <van-button class="cancel-btn" @click="onClickLeft">åæ¶</van-button> |
| | | <van-button class="save-btn" native-type="submit" form-type="submit" :loading="loading">ä¿å</van-button> |
| | | </view> |
| | | </van-form> |
| | | |
| | | <!-- 仿¬¾æ¹å¼éæ©å¨ --> |
| | | <van-popup v-model:show="showPaymentType" position="bottom"> |
| | | <van-picker |
| | | :model-value="pickerValue" |
| | | :columns="receipt_payment_type" |
| | | @confirm="onPaymentTypeConfirm" |
| | | @cancel="showPaymentType = false" |
| | | /> |
| | | </van-popup> |
| | | |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <van-popup v-model:show="showDate" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentDate" |
| | | title="éæ©æ¥æ" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDate = false" |
| | | /> |
| | | </van-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { receiptPaymentSaveOrUpdate, invoiceInfo } from '@/api/salesManagement/receiptPayment' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { showToast, showNotify } from 'vant' |
| | | import { useDict } from '@/utils/dict' |
| | | import {paymentRegistrationAdd, paymentRegistrationEdit} from "@/api/procurementManagement/paymentEntry"; |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // 表åå¼ç¨ |
| | | const formRef = ref() |
| | | |
| | | // ååºå¼æ°æ® |
| | | const loading = ref(false) |
| | | const showPaymentType = ref(false) |
| | | const pickerValue = ref([]) |
| | | const showDate = ref(false) |
| | | const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | purchaseContractNumber: '', |
| | | salesContractNo: '', |
| | | supplierName: '', |
| | | invoiceNumber: '', |
| | | invoiceAmount: '', |
| | | taxRate: '', |
| | | currentPaymentAmount: '', |
| | | receiptPaymentType: '', |
| | | paymentMethod: '', |
| | | registrant: '', |
| | | paymentDate: '', |
| | | registrationtDate: '', |
| | | ticketRegistrationId: '' |
| | | }) |
| | | const currentNoReceiptAmount = ref(0) |
| | | const operationType = ref('') |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { receipt_payment_type: dictReceiptPaymentType } = useDict('receipt_payment_type') |
| | | |
| | | // 转æ¢åå
¸æ°æ®æ ¼å¼ä¸ºéæ©å¨éè¦çæ ¼å¼ |
| | | const receipt_payment_type = computed(() => { |
| | | return dictReceiptPaymentType.value.map(item => ({ |
| | | text: item.label, |
| | | value: item.value |
| | | })) |
| | | }) |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const onClickLeft = () => { |
| | | uni.removeStorageSync('invoiceLedgerEditRow'); |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // æ¾ç¤ºä»æ¬¾æ¹å¼éæ©å¨ |
| | | const showPaymentTypePicker = () => { |
| | | showPaymentType.value = true |
| | | } |
| | | const changeNum = () => { |
| | | if (form.value.currentPaymentAmount > currentNoReceiptAmount.value) { |
| | | form.value.currentPaymentAmount = currentNoReceiptAmount.value |
| | | showToast('ä¸å¯å¤§äºå¾
仿¬¾éé¢') |
| | | } |
| | | } |
| | | |
| | | // ç¡®è®¤ä»æ¬¾æ¹å¼éæ© |
| | | const onPaymentTypeConfirm = ({ selectedValues, selectedOptions }) => { |
| | | form.value.receiptPaymentType = selectedOptions[0].value |
| | | form.value.paymentMethod = selectedOptions[0].text |
| | | pickerValue.value = selectedValues; |
| | | showPaymentType.value = false |
| | | } |
| | | |
| | | // æ¾ç¤ºæ¥æéæ©å¨ |
| | | const showDatePicker = () => { |
| | | showDate.value = true |
| | | } |
| | | |
| | | // ç¡®è®¤æ¥æéæ© |
| | | const onDateConfirm = ({ selectedValues }) => { |
| | | form.value.paymentDate = selectedValues.join('-') |
| | | currentDate.value = selectedValues |
| | | showDate.value = false |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const onSubmit = () => { |
| | | // 表åéªè¯ |
| | | if (!form.value.currentPaymentAmount) { |
| | | showNotify({ type: 'warning', message: '请è¾å
¥ä»æ¬¾éé¢' }) |
| | | return |
| | | } |
| | | if (!form.value.receiptPaymentType) { |
| | | showNotify({ type: 'warning', message: 'è¯·éæ©ä»æ¬¾å½¢å¼' }) |
| | | return |
| | | } |
| | | loading.value = true |
| | | paymentRegistrationEdit(form.value) |
| | | .then(() => { |
| | | showToast('æäº¤æå') |
| | | onClickLeft() |
| | | }) |
| | | .catch((error) => { |
| | | loading.value = false |
| | | }) |
| | | } |
| | | |
| | | // åå§åæ°æ® |
| | | const initData = () => { |
| | | const rowStr = uni.getStorageSync('invoiceLedgerEditRow') |
| | | const row = JSON.parse(rowStr) |
| | | form.value = { ...row }; |
| | | form.value.ticketRegistrationId = row.id; |
| | | form.value.id = ""; |
| | | if (operationType.value === 'add') { |
| | | currentNoReceiptAmount.value = row.unPaymentAmountTotal |
| | | form.value.registrant = userStore.nickName |
| | | form.value.registrationtDate = getCurrentDate(); |
| | | form.value.paymentDate = getCurrentDate(); |
| | | } |
| | | } |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | onMounted(() => { |
| | | operationType.value = uni.getStorageSync('operationType') || ''; |
| | | initData() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .account-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 6.375rem; |
| | | background: #C7C9CC; |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .save-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 14rem; |
| | | background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | // ååºå¼è°æ´ |
| | | @media (max-width: 768px) { |
| | | .submit-section { |
| | | padding: 12px; |
| | | } |
| | | } |
| | | .tip-text { padding: 4px 16px 0 16px; font-size: 12px; color: #888; } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="receipt-payment"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="仿¬¾ç»è®°" @back="goBack" /> |
| | | |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-filter-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <input |
| | | class="search-text" |
| | | placeholder="ä¾åºååç§°/ååå·" |
| | | v-model="searchForm.supplierNameOrContractNo" |
| | | confirm-type="search" |
| | | /> |
| | | </view> |
| | | <view class="filter-button" @click="getList"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- çéå¼å
³ --> |
| | | <view class="switch-row"> |
| | | <text class="switch-label">䏿¾ç¤ºå¾
仿¬¾ä¸º0</text> |
| | | <van-switch v-model="searchForm.status" @change="getList" size="18"/> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | |
| | | <!-- å表åºå --> |
| | | <view class="ledger-list" v-if="tableData.length > 0"> |
| | | <view v-for="(item, index) in tableData" :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.purchaseContractNumber }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">éå®ååå·</text> |
| | | <text class="detail-value">{{ item.salesContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¾åºååç§°</text> |
| | | <text class="detail-value">{{ item.supplierName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å票å·</text> |
| | | <text class="detail-value">{{ item.invoiceNumber }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å票éé¢(å
)</text> |
| | | <text class="detail-value">{{ item.invoiceAmount }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">已仿¬¾éé¢(å
)</text> |
| | | <text class="detail-value">{{ item.paymentAmountTotal || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¾
仿¬¾éé¢(å
)</text> |
| | | <text class="detail-value highlight">{{ formatNumber(item.unPaymentAmountTotal) }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- æä½æé® --> |
| | | <view class="action-buttons"> |
| | | <van-button |
| | | type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.unPaymentAmountTotal == 0" |
| | | @click="openForm('add', item)" |
| | | > |
| | | æ°å¢ä»æ¬¾ |
| | | </van-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- æ æ°æ®æç¤º --> |
| | | <view class="no-data" v-else> |
| | | <text>ææ ä»æ¬¾æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { showToast } from 'vant' |
| | | import {onShow} from "@dcloudio/uni-app"; |
| | | import {invoiceListPage} from "@/api/procurementManagement/procurementInvoiceLedger"; |
| | | |
| | | // ååºå¼æ°æ® |
| | | const tableData = ref([]) |
| | | const tableLoading = ref(false) |
| | | |
| | | // æ¥è¯¢åæ°è®¾ç½®ä¸º-1è·åå
¨é¨æ°æ® |
| | | const page = ref({ |
| | | current: -1, |
| | | size: -1 |
| | | }) |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = ref({ |
| | | supplierNameOrContractNo: '', |
| | | status: true, |
| | | customerName: '', |
| | | customerContractNo: '', |
| | | projectName: '' |
| | | }) |
| | | |
| | | // æ ¼å¼åæ°å |
| | | const formatNumber = (value) => { |
| | | return parseFloat(value || 0).toFixed(2) |
| | | } |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // è·ååè¡¨æ°æ® |
| | | const getList = () => { |
| | | tableLoading.value = true |
| | | invoiceListPage({ ...searchForm.value, ...page.value }).then((res) => { |
| | | tableLoading.value = false |
| | | tableData.value = res.records || [] |
| | | }).catch(() => { |
| | | tableLoading.value = false |
| | | }) |
| | | } |
| | | |
| | | // æå¼æ°å¢è¡¨å |
| | | const openForm = (type, item) => { |
| | | if (item.unPaymentAmountTotal == 0) { |
| | | showToast('æ éå仿¬¾') |
| | | return |
| | | } |
| | | uni.setStorageSync('operationType', type); |
| | | uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item)) |
| | | uni.navigateTo({ url: '/pages/procurementManagement/paymentEntry/add' }) |
| | | } |
| | | |
| | | onShow(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | .receipt-payment { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | } |
| | | |
| | | .search-filter-section { |
| | | padding: 10px 20px; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | background: #f5f5f5; |
| | | border-radius: 24px; |
| | | padding: 10px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-text { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #333; |
| | | background: transparent; |
| | | border: none; |
| | | outline: none; |
| | | } |
| | | |
| | | .search-text::placeholder { |
| | | color: #999; |
| | | } |
| | | |
| | | .filter-button { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .switch-row { |
| | | padding: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .switch-label { |
| | | font-size: 14px; |
| | | color: #333; |
| | | } |
| | | |
| | | |
| | | |
| | | .ledger-list { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .ledger-item { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | padding: 0 16px; |
| | | } |
| | | |
| | | .item-header { |
| | | padding: 16px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #2979ff; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | |
| | | |
| | | .item-details { |
| | | padding: 16px 0; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 12px; |
| | | color: #777777; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 12px; |
| | | color: #000000; |
| | | text-align: right; |
| | | flex: 1; |
| | | margin-left: 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | color: #ee0a24; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .children-list { |
| | | .children-title { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | color: #333; |
| | | padding: 12px 0 8px 0; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | } |
| | | |
| | | .child-item { |
| | | .child-details { |
| | | padding: 12px 0; |
| | | } |
| | | |
| | | .child-actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | padding: 8px 0 16px 0; |
| | | justify-content: flex-end; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | padding: 0 0 16px 0; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .no-data { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | color: #999; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="receipt-payment-detail"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="客æ·å¾æ¥è¯¦æ
" @back="goBack" /> |
| | | |
| | | <!-- ç»è®¡ä¿¡æ¯ --> |
| | | <view class="summary-info" v-if="tableData.length > 0"> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">æ»è®°å½æ°</text> |
| | | <text class="summary-value">{{ tableData.length }}</text> |
| | | </view> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">å¼ç¥¨æ»éé¢</text> |
| | | <text class="summary-value">{{ formatAmount(invoiceTotal) }}</text> |
| | | </view> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">忬¾æ»éé¢</text> |
| | | <text class="summary-value highlight">{{ formatAmount(receiptTotal) }}</text> |
| | | </view> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">åºæ¶æ»éé¢</text> |
| | | <text class="summary-value danger">{{ formatAmount(unReceiptTotal) }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 忬¾è®°å½æç»å表 --> |
| | | <view class="detail-list" v-if="tableData.length > 0"> |
| | | <view v-for="(item, index) in tableData" :key="index" class="detail-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="record-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-index">{{ index + 1 }}</text> |
| | | </view> |
| | | <view class="item-date">{{ item.happenTime }}</view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å票éé¢(å
)</text> |
| | | <text class="detail-value">{{ formatAmount(item.invoiceAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">仿¬¾éé¢(å
)</text> |
| | | <text class="detail-value highlight">{{ formatAmount(item.currentPaymentAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åºä»éé¢(å
)</text> |
| | | <text class="detail-value danger">{{ formatAmount(item.payableAmount) }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="no-data"> |
| | | <text>ææ åæ¬¾è®°å½</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted } from 'vue'; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import {paymentLedgerList} from "@/api/procurementManagement/paymentLedger"; |
| | | |
| | | // 客æ·ä¿¡æ¯ |
| | | const supplierId = ref(''); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | |
| | | const invoiceTotal = computed(() => { |
| | | return tableData.value.reduce((sum, item) => { |
| | | return sum + (parseFloat(item.invoiceAmount) || 0); |
| | | }, 0); |
| | | }); |
| | | |
| | | const receiptTotal = computed(() => { |
| | | return tableData.value.reduce((sum, item) => { |
| | | return sum + (parseFloat(item.receiptAmount) || 0); |
| | | }, 0); |
| | | }); |
| | | |
| | | const unReceiptTotal = computed(() => { |
| | | return tableData.value.reduce((sum, item) => { |
| | | return sum + (parseFloat(item.unReceiptAmount) || 0); |
| | | }, 0); |
| | | }); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // è·å页é¢åæ° |
| | | const getPageParams = () => { |
| | | const pages = getCurrentPages(); |
| | | const currentPage = pages[pages.length - 1]; |
| | | const options = currentPage.options; |
| | | |
| | | if (options.supplierId) { |
| | | supplierId.value = options.supplierId; |
| | | } |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | if (!supplierId.value) { |
| | | uni.showToast({ |
| | | title: '客æ·ä¿¡æ¯ç¼ºå¤±', |
| | | icon: 'error' |
| | | }); |
| | | return; |
| | | } |
| | | const param = { |
| | | supplierId: supplierId.value, |
| | | }; |
| | | paymentLedgerList(param).then((res) => { |
| | | tableData.value = res.data; |
| | | }).catch(() => { |
| | | uni.showToast({ |
| | | title: 'æ¥è¯¢å¤±è´¥', |
| | | icon: 'error' |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // æ ¼å¼åéé¢ |
| | | const formatAmount = (amount) => { |
| | | return amount ? parseFloat(amount).toFixed(2) : '0.00'; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // 页é¢å è½½æ¶è·ååæ°å¹¶å·æ°å表 |
| | | getPageParams(); |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .receipt-payment-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | } |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | .summary-info { |
| | | background: #ffffff; |
| | | margin: 20px 20px 0 20px; |
| | | border-radius: 12px; |
| | | padding: 16px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .summary-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .summary-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | |
| | | .summary-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .summary-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .summary-value.danger { |
| | | color: #ff4757; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .detail-list { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .detail-item { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | padding: 0 16px; |
| | | } |
| | | |
| | | .item-header { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .record-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #2979ff; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-index { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .item-date { |
| | | font-size: 12px; |
| | | color: #666; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 16px 0; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 12px; |
| | | color: #777777; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 12px; |
| | | color: #000000; |
| | | text-align: right; |
| | | flex: 1; |
| | | margin-left: 16px; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | color: #ff4757; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .no-data { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | color: #999; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="receipt-payment-ledger"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¾åºå徿¥" @back="goBack" /> |
| | | |
| | | <!-- æç´¢åºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <input |
| | | class="search-text" |
| | | placeholder="请è¾å
¥ä¾åºååç§°" |
| | | v-model="searchForm.searchText" |
| | | @input="handleQuery" |
| | | /> |
| | | </view> |
| | | <view class="search-button" @click="handleQuery"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- ä¾åºåå表 --> |
| | | <view class="customer-list-container"> |
| | | <view class="customer-list" v-if="tableData.length > 0"> |
| | | <view |
| | | v-for="(item, index) in tableData" |
| | | :key="item.id" |
| | | class="customer-item" |
| | | @click="rowClickMethod(item)" |
| | | > |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="customer-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="customer-name">{{ item.supplierName }}</text> |
| | | </view> |
| | | <view class="item-right"> |
| | | <up-icon name="arrow-right" size="16" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å票éé¢(å
)</text> |
| | | <text class="detail-value">{{ formattedNumber(item.invoiceAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">仿¬¾éé¢(å
)</text> |
| | | <text class="detail-value">{{ formattedNumber(item.receiptPaymentAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åºä»éé¢(å
)</text> |
| | | <text class="detail-value highlight danger">{{ formattedNumber(item.payableAmount) }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="no-data"> |
| | | <text>ææ ä¾åºåæ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, toRefs } from "vue"; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import {paymentLedgerList} from "@/api/procurementManagement/paymentLedger"; |
| | | |
| | | |
| | | const tableData = ref([]); |
| | | |
| | | const page = reactive({ |
| | | current: -1, |
| | | size: -1, |
| | | }); |
| | | |
| | | |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | searchText: "", |
| | | invoiceDate: "", |
| | | }, |
| | | }); |
| | | |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const handleQuery = () => { |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | paymentLedgerList({ ...searchForm.value, ...page }).then((res) => { |
| | | tableData.value = res.data.records; |
| | | }).catch(() => { |
| | | uni.showToast({ |
| | | title: 'æ¥è¯¢å¤±è´¥', |
| | | icon: 'error' |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const formattedNumber = (value) => { |
| | | return parseFloat(value || 0).toFixed(2); |
| | | }; |
| | | |
| | | |
| | | |
| | | const rowClickMethod = (row) => { |
| | | // 跳转å°åæ¬¾è®°å½æç»é¡µé¢ |
| | | uni.navigateTo({ |
| | | url: `/pages/procurementManagement/paymentLedger/detail?supplierId=${row.supplierId}` |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | .receipt-payment-ledger { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | } |
| | | |
| | | .search-section { |
| | | padding: 10px 20px; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | background: #f5f5f5; |
| | | border-radius: 24px; |
| | | padding: 10px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-text { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #333; |
| | | background: transparent; |
| | | border: none; |
| | | outline: none; |
| | | } |
| | | |
| | | .search-text::placeholder { |
| | | color: #999; |
| | | } |
| | | |
| | | .search-button { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .customer-list-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .customer-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .customer-item { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | padding: 0 16px; |
| | | transition: all 0.3s ease; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); |
| | | } |
| | | } |
| | | |
| | | .item-header { |
| | | padding: 16px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .item-right { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .customer-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #2979ff; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .customer-name { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .item-index { |
| | | font-size: 12px; |
| | | color: #999; |
| | | background: #f5f5f5; |
| | | padding: 2px 8px; |
| | | border-radius: 12px; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 16px 0; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 12px; |
| | | color: #777777; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 12px; |
| | | color: #000000; |
| | | text-align: right; |
| | | flex: 1; |
| | | margin-left: 16px; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | color: #ff4757; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .no-data { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | color: #999; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="account-detail"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ç¼è¾æ¥ç¥¨å°è´¦" @back="goBack" /> |
| | | |
| | | <van-form @submit="submitForm" ref="formRef" label-width="120px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center"> |
| | | <van-cell-group title="åºæ¬ä¿¡æ¯" inset> |
| | | <van-field v-model="form.purchaseContractNumber" label="éè´ååå·" readonly /> |
| | | <van-field v-model="form.salesContractNo" label="éå®ååå·" readonly /> |
| | | <van-field v-model="form.taxInclusiveUnitPrice" label="å«ç¨åä»·(å
)" readonly /> |
| | | <van-field v-model="form.createdAt" label="å建æ¶é´" readonly /> |
| | | <van-field v-model="form.invoiceNumber" label="å票å·" placeholder="请è¾å
¥" readonly /> |
| | | <van-field v-model="form.ticketsNum" label="æ¥ç¥¨æ°" type="number" placeholder="请è¾å
¥" required :rules="[{ required: true, message: '请è¾å
¥æ¥ç¥¨æ°' }]" @change="inputTicketsNum"/> |
| | | <van-field v-model="form.ticketsAmount" label="æ¬æ¬¡æ¥ç¥¨éé¢(å
)" type="number" placeholder="请è¾å
¥" required :rules="[{ required: true, message: '请è¾å
¥æ¬æ¬¡æ¥ç¥¨éé¢' }]" @change="inputTicketsAmount"/> |
| | | <view class="tip-text">æªæ¥ç¥¨æ°ï¼{{ formatAmount(form.futureTickets) }} å
</view> |
| | | <!-- <van-field v-model="form.invoicePerson" label="æªæ¥ç¥¨æ°" readonly />--> |
| | | </van-cell-group> |
| | | |
| | | <!-- <van-cell-group title="éä»¶ææï¼ä»
æ¯æ pdfï¼" inset>--> |
| | | <!-- <van-uploader--> |
| | | <!-- accept=".pdf"--> |
| | | <!-- multiple--> |
| | | <!-- :after-read="afterReadUpload"--> |
| | | <!-- :before-read="beforeReadPdf"--> |
| | | <!-- >--> |
| | | <!-- <van-button class="upload-btn" icon="plus" type="primary" block>ä¸ä¼ æä»¶</van-button>--> |
| | | <!-- </van-uploader>--> |
| | | <!-- <view class="uploaded-list" v-if="fileList.length">--> |
| | | <!-- <view class="uploaded-item" v-for="(f, idx) in fileList" :key="idx">--> |
| | | <!-- <text class="file-name">{{ f.name || getFileNameFromUrl(f.url) }}</text>--> |
| | | <!-- <van-button size="mini" type="danger" plain @click="removeUploaded(idx)">ç§»é¤</van-button>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- </van-cell-group>--> |
| | | |
| | | <view class="footer-btns"> |
| | | <van-button class="cancel-btn" @click="goBack">åæ¶</van-button> |
| | | <van-button class="save-btn" native-type="submit" form-type="submit">ä¿å</van-button> |
| | | </view> |
| | | </van-form> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from 'vue' |
| | | import { showToast, showLoadingToast, closeToast } from 'vant' |
| | | import dayjs from 'dayjs' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { getToken } from '@/utils/auth' |
| | | import { invoiceLedgerSaveOrUpdate } from '@/api/salesManagement/invoiceLedger.js' |
| | | import config from '@/config.js' |
| | | import {getProductRecordById, updateRegistration} from "@/api/procurementManagement/procurementInvoiceLedger"; |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | const formRef = ref() |
| | | let form = ref({ |
| | | salesLedgerId: '', |
| | | customerId: '', |
| | | invoiceNo: '', |
| | | invoiceTotal: '', |
| | | taxRate: '', |
| | | invoicePerson: '', |
| | | invoiceDate: '', |
| | | customerName: '', |
| | | fileList: [], |
| | | createTime: '', |
| | | taxInclusiveTotalPrice: '', |
| | | taxInclusiveUnitPrice: '' |
| | | }) |
| | | const fileList = ref([]) |
| | | const currentId = ref('') |
| | | const temFutureTickets = ref(0) |
| | | |
| | | // æ¥æéæ© |
| | | const currentInvoiceDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync('invoiceLedgerEditRow'); |
| | | uni.navigateBack() |
| | | } |
| | | const inputTicketsNum = (val) => { |
| | | // ç¡®ä¿å«ç¨åä»·åå¨ä¸ä¸ä¸ºé¶ |
| | | if (!form.value.taxInclusiveUnitPrice || Number(form.value.taxInclusiveUnitPrice) === 0) { |
| | | showToast("å«ç¨åä»·ä¸è½ä¸ºé¶ææªå®ä¹"); |
| | | return; |
| | | } |
| | | if (Number(form.value.ticketsNum) > Number(temFutureTickets.value)) { |
| | | showToast("æ¥ç¥¨æ°ä¸å¾å¤§äºæªæ¥ç¥¨æ°"); |
| | | form.value.ticketsNum = temFutureTickets.value |
| | | } |
| | | |
| | | // ç¡®ä¿æææ°å¼é½è½¬æ¢ä¸ºæ°åç±»åè¿è¡è®¡ç® |
| | | const ticketsAmount = Number(form.value.ticketsNum) * Number(form.value.taxInclusiveUnitPrice); |
| | | const futureTickets = Number(temFutureTickets.value) - Number(form.value.ticketsNum); |
| | | form.value.futureTickets = Number(futureTickets.toFixed(2)); |
| | | form.value.ticketsAmount = Number(ticketsAmount.toFixed(2)); |
| | | }; |
| | | const inputTicketsAmount = (val) => { |
| | | // ç¡®ä¿å«ç¨åä»·åå¨ä¸ä¸ä¸ºé¶ |
| | | if (!form.value.taxInclusiveUnitPrice || Number(form.value.taxInclusiveUnitPrice) === 0) { |
| | | showToast("å«ç¨åä»·ä¸è½ä¸ºé¶ææªå®ä¹"); |
| | | return; |
| | | } |
| | | |
| | | if (Number(val) > Number(form.value.futureTickets*form.value.taxInclusiveUnitPrice)) { |
| | | showToast("æ¬æ¬¡æ¥ç¥¨éé¢ä¸å¾å¤§äºæ»éé¢"); |
| | | form.value.ticketsAmount = (form.value.futureTickets*form.value.taxInclusiveUnitPrice).toFixed(2) |
| | | const ticketsNum = Number(form.value.ticketsAmount) / Number(form.value.taxInclusiveUnitPrice); |
| | | form.value.ticketsNum = Number(ticketsNum.toFixed(2)) |
| | | return; |
| | | } |
| | | |
| | | // ç¡®ä¿æææ°å¼é½è½¬æ¢ä¸ºæ°åç±»åè¿è¡è®¡ç® |
| | | const ticketsNum = Number(val) / Number(form.value.taxInclusiveUnitPrice); |
| | | form.value.ticketsNum = Number(ticketsNum.toFixed(2)); |
| | | }; |
| | | const formatAmount = (val) => { |
| | | if (val === undefined || val === null || val === '') return '0.00' |
| | | const num = Number(val) |
| | | if (Number.isNaN(num)) return '0.00' |
| | | return num.toFixed(2) |
| | | } |
| | | |
| | | // ä¸ä¼ åæ ¡éªï¼å
¼å®¹ Vant Uploader ç file/fileList ç»æï¼ |
| | | const beforeReadPdf = (file) => { |
| | | const items = Array.isArray(file) ? file : [file] |
| | | for (const it of items) { |
| | | const raw = it?.file || it |
| | | const fileName = raw?.name || it?.name || '' |
| | | const ext = fileName.split('.').pop()?.toLowerCase() |
| | | const sizeOk = (raw?.size || 0) <= 10 * 1024 * 1024 |
| | | if (ext !== 'pdf') { |
| | | showToast('ä»
æ¯æpdfæä»¶') |
| | | return false |
| | | } |
| | | if (!sizeOk) { |
| | | showToast('ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿10MB') |
| | | return false |
| | | } |
| | | } |
| | | return true |
| | | } |
| | | |
| | | const uploadSingleFile = async (fileObj) => { |
| | | return new Promise((resolve, reject) => { |
| | | showLoadingToast({ message: 'æ£å¨ä¸ä¼ ...' }) |
| | | const baseUrl = config.baseUrl + '/invoiceLedger/uploadFile' |
| | | |
| | | const filePath = fileObj?.url || fileObj?.tempFilePath || fileObj?.file?.path |
| | | if (filePath) { |
| | | uni.uploadFile({ |
| | | url: baseUrl, |
| | | filePath, |
| | | name: 'file', |
| | | header: { Authorization: 'Bearer ' + getToken() }, |
| | | success: (res) => { |
| | | closeToast() |
| | | try { |
| | | const data = JSON.parse(res.data || '{}') |
| | | if (data.code === 200) { |
| | | resolve(data.data) |
| | | } else { |
| | | reject(new Error(data.msg || 'ä¸ä¼ 失败')) |
| | | } |
| | | } catch (err) { |
| | | reject(err) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | closeToast() |
| | | reject(err) |
| | | } |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // H5: 使ç¨åå§ Fileï¼input éæ©ï¼ |
| | | const rawFile = fileObj?.file |
| | | if (rawFile) { |
| | | // uni.uploadFile å¨ H5 䏿¯æåç File 对象ï¼è¿éç¨ fetch åé FormData |
| | | const formData = new FormData() |
| | | formData.append('file', rawFile, rawFile.name || 'file.pdf') |
| | | formData.append('salesLedgerId', form.value.salesLedgerId || currentId.value || '') |
| | | fetch(baseUrl, { |
| | | method: 'POST', |
| | | headers: { Authorization: 'Bearer ' + getToken() }, |
| | | body: formData |
| | | }).then(async (res) => { |
| | | closeToast() |
| | | const data = await res.json() |
| | | if (data.code === 200) { |
| | | resolve(data.data) |
| | | } else { |
| | | reject(new Error(data.msg || 'ä¸ä¼ 失败')) |
| | | } |
| | | }).catch((err) => { |
| | | closeToast() |
| | | reject(err) |
| | | }) |
| | | return |
| | | } |
| | | |
| | | closeToast() |
| | | reject(new Error('æªæ¾å°å¯ä¸ä¼ çæä»¶')) |
| | | }) |
| | | } |
| | | |
| | | const afterReadUpload = async (file) => { |
| | | try { |
| | | const files = Array.isArray(file) ? file : file?.file ? [file] : [file] |
| | | for (const f of files) { |
| | | const uploaded = await uploadSingleFile(f) |
| | | fileList.value.push(uploaded) |
| | | } |
| | | showToast('ä¸ä¼ æå') |
| | | } catch (e) { |
| | | showToast('ä¸ä¼ 失败') |
| | | } |
| | | } |
| | | |
| | | const removeUploaded = (index) => { |
| | | fileList.value.splice(index, 1) |
| | | } |
| | | |
| | | const getFileNameFromUrl = (url) => { |
| | | try { if (!url) return ''; return decodeURIComponent(url.split('/').pop()) } catch (e) { return url } |
| | | } |
| | | |
| | | const loadDetail = async (id) => { |
| | | try { |
| | | showLoadingToast({ message: 'å è½½ä¸...' }) |
| | | const res = await getProductRecordById({ id }) |
| | | const data = res?.data || res |
| | | form.value = { ...data } |
| | | temFutureTickets.value = data.futureTickets; |
| | | fileList.value = data?.fileList || [] |
| | | if (!form.value.invoicePerson) { |
| | | form.value.invoicePerson = userStore.nickName |
| | | } |
| | | if (!form.value.invoiceDate) { |
| | | form.value.invoiceDate = dayjs().format('YYYY-MM-DD') |
| | | } |
| | | closeToast() |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('å 载失败') |
| | | } |
| | | } |
| | | |
| | | const submitForm = async () => { |
| | | try { |
| | | showLoadingToast({ message: 'æäº¤ä¸...' }) |
| | | await updateRegistration(form.value) |
| | | closeToast() |
| | | showToast('æäº¤æå') |
| | | setTimeout(() => { goBack() }, 800) |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('æäº¤å¤±è´¥ï¼è¯·éè¯') |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | const rowStr = uni.getStorageSync('invoiceLedgerEditRow') |
| | | if (rowStr) { |
| | | try { |
| | | const row = JSON.parse(rowStr) |
| | | currentId.value = row.id |
| | | loadDetail(currentId.value) |
| | | } catch (e) { |
| | | // ignore |
| | | } |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .account-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | .uploaded-list { padding: 8px 16px 0 16px; } |
| | | .uploaded-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #f5f5f5; } |
| | | .file-name { font-size: 12px; color: #333; margin-right: 8px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| | | .tip-text { padding: 4px 16px 0 16px; font-size: 12px; color: #888; } |
| | | .footer-btns { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; display: flex; justify-content: space-around; align-items: center; padding: 0.75rem 0; box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); z-index: 1000; } |
| | | .cancel-btn { font-weight: 400; font-size: 1rem; color: #FFFFFF; width: 6.375rem; background: #C7C9CC; box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; } |
| | | .save-btn { font-weight: 400; font-size: 1rem; color: #FFFFFF; width: 14rem; background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; } |
| | | </style> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="æ¥ç¥¨å°è´¦" @back="goBack" /> |
| | | |
| | | <!-- æç´¢åçéåºåï¼ä¿æä¸éå®å°è´¦é£æ ¼ä¸è´ï¼ --> |
| | | <view class="search-filter-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <input |
| | | class="search-text" |
| | | placeholder="ä¾åºååç§°/éè´ååå·" |
| | | v-model="searchForm.searchText" |
| | | confirm-type="search" |
| | | @confirm="handleQuery" |
| | | /> |
| | | </view> |
| | | <!-- <view class="filter-button" @click="showFilter = true">--> |
| | | <!-- <up-icon name="list" size="24" color="#999"></up-icon>--> |
| | | <!-- </view>--> |
| | | <view class="filter-button" @click="handleQuery"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- å表åºå --> |
| | | <view class="ledger-list" v-if="total > 0"> |
| | | <view v-for="(item, index) in ledgerList" :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.purchaseContractNumber }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">éå®ååå·</text> |
| | | <text class="detail-value">{{ item.salesContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项ç®åç§°</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¾åºååç§°</text> |
| | | <text class="detail-value">{{ item.supplierName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产å大类</text> |
| | | <text class="detail-value">{{ item.productCategory }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">è§æ ¼åå·</text> |
| | | <text class="detail-value">{{ item.specificationModel }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å票å·</text> |
| | | <text class="detail-value">{{ item.invoiceNumber || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ååéé¢(å
)</text> |
| | | <text class="detail-value">{{ item.taxInclusiveTotalPrice || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ¥ç¥¨æ¥æ</text> |
| | | <text class="detail-value">{{ item.createdAt || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ¥ç¥¨éé¢(å
)</text> |
| | | <text class="detail-value highlight">{{ formatAmount(item.ticketsAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸å«ç¨éé¢(å
)</text> |
| | | <text class="detail-value highlight">{{ formatAmount(item.unTicketsPrice) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¢å¼ç¨</text> |
| | | <text class="detail-value">{{ item.invoiceAmount }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å½å
¥äºº</text> |
| | | <text class="detail-value">{{ item.issUer }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å½å
¥æ¥æ</text> |
| | | <text class="detail-value">{{ item.createdAt }}</text> |
| | | </view> |
| | | |
| | | </view> |
| | | <view class="action-buttons"> |
| | | <van-button |
| | | type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.issUer !== userStore.nickName" |
| | | @click="openEdit(item)" |
| | | > |
| | | ç¼è¾ |
| | | </van-button> |
| | | <van-button |
| | | type="danger" |
| | | size="small" |
| | | plain |
| | | class="action-btn" |
| | | :disabled="item.issUer !== userStore.nickName" |
| | | @click="handleDelete(item)" |
| | | > |
| | | å é¤ |
| | | </van-button> |
| | | <van-button |
| | | type="default" |
| | | size="small" |
| | | plain |
| | | class="action-btn" |
| | | v-if="item.invoiceFileName" |
| | | @click="openFileActions(item.commonFiles || [])" |
| | | > |
| | | æ¥çéä»¶ |
| | | </van-button> |
| | | <van-button |
| | | type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | v-else |
| | | :disabled="item.issUer !== userStore.nickName" |
| | | @click="openUpload(item)" |
| | | > |
| | | ä¸ä¼ |
| | | </van-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="no-data"> |
| | | <text>ææ æ¥ç¥¨å°è´¦æ°æ®</text> |
| | | </view> |
| | | |
| | | <!-- çéå¼¹çª --> |
| | | <van-popup v-model:show="showFilter" position="bottom" round> |
| | | <view class="filter-popup"> |
| | | <van-cell-group title="ç鿡件" inset> |
| | | <van-field |
| | | label="æ¥ç¥¨æ¥æ" |
| | | readonly |
| | | @click="showInvoiceRange = true" |
| | | :placeholder="invoiceRangeLabel || 'è¯·éæ©æ¥æèå´'" |
| | | /> |
| | | <van-field |
| | | label="å½å
¥æ¥æ" |
| | | readonly |
| | | @click="showCreateDatePicker = true" |
| | | :placeholder="searchForm.createTimeStart || 'è¯·éæ©å½å
¥æ¥æ'" |
| | | /> |
| | | <view class="switch-row"> |
| | | <text class="switch-label">䏿¾ç¤ºæå票è¡</text> |
| | | <van-switch v-model="searchForm.status" size="20" /> |
| | | </view> |
| | | </van-cell-group> |
| | | <view class="filter-actions"> |
| | | <van-button @click="resetFilter">éç½®</van-button> |
| | | <van-button type="primary" @click="confirmFilter">ç¡®å®</van-button> |
| | | </view> |
| | | </view> |
| | | </van-popup> |
| | | |
| | | <!-- æ¥åï¼æ¥ç¥¨æ¥æèå´ --> |
| | | <van-popup v-model:show="showInvoiceRange" position="bottom"> |
| | | <van-calendar |
| | | title="éæ©æ¥ç¥¨æ¥æèå´" |
| | | type="range" |
| | | color="#2979ff" |
| | | @confirm="onInvoiceRangeConfirm" |
| | | @cancel="showInvoiceRange = false" |
| | | /> |
| | | </van-popup> |
| | | |
| | | <!-- æ¥æï¼å½å
¥æ¥æ --> |
| | | <van-popup v-model:show="showCreateDatePicker" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentCreateDate" |
| | | title="éæ©å½å
¥æ¥æ" |
| | | @confirm="onCreateDateConfirm" |
| | | @cancel="showCreateDatePicker = false" |
| | | /> |
| | | </van-popup> |
| | | |
| | | |
| | | |
| | | <!-- åè¡ä¸ä¼ å¼¹çªï¼æ 表åï¼ --> |
| | | <van-popup v-model:show="showUpload" position="bottom" round> |
| | | <view class="upload-container"> |
| | | <van-cell-group title="ä¸ä¼ éä»¶ï¼ä»
æ¯æ pdfï¼æå¤§10MBï¼æå¤10个ï¼" inset> |
| | | <van-uploader |
| | | accept="*" |
| | | multiple |
| | | :max-count="10" |
| | | :after-read="afterReadRowUpload" |
| | | :before-read="beforeReadPdf" |
| | | /> |
| | | <view class="uploaded-list" v-if="fileList.length"> |
| | | <view class="uploaded-item" v-for="(f, idx) in fileList" :key="idx"> |
| | | <text class="file-name">{{ f.name || getFileNameFromUrl(f.url) }}</text> |
| | | <van-button size="mini" type="danger" plain @click="removeUploaded(idx)">ç§»é¤</van-button> |
| | | </view> |
| | | </view> |
| | | </van-cell-group> |
| | | <view class="filter-actions"> |
| | | <van-button @click="showUpload = false">åæ¶</van-button> |
| | | <van-button type="primary" @click="confirmUpload">确认</van-button> |
| | | </view> |
| | | </view> |
| | | </van-popup> |
| | | |
| | | <!-- éä»¶åè¡¨éæ© --> |
| | | <van-action-sheet v-model:show="showFileSheet" :actions="fileActions" cancel-text="åæ¶" close-on-click-action @select="onSelectFile" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import dayjs from 'dayjs' |
| | | import { showToast, showLoadingToast, closeToast } from 'vant' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { getToken } from '@/utils/auth' |
| | | import config from '@/config.js' |
| | | import { |
| | | registrationProductPage, |
| | | commitFile, |
| | | delInvoiceLedgerByRegProductId |
| | | } from '@/api/salesManagement/invoiceLedger.js' |
| | | import {onShow} from "@dcloudio/uni-app"; |
| | | import {productRecordPage} from "@/api/procurementManagement/procurementInvoiceLedger"; |
| | | import {delRegistration} from "@/api/procurementManagement/invoiceEntry"; |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // åè¡¨ä¸æ¥è¯¢ |
| | | const ledgerList = ref([]) |
| | | const total = ref(0) |
| | | const page = reactive({ current: -1, size: -1 }) |
| | | const searchForm = reactive({ |
| | | searchText: '', |
| | | status: false, |
| | | createTimeStart: '' |
| | | }) |
| | | |
| | | // é¡¶é¨äº¤äº |
| | | const showFilter = ref(false) |
| | | const showInvoiceRange = ref(false) |
| | | const showCreateDatePicker = ref(false) |
| | | const invoiceRangeLabel = ref('') |
| | | const currentCreateDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) |
| | | |
| | | const currentId = ref('') |
| | | const fileList = ref([]) // è¡ä¸ä¼ æéç¨ä¸ä¼ å表 |
| | | |
| | | // è¡ä¸ä¼ å¼¹çª |
| | | const showUpload = ref(false) |
| | | |
| | | // éä»¶æ¥ç |
| | | const showFileSheet = ref(false) |
| | | const fileActions = ref([]) |
| | | let currentFilesToOpen = [] |
| | | |
| | | const formatAmount = (val) => { |
| | | if (val === undefined || val === null || val === '') return '0.00' |
| | | const num = Number(val) |
| | | if (Number.isNaN(num)) return '0.00' |
| | | return num.toFixed(2) |
| | | } |
| | | const formatDateTime = (val) => { |
| | | if (!val) return '' |
| | | return dayjs(val).format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | |
| | | const goBack = () => { |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | const handleQuery = () => { |
| | | getList() |
| | | } |
| | | |
| | | const getList = async () => { |
| | | try { |
| | | showLoadingToast({ message: 'å è½½ä¸...' }) |
| | | const { invoiceDate, ...rest } = searchForm |
| | | const res = await productRecordPage({ ...rest, ...page }) |
| | | // å
¼å®¹ä¸åè¿åç»æ |
| | | const records = res?.data?.records || res?.records || res?.data || [] |
| | | const totalVal = res?.data?.total || res?.total || records.length || 0 |
| | | ledgerList.value = records |
| | | total.value = totalVal |
| | | closeToast() |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('è·åå表失败') |
| | | } |
| | | } |
| | | |
| | | // çéé»è¾ |
| | | const resetFilter = () => { |
| | | searchForm.searchText = '' |
| | | searchForm.status = false |
| | | const start = dayjs().startOf('month').format('YYYY-MM-DD') |
| | | const end = dayjs().endOf('month').format('YYYY-MM-DD') |
| | | searchForm.invoiceDate = [start, end] |
| | | searchForm.invoiceDateStart = start |
| | | searchForm.invoiceDateEnd = end |
| | | searchForm.createTimeStart = '' |
| | | invoiceRangeLabel.value = '' |
| | | } |
| | | const confirmFilter = () => { |
| | | showFilter.value = false |
| | | getList() |
| | | } |
| | | const onInvoiceRangeConfirm = (e) => { |
| | | // e 为 [start, end] ç Date 对象æå符串ï¼uni-app ä¸ Vant Calendar è¿åæ¶é´æ³æ°ç» |
| | | try { |
| | | let start, end |
| | | if (Array.isArray(e)) { |
| | | const [s, ed] = e |
| | | start = dayjs(s).format('YYYY-MM-DD') |
| | | end = dayjs(ed).format('YYYY-MM-DD') |
| | | } else if (e && e.detail && Array.isArray(e.detail)) { |
| | | const [s, ed] = e.detail |
| | | start = dayjs(s).format('YYYY-MM-DD') |
| | | end = dayjs(ed).format('YYYY-MM-DD') |
| | | } |
| | | searchForm.invoiceDateStart = start |
| | | searchForm.invoiceDateEnd = end |
| | | invoiceRangeLabel.value = `${start} è³ ${end}` |
| | | showInvoiceRange.value = false |
| | | } catch (err) { |
| | | showInvoiceRange.value = false |
| | | } |
| | | } |
| | | const onCreateDateConfirm = ({ selectedValues }) => { |
| | | try { |
| | | searchForm.createTimeStart = selectedValues.join('-') |
| | | currentCreateDate.value = selectedValues |
| | | showCreateDatePicker.value = false |
| | | } catch (err) { |
| | | showCreateDatePicker.value = false |
| | | } |
| | | } |
| | | |
| | | // ç¼è¾é»è¾æ¹ä¸ºè·³è½¬æ°é¡µé¢ |
| | | const openEdit = (row) => { |
| | | try { |
| | | uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(row)) |
| | | uni.navigateTo({ url: '/pages/procurementManagement/procurementInvoiceLedger/detail' }) |
| | | } catch (e) { |
| | | showToast('跳转失败') |
| | | } |
| | | } |
| | | |
| | | // å é¤ |
| | | const handleDelete = (row) => { |
| | | let ids = []; |
| | | ids.push(row.id); |
| | | console.log(ids) |
| | | uni.showModal({ |
| | | title: 'å é¤ç¡®è®¤', |
| | | content: '该å票å°è´¦å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼', |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | try { |
| | | showLoadingToast({ message: 'å¤çä¸...' }) |
| | | await delRegistration(ids) |
| | | closeToast() |
| | | showToast('å 餿å') |
| | | await getList() |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('å é¤å¤±è´¥ï¼è¯·éè¯') |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // è¡ä¸ä¼ |
| | | const openUpload = (row) => { |
| | | currentId.value = row.id |
| | | fileList.value = [] |
| | | showUpload.value = true |
| | | } |
| | | const confirmUpload = async () => { |
| | | try { |
| | | const payload = { fileList: fileList.value, id: currentId.value } |
| | | showLoadingToast({ message: 'æäº¤ä¸...' }) |
| | | await commitFile(payload) |
| | | closeToast() |
| | | showToast('æäº¤æå') |
| | | showUpload.value = false |
| | | fileList.value = [] |
| | | currentId.value = '' |
| | | getList() |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('æäº¤å¤±è´¥ï¼è¯·éè¯') |
| | | } |
| | | } |
| | | |
| | | // ä¸ä¼ ç¸å
³ |
| | | const beforeReadPdf = (file) => { |
| | | // å
¼å®¹å¤æä»¶ |
| | | const files = Array.isArray(file) ? file : [file] |
| | | for (const f of files) { |
| | | const sizeOk = f.size <= 10 * 1024 * 1024 |
| | | const ext = (f.name || '').split('.').pop()?.toLowerCase() |
| | | if (ext !== 'pdf') { |
| | | showToast('ä»
æ¯æpdfæä»¶') |
| | | return false |
| | | } |
| | | if (!sizeOk) { |
| | | showToast('ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿10MB') |
| | | return false |
| | | } |
| | | } |
| | | return true |
| | | } |
| | | |
| | | const uploadSingleFile = async (fileObj) => { |
| | | return new Promise((resolve, reject) => { |
| | | showLoadingToast({ message: 'æ£å¨ä¸ä¼ ...' }) |
| | | uni.uploadFile({ |
| | | url: config.baseUrl + '/invoiceLedger/uploadFile', |
| | | filePath: fileObj.url || fileObj.file?.path || fileObj.tempFilePath, |
| | | name: 'file', |
| | | header: { Authorization: 'Bearer ' + getToken() }, |
| | | success: (res) => { |
| | | closeToast() |
| | | try { |
| | | const data = JSON.parse(res.data || '{}') |
| | | if (data.code === 200) { |
| | | resolve(data.data) |
| | | } else { |
| | | reject(new Error(data.msg || 'ä¸ä¼ 失败')) |
| | | } |
| | | } catch (err) { |
| | | reject(err) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | closeToast() |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | const afterReadEditUpload = async (file) => { |
| | | try { |
| | | const files = Array.isArray(file) ? file : file?.file ? [file] : [file] |
| | | for (const f of files) { |
| | | const uploaded = await uploadSingleFile(f) |
| | | fileList.value.push(uploaded) |
| | | } |
| | | showToast('ä¸ä¼ æå') |
| | | } catch (e) { |
| | | showToast('ä¸ä¼ 失败') |
| | | } |
| | | } |
| | | |
| | | const afterReadRowUpload = async (file) => { |
| | | try { |
| | | const files = Array.isArray(file) ? file : file?.file ? [file] : [file] |
| | | for (const f of files) { |
| | | const uploaded = await uploadSingleFile(f) |
| | | fileList.value.push(uploaded) |
| | | } |
| | | showToast('ä¸ä¼ æå') |
| | | } catch (e) { |
| | | showToast('ä¸ä¼ 失败') |
| | | } |
| | | } |
| | | |
| | | const removeUploaded = (index) => { |
| | | fileList.value.splice(index, 1) |
| | | } |
| | | |
| | | const getFileNameFromUrl = (url) => { |
| | | try { |
| | | if (!url) return '' |
| | | return decodeURIComponent(url.split('/').pop()) |
| | | } catch (e) { |
| | | return url |
| | | } |
| | | } |
| | | |
| | | // éä»¶æ¥ç |
| | | const openFileActions = (commonFiles) => { |
| | | currentFilesToOpen = commonFiles || [] |
| | | fileActions.value = (commonFiles || []).map((f, idx) => ({ name: getFileNameFromUrl(f.url || ''), index: idx })) |
| | | showFileSheet.value = true |
| | | } |
| | | const onSelectFile = async (action) => { |
| | | try { |
| | | const item = currentFilesToOpen[action.index] |
| | | if (!item || !item.url) return |
| | | showLoadingToast({ message: 'ä¸è½½ä¸...' }) |
| | | uni.downloadFile({ |
| | | url: item.url, |
| | | success: (res) => { |
| | | closeToast() |
| | | if (res.statusCode === 200) { |
| | | uni.openDocument({ filePath: res.tempFilePath }) |
| | | } else { |
| | | showToast('ä¸è½½å¤±è´¥') |
| | | } |
| | | }, |
| | | fail: () => { |
| | | closeToast() |
| | | showToast('ä¸è½½å¤±è´¥') |
| | | } |
| | | }) |
| | | } catch (e) { |
| | | closeToast() |
| | | showToast('æå¼å¤±è´¥') |
| | | } |
| | | } |
| | | |
| | | onShow(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | .sales-account { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | } |
| | | |
| | | .search-filter-section { |
| | | padding: 10px 20px; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | background: #f5f5f5; |
| | | border-radius: 24px; |
| | | padding: 10px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-text { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #333; |
| | | background: transparent; |
| | | border: none; |
| | | outline: none; |
| | | } |
| | | |
| | | .search-text::placeholder { |
| | | color: #999; |
| | | } |
| | | |
| | | .filter-button { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .ledger-list { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .ledger-item { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | padding: 0 16px; |
| | | } |
| | | |
| | | .item-header { |
| | | padding: 16px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #2979ff; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 16px 0; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 12px; |
| | | color: #777777; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 12px; |
| | | color: #000000; |
| | | text-align: right; |
| | | flex: 1; |
| | | margin-left: 16px; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .no-data { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | color: #999; |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | padding: 0 0 16px 0; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | } |
| | | |
| | | .filter-popup { |
| | | padding: 12px 12px 20px; |
| | | } |
| | | |
| | | .switch-row { |
| | | padding: 12px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .switch-label { |
| | | font-size: 14px; |
| | | color: #333; |
| | | } |
| | | |
| | | .filter-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | padding: 12px 16px 16px; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .edit-container { |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .uploaded-list { |
| | | padding: 8px 16px 0 16px; |
| | | } |
| | | |
| | | .uploaded-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 8px 0; |
| | | border-bottom: 1px solid #f5f5f5; |
| | | } |
| | | |
| | | .file-name { |
| | | font-size: 12px; |
| | | color: #333; |
| | | margin-right: 8px; |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .tip-text { |
| | | padding: 4px 16px 0 16px; |
| | | font-size: 12px; |
| | | color: #888; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); |
| | | z-index: 1000; |
| | | } |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 6.375rem; |
| | | background: #C7C9CC; |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | .save-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 14rem; |
| | | background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="receipt-payment-history"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="仿¬¾æµæ°´" @back="goBack" /> |
| | | |
| | | <!-- æç´¢åºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <input |
| | | class="search-text" |
| | | placeholder="请è¾å
¥ä¾åºååç§°" |
| | | v-model="searchForm.searchText" |
| | | @input="getList" |
| | | /> |
| | | </view> |
| | | <view class="search-button" @click="getList"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- ç»è®¡ä¿¡æ¯ --> |
| | | <view class="summary-info" v-if="tableData.length > 0"> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">æ»è®°å½æ°</text> |
| | | <text class="summary-value">{{ tableData.length }}</text> |
| | | </view> |
| | | <view class="summary-item"> |
| | | <text class="summary-label">æ»éé¢</text> |
| | | <text class="summary-value highlight">{{ formatAmount(totalAmount) }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- 仿¬¾åå²å表 --> |
| | | <view class="history-list" v-if="tableData.length > 0"> |
| | | <view v-for="(item, index) in tableData" :key="index"> |
| | | <view class="history-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.purchaseContractNumber }}</text> |
| | | </view> |
| | | <view class="item-tag" :class="getTagClass(item.paymentMethod)"> |
| | | <text class="tag-text">{{ item.paymentMethod }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¾åºååç§°</text> |
| | | <text class="detail-value">{{ item.supplierName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">仿¬¾éé¢(å
)</text> |
| | | <text class="detail-value highlight">{{ formatAmount(item.currentPaymentAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">仿¬¾æ¥æ</text> |
| | | <text class="detail-value">{{ item.paymentDate }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="detail-info"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»è®°äºº</text> |
| | | <text class="detail-value">{{ item.registrant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»è®°æ¥æ</text> |
| | | <text class="detail-value">{{ item.registrationtDate }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- æä½æé® --> |
| | | <view class="action-buttons"> |
| | | <van-button |
| | | type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.registrant !== userStore.nickName" |
| | | @click="openForm(item)" |
| | | > |
| | | ç¼è¾ä»æ¬¾ |
| | | </van-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="no-data"> |
| | | <text>ææ ä»æ¬¾å岿°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from 'vue'; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import {paymentHistoryListPage} from "@/api/procurementManagement/paymentEntry"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | const userStore = useUserStore() |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = ref({ |
| | | searchText: '', |
| | | }); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | |
| | | // å页忰 |
| | | const page = ref({ |
| | | current: -1, |
| | | size: -1, |
| | | }); |
| | | |
| | | const totalAmount = computed(() => { |
| | | return tableData.value.reduce((sum, item) => { |
| | | return sum + (parseFloat(item.receiptPaymentAmount) || 0); |
| | | }, 0); |
| | | }); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | const params = { |
| | | ...searchForm.value, |
| | | ...page.value |
| | | }; |
| | | paymentHistoryListPage(params).then((res) => { |
| | | tableData.value = res.records; |
| | | }).catch(() => { |
| | | uni.showToast({ |
| | | title: 'æ¥è¯¢å¤±è´¥', |
| | | icon: 'error' |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = (type) => { |
| | | if (type == 'çµæ±') { |
| | | return "tag-electric"; |
| | | } else if (type == 'æ¿å
') { |
| | | return "tag-acceptance"; |
| | | } else { |
| | | return "tag-unknown"; |
| | | } |
| | | }; |
| | | |
| | | // æ ¼å¼åéé¢ |
| | | const formatAmount = (amount) => { |
| | | return amount ? parseFloat(amount).toFixed(2) : '0.00'; |
| | | }; |
| | | // æå¼ç¼è¾è¡¨å |
| | | const openForm = (item) => { |
| | | uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item)) |
| | | uni.navigateTo({ url: '/pages/procurementManagement/paymentEntry/edit' }) |
| | | } |
| | | onShow(() => { |
| | | // 页颿¾ç¤ºæ¶å·æ°å表 |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | .receipt-payment-history { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | } |
| | | |
| | | |
| | | |
| | | .search-section { |
| | | padding: 10px 20px; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | background: #f5f5f5; |
| | | border-radius: 24px; |
| | | padding: 10px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-text { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #333; |
| | | background: transparent; |
| | | border: none; |
| | | outline: none; |
| | | } |
| | | |
| | | .search-text::placeholder { |
| | | color: #999; |
| | | } |
| | | |
| | | .search-button { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .history-list { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .history-item { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | padding: 0 16px; |
| | | } |
| | | |
| | | .item-header { |
| | | padding: 16px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #2979ff; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .item-tag { |
| | | border-radius: 4px; |
| | | padding: 2px 8px; |
| | | } |
| | | |
| | | .tag-electric { |
| | | background: #4caf50; |
| | | } |
| | | |
| | | .tag-acceptance { |
| | | background: #ff9800; |
| | | } |
| | | |
| | | .tag-unknown { |
| | | background: #9e9e9e; |
| | | } |
| | | |
| | | .tag-text { |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 16px 0; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .detail-info { |
| | | margin-top: 10px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | } |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | padding: 12px 0 0 0; |
| | | justify-content: space-between; |
| | | } |
| | | .action-btn { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 12px; |
| | | color: #777777; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 12px; |
| | | color: #000000; |
| | | text-align: right; |
| | | flex: 1; |
| | | margin-left: 16px; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .no-data { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | color: #999; |
| | | } |
| | | |
| | | .summary-info { |
| | | background: #ffffff; |
| | | margin: 20px 20px 0 20px; |
| | | border-radius: 12px; |
| | | padding: 16px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .summary-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .summary-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | |
| | | .summary-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .summary-value.highlight { |
| | | color: #2979ff; |
| | | font-weight: 600; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="account-detail"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ç¼è¾å款" @back="onClickLeft" /> |
| | | |
| | | <!-- 表åå
容 --> |
| | | <van-form @submit="onSubmit" ref="formRef" label-width="110px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <van-cell-group title="åºæ¬ä¿¡æ¯" inset> |
| | | <van-field |
| | | v-model="form.salesContractNo" |
| | | label="éå®ååå·" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="form.customerName" |
| | | label="客æ·åç§°" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | <!-- <van-field--> |
| | | <!-- v-model="form.invoiceNo"--> |
| | | <!-- label="å票å·"--> |
| | | <!-- placeholder="èªå¨å¡«å
"--> |
| | | <!-- readonly--> |
| | | <!-- />--> |
| | | <!-- <van-field--> |
| | | <!-- v-model="form.invoiceTotal"--> |
| | | <!-- label="å票éé¢(å
)"--> |
| | | <!-- placeholder="èªå¨å¡«å
"--> |
| | | <!-- readonly--> |
| | | <!-- />--> |
| | | <!-- <van-field--> |
| | | <!-- v-model="form.taxRate"--> |
| | | <!-- label="ç¨ç"--> |
| | | <!-- placeholder="èªå¨å¡«å
"--> |
| | | <!-- readonly--> |
| | | <!-- />--> |
| | | <view class="tip-text">å¾
忬¾éé¢ï¼{{ currentNoReceiptAmount }} å
</view> |
| | | <van-field |
| | | v-model="form.receiptPaymentAmount" |
| | | label="æ¬æ¬¡å款éé¢" |
| | | type="number" |
| | | placeholder="请è¾å
¥" |
| | | @blur="changeNum" |
| | | :rules="[{ required: true, message: '请è¾å
¥å款éé¢' }]" |
| | | clearable |
| | | /> |
| | | <van-field |
| | | v-model="form.receiptPaymentTypeName" |
| | | label="忬¾å½¢å¼" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | @click="showPaymentTypePicker" |
| | | :rules="[{ required: true, message: 'è¯·éæ©åæ¬¾å½¢å¼' }]" |
| | | /> |
| | | <van-field |
| | | v-model="form.receiptPaymentDate" |
| | | label="æ¥æ¬¾æ¥æ" |
| | | placeholder="è¯·éæ©" |
| | | readonly |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ¥æ¬¾æ¥æ' }]" |
| | | /> |
| | | <van-field |
| | | v-model="form.registrant" |
| | | label="ç»è®°äºº" |
| | | placeholder="èªå¨å¡«å
" |
| | | readonly |
| | | /> |
| | | </van-cell-group> |
| | | |
| | | <!-- æäº¤æé® --> |
| | | <view class="footer-btns"> |
| | | <van-button class="cancel-btn" @click="onClickLeft">åæ¶</van-button> |
| | | <van-button class="save-btn" native-type="submit" form-type="submit" :loading="loading">ä¿å</van-button> |
| | | </view> |
| | | </van-form> |
| | | |
| | | <!-- 忬¾æ¹å¼éæ©å¨ --> |
| | | <van-popup v-model:show="showPaymentType" position="bottom"> |
| | | <van-picker |
| | | :model-value="pickerValue" |
| | | :columns="receipt_payment_type" |
| | | @confirm="onPaymentTypeConfirm" |
| | | @cancel="showPaymentType = false" |
| | | /> |
| | | </van-popup> |
| | | |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <van-popup v-model:show="showDate" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentDate" |
| | | title="éæ©æ¥æ" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDate = false" |
| | | /> |
| | | </van-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { receiptPaymentSaveOrUpdate, invoiceInfo } from '@/api/salesManagement/receiptPayment' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { showToast, showNotify } from 'vant' |
| | | import { useDict } from '@/utils/dict' |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // 表åå¼ç¨ |
| | | const formRef = ref() |
| | | |
| | | // ååºå¼æ°æ® |
| | | const loading = ref(false) |
| | | const showPaymentType = ref(false) |
| | | const pickerValue = ref([]) |
| | | const showDate = ref(false) |
| | | const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | salesContractNo: '', |
| | | customerName: '', |
| | | invoiceNo: '', |
| | | invoiceTotal: '', |
| | | taxRate: '', |
| | | receiptPaymentAmount: '', |
| | | receiptPaymentType: '', |
| | | receiptPaymentTypeName: '', |
| | | registrant: '', |
| | | receiptPaymentDate: '', |
| | | invoiceLedgerId: '' |
| | | }) |
| | | const currentNoReceiptAmount = ref(0) |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { receipt_payment_type: dictReceiptPaymentType } = useDict('receipt_payment_type') |
| | | |
| | | // 转æ¢åå
¸æ°æ®æ ¼å¼ä¸ºéæ©å¨éè¦çæ ¼å¼ |
| | | const receipt_payment_type = computed(() => { |
| | | return dictReceiptPaymentType.value.map(item => ({ |
| | | text: item.label, |
| | | value: item.value |
| | | })) |
| | | }) |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const onClickLeft = () => { |
| | | uni.removeStorageSync('invoiceLedgerEditRow'); |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // æ¾ç¤ºå款æ¹å¼éæ©å¨ |
| | | const showPaymentTypePicker = () => { |
| | | showPaymentType.value = true |
| | | } |
| | | const changeNum = () => { |
| | | if (form.value.receiptPaymentAmount > currentNoReceiptAmount.value) { |
| | | form.value.receiptPaymentAmount = currentNoReceiptAmount.value |
| | | showToast('ä¸å¯å¤§äºå¾
忬¾éé¢') |
| | | } |
| | | } |
| | | |
| | | // ç¡®è®¤åæ¬¾æ¹å¼éæ© |
| | | const onPaymentTypeConfirm = ({ selectedValues, selectedOptions }) => { |
| | | form.value.receiptPaymentType = selectedOptions[0].value |
| | | form.value.receiptPaymentTypeName = selectedOptions[0].text |
| | | pickerValue.value = selectedValues; |
| | | showPaymentType.value = false |
| | | } |
| | | |
| | | // æ¾ç¤ºæ¥æéæ©å¨ |
| | | const showDatePicker = () => { |
| | | showDate.value = true |
| | | } |
| | | |
| | | // ç¡®è®¤æ¥æéæ© |
| | | const onDateConfirm = ({ selectedValues }) => { |
| | | form.value.receiptPaymentDate = selectedValues.join('-') |
| | | currentDate.value = selectedValues |
| | | showDate.value = false |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const onSubmit = () => { |
| | | // 表åéªè¯ |
| | | if (!form.value.receiptPaymentAmount) { |
| | | showNotify({ type: 'warning', message: '请è¾å
¥å款éé¢' }) |
| | | return |
| | | } |
| | | |
| | | if (!form.value.receiptPaymentType) { |
| | | showNotify({ type: 'warning', message: 'è¯·éæ©åæ¬¾å½¢å¼' }) |
| | | return |
| | | } |
| | | loading.value = true |
| | | let updateData = { |
| | | id: form.value.id, |
| | | receiptPaymentType: form.value.receiptPaymentType, |
| | | receiptPaymentAmount: form.value.receiptPaymentAmount, |
| | | }; |
| | | receiptPaymentSaveOrUpdate(updateData) |
| | | .then(() => { |
| | | showToast('æäº¤æå') |
| | | onClickLeft() |
| | | }) |
| | | .catch((error) => { |
| | | loading.value = false |
| | | }) |
| | | } |
| | | |
| | | // åå§åæ°æ® |
| | | const initData = () => { |
| | | const rowStr = uni.getStorageSync('invoiceLedgerEditRow') |
| | | const row = JSON.parse(rowStr) |
| | | form.value = { ...row} |
| | | form.value.receiptPaymentTypeName = formatReceiptType(row.receiptPaymentType); |
| | | currentNoReceiptAmount.value = row.noReceiptAmount |
| | | } |
| | | const formatReceiptType = (type) => { |
| | | if (type == 0) { |
| | | return "çµæ±"; |
| | | } else if (type == 1) { |
| | | return "æ¿å
"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initData() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .account-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 6.375rem; |
| | | background: #C7C9CC; |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .save-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #FFFFFF; |
| | | width: 14rem; |
| | | background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | // ååºå¼è°æ´ |
| | | @media (max-width: 768px) { |
| | | .submit-section { |
| | | padding: 12px; |
| | | } |
| | | } |
| | | .tip-text { padding: 4px 16px 0 16px; font-size: 12px; color: #888; } |
| | | </style> |
| | |
| | | <view class="no-data" v-else> |
| | | <text>ææ åæ¬¾æ°æ®</text> |
| | | </view> |
| | | |
| | | <!-- 忬¾æ¹å¼éæ©å¨ --> |
| | | <van-popup v-model:show="showPaymentType" position="bottom"> |
| | | <van-picker |
| | | :columns="receipt_payment_type" |
| | | @confirm="onPaymentTypeConfirm" |
| | | @cancel="showPaymentType = false" |
| | | /> |
| | | </van-popup> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | import { showToast } from 'vant' |
| | | import {onShow} from "@dcloudio/uni-app"; |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // ååºå¼æ°æ® |
| | | const tableData = ref([]) |
| | | const tableLoading = ref(false) |
| | | const showPaymentType = ref(false) |
| | | const currentEditRow = ref(null) |
| | | |
| | | // æ¥è¯¢åæ°è®¾ç½®ä¸º-1è·åå
¨é¨æ°æ® |
| | | const page = ref({ |
| | |
| | | customerContractNo: '', |
| | | projectName: '' |
| | | }) |
| | | |
| | | // 忬¾æ¹å¼é项 |
| | | const receipt_payment_type = ref([ |
| | | { text: 'ç°é', value: '1' }, |
| | | { text: 'é¶è¡è½¬è´¦', value: '2' }, |
| | | { text: 'æ¯ç¥¨', value: '3' }, |
| | | { text: 'å
¶ä»', value: '4' } |
| | | ]) |
| | | |
| | | // æ ¼å¼åæ°å |
| | | const formatNumber = (value) => { |
| | |
| | | uni.navigateTo({ url: '/pages/sales/receiptPayment/add' }) |
| | | } |
| | | |
| | | // ç¡®è®¤åæ¬¾æ¹å¼éæ© |
| | | const onPaymentTypeConfirm = (value) => { |
| | | if (currentEditRow.value) { |
| | | currentEditRow.value.receiptPaymentType = value.value |
| | | } |
| | | showPaymentType.value = false |
| | | } |
| | | onShow(() => { |
| | | getList() |
| | | }) |
| | |
| | | <text class="detail-value">{{ item.createTime }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- æä½æé® --> |
| | | <view class="action-buttons"> |
| | | <van-button |
| | | type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.registrant !== userStore.nickName" |
| | | @click="openForm(item)" |
| | | > |
| | | ç¼è¾å款 |
| | | </van-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | import { ref, computed } from 'vue'; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import { receiptPaymentHistoryListPage } from "@/api/salesManagement/receiptPayment.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | const userStore = useUserStore() |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = ref({ |
| | |
| | | const formatAmount = (amount) => { |
| | | return amount ? parseFloat(amount).toFixed(2) : '0.00'; |
| | | }; |
| | | // æå¼ç¼è¾è¡¨å |
| | | const openForm = (item) => { |
| | | uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item)) |
| | | uni.navigateTo({ url: '/pages/sales/receiptPayment/edit' }) |
| | | } |
| | | onShow(() => { |
| | | // 页颿¾ç¤ºæ¶å·æ°å表 |
| | | getList(); |
| | |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | padding: 12px 0 0 0; |
| | | justify-content: space-between; |
| | | } |
| | | .action-btn { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | } |
| | | .document-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | |
| | | <template> |
| | | <view class="container"> |
| | | <uni-list> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'person-filled' }" title="æµç§°" :rightText="user.nickName" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'phone-filled' }" title="ææºå·ç " |
| | | :rightText="user.phonenumber" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'email-filled' }" title="é®ç®±" :rightText="user.email" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'auth-filled' }" title="å²ä½" :rightText="postGroup" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'staff-filled' }" title="è§è²" :rightText="roleGroup" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{ type: 'calendar-filled' }" title="åå»ºæ¥æ" |
| | | :rightText="user.createTime" /> |
| | | </uni-list> |
| | | <view class="card"> |
| | | <van-cell-group inset> |
| | | <van-cell icon="user" title="æµç§°" :value="user.nickName" /> |
| | | <van-cell icon="phone" title="ææºå·ç " :value="user.phonenumber" /> |
| | | <van-cell icon="invitation" title="é®ç®±" :value="user.email" /> |
| | | <van-cell icon="medal" title="å²ä½" :value="postGroup" /> |
| | | <van-cell icon="friends" title="è§è²" :value="roleGroup" /> |
| | | <van-cell icon="notes" title="åå»ºæ¥æ" :value="user.createTime" /> |
| | | </van-cell-group> |
| | | </view> |
| | | |
| | | <u-button @click="register()">ç»å®å¾®ä¿¡</u-button> |
| | | <!-- <u-button @click="register()">ç»å®å¾®ä¿¡</u-button> --> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | /* èæ¯æ´æåï¼å¡çæ´çªåº */ |
| | | page { |
| | | background-color: #ffffff; |
| | | background-color: #f5f7fb; |
| | | } |
| | | |
| | | .container { |
| | | min-height: 100vh; |
| | | padding: 0.75rem; /* 24rpx -> 0.75rem */ |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | /* å表å¡çå®¹å¨ */ |
| | | .card { |
| | | background-color: #ffffff; |
| | | border-radius: 0.625rem; /* 20rpx -> 0.625rem */ |
| | | box-shadow: 0 0.375rem 1rem rgba(0, 0, 0, 0.06); /* 0 12rpx 32rpx -> 0 0.375rem 1rem */ |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* éé
Vant Cell */ |
| | | :deep(.van-cell) { |
| | | min-height: 2.875rem; /* 92rpx -> 2.875rem */ |
| | | } |
| | | |
| | | :deep(.van-cell__title) { |
| | | font-weight: 500; |
| | | color: #1f2937; /* æ·±ç° */ |
| | | } |
| | | |
| | | :deep(.van-cell__value) { |
| | | color: #6b7280; /* 次è¦ç° */ |
| | | } |
| | | |
| | | /* ç§»é¤ä¸å使ç¨ç .cell-icon æ ·å¼ */ |
| | | </style> |