| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #!/usr/bin/env bash |
| | | # ============================================================================ |
| | | # Vue å端é¨ç½²èæ¬ï¼macOS / Linux çï¼ââ é¶å·ä¹é¸¿åå·¥ï¼JHHGï¼ |
| | | # |
| | | # ç±åç®å½ç JHHG.bat 转åèæ¥ï¼æ¥éª¤ãæç¤ºè¯ãæå¡å¨ãè´¦å·ãè¿ç«¯ç®å½ã |
| | | # è¶
æ¶åæ°ä¸ .bat å®å
¨ä¸è´ï¼Windows 䏿ä¹ç¨ï¼è¿éå°±æä¹ç¨ã |
| | | # |
| | | # ä¸ .bat çå
¨é¨å·®å«ï¼ |
| | | # 1. ä¸ä¾èµ sshpass.exeãç³»ç»éæ sshpass å°±ç¨ sshpassï¼æ²¡æå°±éå macOS |
| | | # èªå¸¦ç /usr/bin/expect æ¥åå¯ç ââ æä»¥è¿å° Mac ä¸ç¨è£
ä»»ä½ä¸è¥¿ä¹è½è·ã |
| | | # 2. èæ¬å¼å¤´ä¼ cd å°èªå·±æå¨ç®å½ï¼ä»ä»»ä½ä½ç½®è°ç¨é½è½æ£ç¡®æå»ºåä¸ä¼ ã |
| | | # 3. ç»å°¾ç pause åªå¨äº¤äºå¼ç»ç«¯éçæï¼è¢«å
¶å®èæ¬/管éè°ç¨æ¶ä¸ä¼å¡ä½ã |
| | | # 4. ãæ¯è¾æä»¶å¤§å°ãè¿ä¸æ¥ææ é¢çåæçæ£åäºæ¯å¯¹ï¼.bat åªæå°ä¸æ¯å¯¹ï¼ï¼ |
| | | # 大å°ä¸ä¸è´ç´æ¥æ¥éï¼é¿å
æä¸ä¸ªä¸ä¼ æ®ç¼ºçå
è§£åå°çº¿ä¸ç®å½ã |
| | | # |
| | | # ç¨æ³ï¼ |
| | | # ./JHHG.sh # 馿¬¡å¯è½éè¦ chmod +x JHHG.sh |
| | | # bash JHHG.sh |
| | | # |
| | | # å¯éç¯å¢åéï¼ä¸è¬ç¨ä¸å°ï¼ï¼ |
| | | # JHHG_TRANSPORT=sshpass|expect å¼ºå¶æå®åå¯ç çæ¹å¼ |
| | | # ============================================================================ |
| | | |
| | | set -uo pipefail |
| | | |
| | | # ========================= |
| | | # é
ç½®ï¼ä¸ JHHG.bat ä¸åä¸å·®ï¼ |
| | | # ========================= |
| | | |
| | | readonly COMPANY='JHHG' |
| | | readonly REMOTE_USER='root' |
| | | readonly REMOTE_HOST='42.63.70.90' |
| | | readonly REMOTE_PORT='22' |
| | | # å¯ç å« ! å #ï¼å¿
é¡»ç¨åå¼å·ï¼ä¸è¦ source å°äº¤äºå¼ shell éè·ï¼é£éä¼å ! åå²å±å¼ï¼ï¼ |
| | | # ç¨ ./JHHG.sh æ bash JHHG.sh æ§è¡ã |
| | | # 2026-10-12 宿µè¿ï¼æå¡å¨æ¥åçå°±æ¯è¿ä¸ªå®æ´å符串ï¼å»æ !@##@! ç Nxjhhg ä¼è¢«æï¼ã |
| | | readonly PASSWORD='Nxjhhg!@##@!' |
| | | readonly ZIP_FILE='dist.zip' |
| | | readonly REMOTE_DIR='/home/vue/dist' |
| | | readonly SSH_OPTS=(-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=3) |
| | | |
| | | readonly REMOTE_TARGET="${REMOTE_USER}@${REMOTE_HOST}" |
| | | readonly REMOTE_TMP="${REMOTE_DIR}/.dist.zip.uploading" |
| | | |
| | | # èæ¬èªèº«æå¨ç®å½ = é¡¹ç®æ ¹ç®å½ |
| | | cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| | | |
| | | # ========================= |
| | | # è¾åºhelperï¼ä¸ .bat çæç¤ºæ ¼å¼ä¸è´ï¼ |
| | | # ========================= |
| | | |
| | | log() { printf '%s\n' "$*"; } |
| | | ok() { printf '[OK] %s\n' "$*"; } |
| | | info() { printf '[INFO] %s\n' "$*"; } |
| | | warn() { printf '[WARN] %s\n' "$*"; } |
| | | err() { printf '[ERROR] %s\n' "$*"; } |
| | | |
| | | # ä¸ .bat ç :END 䏿 ·ï¼äº¤äºå¼ç»ç«¯éåä¸ä¸åéåº |
| | | pause_if_interactive() { |
| | | if [[ -t 0 ]]; then |
| | | printf '\næå车é®éåº...' |
| | | read -r _ || true |
| | | printf '\n' |
| | | fi |
| | | } |
| | | |
| | | fail() { |
| | | log '' |
| | | log '============================================================' |
| | | log ' DEPLOY FAILED' |
| | | log '============================================================' |
| | | log '' |
| | | log 'Please check the error message above.' |
| | | log '' |
| | | pause_if_interactive |
| | | exit 1 |
| | | } |
| | | |
| | | # 没被æ¾å¼å¤ç就失败çå½ä»¤ï¼ä¹èµ°å° DEPLOY FAILEDï¼ä¸çåæªè¾åº |
| | | on_unexpected_error() { |
| | | err "å½ä»¤å¤±è´¥ï¼éåºç $1ï¼èæ¬ç¬¬ $2 è¡ï¼ã" |
| | | fail |
| | | } |
| | | |
| | | trap 'on_unexpected_error $? $LINENO' ERR |
| | | |
| | | # ========================= |
| | | # ä¼ è¾å±ï¼æå¯ç åç» ssh/scp |
| | | # ========================= |
| | | |
| | | # ä¼å
sshpassï¼å .bat 䏿 ·ï¼ï¼æ²¡æå°±ç¨ macOS èªå¸¦ç expect |
| | | TRANSPORT="${JHHG_TRANSPORT:-}" |
| | | if [[ -z "$TRANSPORT" ]]; then |
| | | if command -v sshpass >/dev/null 2>&1; then |
| | | TRANSPORT='sshpass' |
| | | elif command -v expect >/dev/null 2>&1; then |
| | | TRANSPORT='expect' |
| | | fi |
| | | fi |
| | | |
| | | # ç¨å½å TRANSPORT æ§è¡ä¸æ¡ ssh/scp å½ä»¤ï¼åæ°åæ ·éä¼ |
| | | # å¯ç éè¿ç¯å¢åéä¼ éï¼ä¸åºç°å¨å½ä»¤è¡åæ°éï¼ä¸ä¼è¿ ps è¾åºï¼ |
| | | run_remote() { |
| | | if [[ "$TRANSPORT" == 'sshpass' ]]; then |
| | | SSHPASS="$PASSWORD" sshpass -e "$@" |
| | | return $? |
| | | fi |
| | | # expect 忝ï¼ç¨åºå¿
须忿件åç¨ -f è°ç¨ï¼å 为 `expect -c èæ¬ åæ°...` |
| | | # ä¸ä¼æåæ°æ¾è¿ $argvï¼ä¼æå®å½èæ¬æä»¶åï¼ã |
| | | local exp_file rc |
| | | exp_file="$(mktemp "${TMPDIR:-/tmp}/jhhg-deploy.XXXXXX")" || { |
| | | err 'temp file creation failed.' |
| | | return 1 |
| | | } |
| | | cat >"$exp_file" <<'EXPECT_PROGRAM' |
| | | set timeout 300 |
| | | log_user 1 |
| | | if {[catch {spawn {*}$argv} spawn_err]} { |
| | | puts stderr "spawn failed: $spawn_err" |
| | | exit 127 |
| | | } |
| | | expect { |
| | | -re "(?i)are you sure you want to continue connecting" { send "yes\r"; exp_continue } |
| | | -re "(?i)password:" { send "$env(JHHG_PW)\r"; exp_continue } |
| | | eof |
| | | } |
| | | # æåè¿ç¨çéåºç åæ ·å¸¦åºå»ï¼å¯ç éæ¶ ssh è¿å 255ï¼å¿
须让ä¸å±æç¥å°ï¼ |
| | | set wait_result {} |
| | | catch wait wait_result |
| | | set rc [lindex $wait_result 3] |
| | | if {![string is integer -strict $rc]} { set rc 1 } |
| | | exit $rc |
| | | EXPECT_PROGRAM |
| | | JHHG_PW="$PASSWORD" expect -f "$exp_file" "$@" |
| | | rc=$? |
| | | rm -f "$exp_file" |
| | | return $rc |
| | | } |
| | | |
| | | ssh_remote() { # ssh_remote "è¿ç«¯å½ä»¤" |
| | | run_remote ssh -p "$REMOTE_PORT" "${SSH_OPTS[@]}" "$REMOTE_TARGET" "$1" |
| | | } |
| | | |
| | | scp_up() { # scp_up æ¬å°æä»¶ è¿ç«¯è·¯å¾ |
| | | run_remote scp -P "$REMOTE_PORT" "${SSH_OPTS[@]}" "$1" "${REMOTE_TARGET}:$2" |
| | | } |
| | | |
| | | # ========================= |
| | | # å¼å§ |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '============================================================' |
| | | log ' Vue Dist Auto Deploy' |
| | | log '============================================================' |
| | | log '' |
| | | log "Company : $COMPANY" |
| | | log "Server : $REMOTE_USER@$REMOTE_HOST" |
| | | log "Port : $REMOTE_PORT" |
| | | log "Remote Dir : $REMOTE_DIR" |
| | | log "Package : $ZIP_FILE" |
| | | log '' |
| | | |
| | | # ========================= |
| | | # [1/7] å¯ç å·¥å
· |
| | | # ========================= |
| | | |
| | | log '[1/7] Checking password tool...' |
| | | |
| | | if [[ -z "$TRANSPORT" ]]; then |
| | | err 'sshpass å expect 齿²¡æï¼æ æ³èªå¨è¾å
¥å¯ç ã' |
| | | info 'macOS ä¸è¬èªå¸¦ /usr/bin/expectï¼æ£å¸¸ä¸ä¼èµ°å°è¿éï¼' |
| | | info 'å¦æç¡®å®æ²¡æï¼è£
sshpass å³å¯ï¼å¯è½éå
å ç¬¬ä¸æ¹ tapï¼ï¼brew install sshpass' |
| | | info 'Linux: apt install sshpass / yum install sshpass' |
| | | fail |
| | | fi |
| | | |
| | | if [[ "$TRANSPORT" == 'sshpass' ]]; then |
| | | ok "sshpass found: $(command -v sshpass)" |
| | | else |
| | | ok "expect found: $(command -v expect)ï¼macOS èªå¸¦ï¼æ éå®è£
sshpassï¼" |
| | | fi |
| | | |
| | | # ========================= |
| | | # [2/7] pnpm |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '[2/7] Checking pnpm...' |
| | | |
| | | if ! command -v pnpm >/dev/null 2>&1; then |
| | | err 'pnpm not found.' |
| | | info 'HINT: npm install -g pnpm' |
| | | fail |
| | | fi |
| | | |
| | | if ! pnpm --version; then |
| | | err 'pnpm execution failed.' |
| | | fail |
| | | fi |
| | | |
| | | # ========================= |
| | | # [3/7] node |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '[3/7] Checking Node.js...' |
| | | |
| | | if ! command -v node >/dev/null 2>&1; then |
| | | err 'Node.js not found.' |
| | | fail |
| | | fi |
| | | |
| | | if ! node --version; then |
| | | err 'Node.js execution failed.' |
| | | fail |
| | | fi |
| | | |
| | | # ========================= |
| | | # node_modules |
| | | # ========================= |
| | | |
| | | if [[ ! -d node_modules ]]; then |
| | | log '' |
| | | info 'node_modules not found.' |
| | | info 'Running pnpm install...' |
| | | if ! pnpm install; then |
| | | err 'pnpm install failed.' |
| | | fail |
| | | fi |
| | | ok 'pnpm install completed.' |
| | | else |
| | | ok 'node_modules exists.' |
| | | fi |
| | | |
| | | # ========================= |
| | | # [4/7] æå»º |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '[4/7] Building project...' |
| | | |
| | | SKIP_BUILD='' |
| | | if [[ -f "$ZIP_FILE" ]]; then |
| | | log '' |
| | | warn "$ZIP_FILE already exists." |
| | | printf 'Rebuild? Y/N (default Y): ' |
| | | read -r REBUILD_ANSWER || true |
| | | case "$(printf '%s' "${REBUILD_ANSWER:-}" | tr '[:lower:]' '[:upper:]')" in |
| | | N) info 'Skip build.'; SKIP_BUILD='1' ;; |
| | | esac |
| | | fi |
| | | |
| | | if [[ -z "$SKIP_BUILD" ]]; then |
| | | info "Company: $COMPANY" |
| | | info 'Command: pnpm run build' |
| | | log '' |
| | | export VITE_COMPANY="$COMPANY" |
| | | if ! pnpm run build; then |
| | | log '' |
| | | err 'Build failed.' |
| | | fail |
| | | fi |
| | | log '' |
| | | ok 'Build completed.' |
| | | fi |
| | | |
| | | # ========================= |
| | | # [5/7] æ£æ¥å
|
| | | # ========================= |
| | | |
| | | log '' |
| | | log '[5/7] Checking package...' |
| | | |
| | | if [[ ! -f "$ZIP_FILE" ]]; then |
| | | err "$ZIP_FILE not found." |
| | | info 'HINT: Please check whether your build generates dist.zip.' |
| | | fail |
| | | fi |
| | | |
| | | LOCAL_ZIP_BYTES="$(wc -c < "$ZIP_FILE" | tr -d ' ')" |
| | | LOCAL_ZIP_MB="$(awk -v b="$LOCAL_ZIP_BYTES" 'BEGIN { printf "%.2f", b / 1048576 }')" |
| | | |
| | | ok 'Package found.' |
| | | info "File size: $LOCAL_ZIP_BYTES bytes" |
| | | info "File size: $LOCAL_ZIP_MB MB" |
| | | |
| | | # ========================= |
| | | # [6/7] æµè¯ SSH |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '[6/7] Testing SSH connection...' |
| | | |
| | | if ! ssh_remote 'echo SSH_OK'; then |
| | | err 'SSH connection failed.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'SSH connection successful.' |
| | | |
| | | # ========================= |
| | | # 建è¿ç«¯ç®å½ |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Creating remote directory...' |
| | | |
| | | if ! ssh_remote "mkdir -p '$REMOTE_DIR'"; then |
| | | err 'Failed to create remote directory.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'Remote directory ready.' |
| | | |
| | | # ========================= |
| | | # ä¸ä¼ ä¸´æ¶æä»¶ |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Uploading package...' |
| | | |
| | | ssh_remote "rm -f '$REMOTE_TMP'" || true |
| | | |
| | | # è¿ç«¯è·¯å¾ä¸è½å å¼å·ï¼ssh 飿¡çåå¼å·æ¯ç»è¿ç«¯ shell å¥çï¼è scp çåæ°ä¸ç» shellï¼ |
| | | # åå¼å·ä¼åææä»¶åççå®å符ï¼è¿ç«¯ä¼å»å¼ "'/home/vue/dist/..." è¿ä¸ªç¸å¯¹è·¯å¾ï¼ |
| | | if ! scp_up "$ZIP_FILE" "$REMOTE_TMP"; then |
| | | err 'Upload failed.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'Upload completed.' |
| | | |
| | | # ========================= |
| | | # æ ¡éªè¿ç«¯æä»¶ |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Checking remote package...' |
| | | |
| | | if ! ssh_remote "test -f '$REMOTE_TMP'"; then |
| | | err 'Remote package does not exist.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'Remote package exists.' |
| | | |
| | | # ========================= |
| | | # æ¯è¾æä»¶å¤§å° |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Checking package size...' |
| | | log '' |
| | | |
| | | # 大尿¯å¯¹æ¾å¨è¿ç«¯åãåªåéåºç ã |
| | | # ä¸è¦ç¨ $(run_remote ...) 廿ªåè¿ç«¯è¾åºï¼expect ä¼ææ´æ®µäº¤äºåæ¾ï¼spawn å½ä»¤è¡ã |
| | | # å¯ç æç¤ºï¼ä¸èµ·åè¿ stdoutï¼æªåºæ¥ç䏿¯å½ä»¤ç»æï¼æ¯å¯¹å¿
ç¶å¤±è´¥ã |
| | | if ! ssh_remote "test \"\$(stat -c %s '$REMOTE_TMP')\" -eq $LOCAL_ZIP_BYTES"; then |
| | | # åéä¸å¾å ${}ï¼bash 3.2 ä¼æç´§è·å
¶åçå
¨è§å符ï¼å¦ãï¼ãï¼å½æåéåçä¸é¨åï¼ |
| | | # äºæ¯ $ZIP_FILEï¼ ä¼è¢«è§£ææå为 "ZIP_FILEï¼" çåéï¼é
set -u ç´æ¥æ¥ unbound variable |
| | | err "å
大å°ä¸ä¸è´ï¼è¿ç«¯ ${REMOTE_TMP} 䏿¬å° ${ZIP_FILE}ï¼${LOCAL_ZIP_BYTES} åèï¼ä¸ç¬¦ï¼ä¸ä¼ å¯è½è¢«æªæã" |
| | | info "è¿ç«¯ä¸´æ¶æä»¶å·²ä¿çãå¯å¨æå¡å¨ä¸æ§è¡ stat -c %s '${REMOTE_TMP}' æ ¸å¯¹ï¼ç¡®è®¤åå é¤ã" |
| | | fail |
| | | fi |
| | | |
| | | ok "å
大å°ä¸è´ï¼${LOCAL_ZIP_BYTES} åèã" |
| | | |
| | | # ========================= |
| | | # æ¹åçæ |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Activating package...' |
| | | |
| | | if ! ssh_remote "mv -f '$REMOTE_TMP' '$REMOTE_DIR/$ZIP_FILE'"; then |
| | | err 'Failed to activate package.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'Package activated.' |
| | | |
| | | # ========================= |
| | | # æ£æ¥ unzip |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Checking unzip...' |
| | | |
| | | if ! ssh_remote 'command -v unzip'; then |
| | | err 'unzip is not installed on server.' |
| | | log '' |
| | | log 'CentOS/RHEL:' |
| | | log 'yum install -y unzip' |
| | | log '' |
| | | log 'Ubuntu/Debian:' |
| | | log 'apt install -y unzip' |
| | | fail |
| | | fi |
| | | |
| | | ok 'unzip found.' |
| | | |
| | | # ========================= |
| | | # æµè¯ ZIP |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Testing remote ZIP...' |
| | | |
| | | if ! ssh_remote "cd '$REMOTE_DIR' && unzip -t '$ZIP_FILE'"; then |
| | | log '' |
| | | err 'ZIP test failed.' |
| | | info 'Remote ZIP has been kept.' |
| | | fail |
| | | fi |
| | | |
| | | ok 'ZIP test passed.' |
| | | |
| | | # ========================= |
| | | # è§£å |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Extracting package...' |
| | | |
| | | if ! ssh_remote "cd '$REMOTE_DIR' && unzip -o '$ZIP_FILE'"; then |
| | | log '' |
| | | err 'Remote unzip failed.' |
| | | info 'Remote ZIP has been kept.' |
| | | fail |
| | | fi |
| | | |
| | | log '' |
| | | ok 'Extract completed.' |
| | | |
| | | # ========================= |
| | | # å é¤è¿ç«¯ ZIP |
| | | # ========================= |
| | | |
| | | log '' |
| | | info 'Removing remote ZIP...' |
| | | |
| | | if ssh_remote "rm -f '$REMOTE_DIR/$ZIP_FILE'"; then |
| | | ok 'Remote ZIP removed.' |
| | | else |
| | | warn 'Failed to remove remote ZIP.' |
| | | fi |
| | | |
| | | # ========================= |
| | | # [7/7] 宿 |
| | | # ========================= |
| | | |
| | | log '' |
| | | log '============================================================' |
| | | log ' DEPLOY SUCCESS' |
| | | log '============================================================' |
| | | log '' |
| | | log "Company : $COMPANY" |
| | | log "Server : $REMOTE_HOST:$REMOTE_PORT" |
| | | log "Remote Dir : $REMOTE_DIR" |
| | | log "Package : $ZIP_FILE" |
| | | log "Size : $LOCAL_ZIP_MB MB" |
| | | log '' |
| | | log 'Deployment completed successfully.' |
| | | log '' |
| | | |
| | | pause_if_interactive |
| | |
| | | productUnitId?: number; // 产ååä½ç¼å· |
| | | productUnitName?: string; // 产ååä½åç§° |
| | | productBarCode?: string; // äº§åæ¡ç |
| | | productPrice?: number; // 产ååä»·ï¼åèä»·ï¼ |
| | | productPrice?: number; // å«ç¨åä»·ï¼åèä»·ï¼ |
| | | count: number; // æ°é |
| | | taxPercent?: number; // ç¨ç |
| | | totalPrice?: number; // ä¸å«ç¨éé¢ |
| | | taxPrice?: number; // ç¨é¢ |
| | | demandTime?: string; // éæ±æ¥æ |
| | | remark?: string; // 夿³¨ |
| | | qcCheckFlag?: boolean; // æ¯å¦è´¨æ£ |
| | | inCount?: number; // å
¥åºæ°é |
| | | } |
| | | } |
| | | |
| | |
| | | api: getBusinessStatusTypeSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©åæºç¶æç»', |
| | | placeholder: 'è¯·éæ©åæºç¶æç»ï¼éå¡«ï¼', |
| | | allowClear: true, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['id'], |
| | | disabled: (values) => values.id, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'dealTime', |
| | |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | async componentProps() { |
| | | const statusList = await getBusinessStatusSimpleList( |
| | | formData.value?.statusTypeId ?? 0, |
| | | ); |
| | | const statusTypeId = formData.value?.statusTypeId; |
| | | // åæºç¶æç»ä¸ºéå¡«ï¼æªè®¾ç½®ç¶æç»æ¶æ²¡æå¯éé¶æ®µï¼ç¦ç¨å¹¶è¯´æåå |
| | | if (!statusTypeId) { |
| | | return { |
| | | disabled: true, |
| | | options: [], |
| | | placeholder: 'è¯¥åæºæªè®¾ç½®ãåæºç¶æç»ãï¼æ å¯éåæºé¶æ®µ', |
| | | }; |
| | | } |
| | | const statusList = await getBusinessStatusSimpleList(statusTypeId); |
| | | const options = statusList.map((item) => ({ |
| | | label: `${item.name}(èµ¢åçï¼${item.percent}%)`, |
| | | value: item.id, |
| | | })); |
| | | return { |
| | | disabled: false, |
| | | options, |
| | | placeholder: 'è¯·éæ©åæºé¶æ®µ', |
| | | }; |
| | | }, |
| | | // æªè®¾ç½®åæºç¶æç»æ¶ä¸åå¿
å¡«æ ¡éªï¼æ¤æ¶ä¹æ²¡æé¶æ®µå¯ä¾éæ©ï¼ |
| | | rules: () => (formData.value?.statusTypeId ? 'required' : null), |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | ]; |
| | | } |
| | |
| | | }, |
| | | { |
| | | fieldName: 'discountedPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | fixed: 'right', |
| | | minWidth: 120, |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: '产åéé¢', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | fixed: 'right', |
| | | title: 'å计éé¢', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | // TODO èè¿ |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpPurchaseInApi.PurchaseInItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpPurchaseInApi.PurchaseInItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpPurchaseInApi.PurchaseInItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | { field: 'supplierName', title: 'ä¾åºå', minWidth: 120 }, |
| | | { field: 'orderTime', title: 'è®¢åæ¶é´', width: 120, formatter: 'formatDate' }, |
| | | { field: 'totalCount', title: 'å计æ°é', width: 100 }, |
| | | { field: 'totalPrice', title: 'å计éé¢', width: 100 }, |
| | | { field: 'totalPrice', title: 'å«ç¨å计', width: 100 }, |
| | | ]; |
| | | } |
| | | |
| | |
| | | <div>订åå·ï¼{{ selectedItem.no || '-' }}</div> |
| | | <div>ä¾åºåï¼{{ selectedItem.supplierName || '-' }}</div> |
| | | <div>è®¢åæ¶é´ï¼{{ selectedItem.orderTime || '-' }}</div> |
| | | <div>å计éé¢ï¼{{ selectedItem.totalPrice || '-' }} å
</div> |
| | | <div>å«ç¨å计ï¼{{ selectedItem.totalPrice || '-' }} å
</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | |
| | | return z |
| | | .number() |
| | | .min(0, '订éä¸è½å°äº0') |
| | | .max(values.totalPrice, '订éä¸è½å¤§äºä¼æ åéé¢'); |
| | | .max(values.totalPrice, '订éä¸è½å¤§äºä¼æ åå«ç¨éé¢'); |
| | | } |
| | | return z.number().min(0, '订éä¸è½å°äº0'); |
| | | }, |
| | |
| | | }, |
| | | { |
| | | fieldName: 'totalPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPercent', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'ç¨é¢å计', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | render: (val) => erpCountInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å计éé¢', |
| | | label: 'å«ç¨å计éé¢', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | |
| | | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: 'åä»·ï¼åèä»·ï¼', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'é¢ä¼°éé¢', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPercent', |
| | |
| | | minWidth: 100, |
| | | fixed: 'right', |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | slots: { default: 'totalTaxInclusivePrice' }, |
| | | }, |
| | | { |
| | | field: 'demandTime', |
| | |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'é¢ä¼°éé¢', |
| | | title: 'å«ç¨éé¢', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: 'åä»·ï¼åèä»·ï¼', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'é¢ä¼°éé¢', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | |
| | | title: 'ç¨ç(%)', |
| | | minWidth: 90, |
| | | formatter: ({ cellValue }) => (cellValue ? `${cellValue}%` : '-'), |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'totalTaxInclusivePrice', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | formatter: ({ row }) => |
| | | erpPriceInputFormatter((row.totalPrice || 0) + (row.taxPrice || 0)) || '-', |
| | | }, |
| | | { field: 'demandTime', title: 'éæ±æ¥æ', minWidth: 110 }, |
| | | { |
| | |
| | | render: (val) => erpCountInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å计éé¢', |
| | | label: 'å«ç¨å计éé¢', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | |
| | | |
| | | const tableData = ref<ErpPurchaseRequestApi.PurchaseRequestItem[]>([]); |
| | | |
| | | /** è·åè¡¨æ ¼åè®¡æ°æ® */ |
| | | /** è·åè¡¨æ ¼åè®¡æ°æ®ï¼è¡ä¸ totalPrice 为ä¸å«ç¨éé¢ï¼å«ç¨å计éå ä¸ç¨é¢ï¼ */ |
| | | const summaries = computed(() => { |
| | | return { |
| | | count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0), |
| | | totalPrice: tableData.value.reduce( |
| | | (sum, item) => { |
| | | const price = erpPriceMultiply(item.productPrice || 0, item.count || 0) ?? 0; |
| | | return sum + price; |
| | | }, |
| | | (sum, item) => sum + (item.totalPrice || 0), |
| | | 0, |
| | | ), |
| | | taxPrice: tableData.value.reduce((sum, item) => sum + (item.taxPrice || 0), 0), |
| | | }; |
| | | }); |
| | | |
| | | /** å«ç¨å计 = ä¸å«ç¨éé¢ + ç¨é¢ */ |
| | | const totalTaxInclusivePrice = computed( |
| | | () => summaries.value.totalPrice + summaries.value.taxPrice, |
| | | ); |
| | | |
| | | /** è¡¨æ ¼é
ç½® */ |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | |
| | | handleRowChange(row); |
| | | } |
| | | |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpPurchaseRequestApi.PurchaseRequestItem) { |
| | | if (row.productPrice && row.count) { |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = taxInclusivePrice - row.taxPrice; |
| | | } |
| | | } |
| | | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | | } else { |
| | | tableData.value[index] = row; |
| | | } |
| | | // 计ç®é¢ä¼°éé¢ |
| | | if (row.productPrice && row.count) { |
| | | row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | } |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpPurchaseRequestApi.PurchaseRequestItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | /> |
| | | <span v-else>{{ row.taxPercent ? `${row.taxPercent}%` : '-' }}</span> |
| | | </template> |
| | | <template #totalTaxInclusivePrice="{ row }"> |
| | | <span>{{ erpPriceInputFormatter((row.totalPrice || 0) + (row.taxPrice || 0)) }}</span> |
| | | </template> |
| | | <template #demandTime="{ row }"> |
| | | <DatePicker |
| | | v-if="!disabled" |
| | |
| | | <span class="font-medium text-foreground">å计ï¼</span> |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span>é¢ä¼°éé¢ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }}</span> |
| | | <span>ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }}</span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span>å«ç¨å计ï¼{{ erpPriceInputFormatter(totalTaxInclusivePrice) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | }, |
| | | { |
| | | fieldName: 'discountedPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | fixed: 'right', |
| | | minWidth: 120, |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: '产åéé¢', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | fixed: 'right', |
| | | title: 'å计éé¢', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | // TODO èè¿ |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | { field: 'customerName', title: '客æ·', minWidth: 120 }, |
| | | { field: 'orderTime', title: 'è®¢åæ¶é´', width: 120, formatter: 'formatDate' }, |
| | | { field: 'totalCount', title: 'å计æ°é', width: 100 }, |
| | | { field: 'totalPrice', title: 'å计éé¢', width: 100 }, |
| | | { field: 'totalPrice', title: 'å«ç¨å计', width: 100 }, |
| | | ]; |
| | | } |
| | | |
| | |
| | | <div>订åå·ï¼{{ selectedItem.no || '-' }}</div> |
| | | <div>客æ·ï¼{{ selectedItem.customerName || '-' }}</div> |
| | | <div>è®¢åæ¶é´ï¼{{ selectedItem.orderTime || '-' }}</div> |
| | | <div>å计éé¢ï¼{{ selectedItem.totalPrice || '-' }} å
</div> |
| | | <div>å«ç¨å计ï¼{{ selectedItem.totalPrice || '-' }} å
</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | |
| | | }, |
| | | { |
| | | fieldName: 'totalPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | return z |
| | | .number() |
| | | .min(0, '订éä¸è½å°äº0') |
| | | .max(values.totalPrice, 'æ¶å订éä¸è½å¤§äºä¼æ åéé¢'); |
| | | .max(values.totalPrice, 'æ¶å订éä¸è½å¤§äºä¼æ åå«ç¨éé¢'); |
| | | } |
| | | return z.number().min(0, '订éä¸è½å°äº0').optional(); |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPercent', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'ç¨é¢å计', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | fixed: 'right', |
| | | formatter: 'formatAmount2', |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | render: (val) => erpCountInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å计éé¢', |
| | | label: 'å«ç¨å计éé¢', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | |
| | | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpSaleOrderApi.SaleOrderItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpSaleOrderApi.SaleOrderItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpSaleOrderApi.SaleOrderItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | // é»è®¤éè¦ç产 |
| | | if (row.needProduction === undefined) { |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | } |
| | | |
| | | /** |
| | | * æç»è¡ï¼å端ä¸è¿åæç»è¡ç totalProductPrice/totalPriceï¼éæåä»·Ãæ°é计ç®ï¼ |
| | | * éé¢ = åä»· à æ°éï¼ç¨é¢ = éé¢ Ã ç¨çï¼å«ç¨éé¢ = éé¢ + ç¨é¢ï¼ |
| | | * æç»è¡ï¼ä¼å
ç¨å端è¿åå¼ï¼ç¼ºçæ¶æãå价为å«ç¨åä»·ã计ç®ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ï¼ |
| | | */ |
| | | const printRows = computed(() => |
| | | (printData.value.items || []).map((item) => { |
| | | const totalProductPrice = |
| | | item.totalProductPrice ?? multiplyPrice(item.productPrice, item.count) ?? 0; |
| | | const taxInclusivePrice = multiplyPrice(item.productPrice, item.count); |
| | | const taxPrice = |
| | | item.taxPrice ?? multiplyPrice(totalProductPrice, (item.taxPercent ?? 0) / 100) ?? 0; |
| | | const totalPrice = item.totalPrice ?? totalProductPrice + taxPrice; |
| | | item.taxPrice ?? multiplyPrice(taxInclusivePrice, (item.taxPercent ?? 0) / 100) ?? 0; |
| | | const totalPrice = item.totalPrice ?? taxInclusivePrice ?? 0; |
| | | const totalProductPrice = item.totalProductPrice ?? totalPrice - taxPrice; |
| | | return { ...item, totalProductPrice, taxPrice, totalPrice }; |
| | | }), |
| | | ); |
| | | |
| | | /** æç»åè®¡ï¼æ°é/éé¢ä¼å
å订å头ï¼å端æå¨å¼ï¼ï¼ç¨é¢ä¸å«ç¨é颿æç»ç´¯å ï¼è®¢å头 totalPrice ä¸ºä¼æ åéé¢ï¼å¦å¨éé¢ä¿¡æ¯åºå±ç¤ºï¼ */ |
| | | /** æç»åè®¡ï¼æ°é/éé¢ä¼å
å订å头ï¼å端æå¨å¼ï¼ï¼ç¨é¢ä¸å«ç¨é颿æç»ç´¯å ï¼è®¢å头 totalPrice ä¸ºä¼æ åå«ç¨éé¢ï¼å¦å¨éé¢ä¿¡æ¯åºå±ç¤ºï¼ */ |
| | | const summaries = computed(() => { |
| | | const rows = printRows.value; |
| | | const count = rows.reduce((sum, item) => sum + (item.count || 0), 0); |
| | |
| | | <th |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold" |
| | | > |
| | | 产ååä»·(å
) |
| | | </th> |
| | | <th |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold" |
| | | > |
| | | éé¢(å
) |
| | | å«ç¨åä»·(å
) |
| | | </th> |
| | | <th |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold" |
| | | > |
| | | ç¨ç(%) |
| | | </th> |
| | | <th |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold" |
| | | > |
| | | ä¸å«ç¨éé¢(å
) |
| | | </th> |
| | | <th |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold" |
| | |
| | | {{ formatPrice(item.productPrice) }} |
| | | </td> |
| | | <td class="border border-solid border-[#dcdfe6] p-2 text-right"> |
| | | {{ formatPrice(item.totalProductPrice) }} |
| | | {{ formatPrice(item.taxPercent) }} |
| | | </td> |
| | | <td class="border border-solid border-[#dcdfe6] p-2 text-right"> |
| | | {{ formatPrice(item.taxPercent) }} |
| | | {{ formatPrice(item.totalProductPrice) }} |
| | | </td> |
| | | <td class="border border-solid border-[#dcdfe6] p-2 text-right"> |
| | | {{ formatPrice(item.taxPrice) }} |
| | |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2" |
| | | ></td> |
| | | <td |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2" |
| | | ></td> |
| | | <td |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right" |
| | | > |
| | | {{ formatPrice(summaries.totalProductPrice) }} |
| | | </td> |
| | | <td |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2" |
| | | ></td> |
| | | <td |
| | | class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right" |
| | | > |
| | |
| | | > |
| | | <div>伿 ç(%)ï¼{{ formatPrice(printData.discountPercent) }}</div> |
| | | <div>仿¬¾ä¼æ (å
)ï¼{{ formatPrice(printData.discountPrice) }}</div> |
| | | <div>伿 åéé¢(å
)ï¼{{ formatPrice(printData.totalPrice) }}</div> |
| | | <div>伿 åå«ç¨éé¢(å
)ï¼{{ formatPrice(printData.totalPrice) }}</div> |
| | | <div>æ¶å订é(å
)ï¼{{ formatPrice(printData.depositPrice) }}</div> |
| | | </div> |
| | | |
| | |
| | | }, |
| | | { |
| | | fieldName: 'discountedPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | fixed: 'right', |
| | | minWidth: 120, |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: '产åéé¢', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | fixed: 'right', |
| | | title: 'å计éé¢', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpSaleOutApi.SaleOutItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpSaleOutApi.SaleOutItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpSaleOutApi.SaleOutItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | }, |
| | | { |
| | | fieldName: 'discountedPrice', |
| | | label: '伿 åéé¢', |
| | | label: '伿 åå«ç¨éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '伿 åéé¢', |
| | | placeholder: '伿 åå«ç¨éé¢', |
| | | precision: 2, |
| | | formatter: erpPriceInputFormatter, |
| | | disabled: true, |
| | |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: '产ååä»·', |
| | | title: 'å«ç¨åä»·(å
)', |
| | | fixed: 'right', |
| | | minWidth: 120, |
| | | slots: { default: 'productPrice' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: '产åéé¢', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | |
| | | slots: { default: 'taxPercent' }, |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | fixed: 'right', |
| | | title: 'ä¸å«ç¨éé¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | fixed: 'right', |
| | | field: 'taxPrice', |
| | | title: 'ç¨é¢', |
| | | title: 'ç¨é¢(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | fixed: 'right', |
| | | title: 'å计éé¢', |
| | | title: 'å«ç¨å计(å
)', |
| | | minWidth: 120, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | |
| | | }, |
| | | { |
| | | field: 'totalProductPrice', |
| | | title: 'éé¢å计', |
| | | title: 'ä¸å«ç¨éé¢å计', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | |
| | | |
| | | /** å¤çè¡æ°æ®åæ´ */ |
| | | function handleRowChange(row: any) { |
| | | recalcRow(row); |
| | | const index = tableData.value.findIndex((item) => item.seq === row.seq); |
| | | if (index === -1) { |
| | | tableData.value.push(row); |
| | |
| | | emit('update:items', [...tableData.value]); |
| | | } |
| | | |
| | | /** åå§åè¡æ°æ® */ |
| | | function initRow(row: ErpSaleReturnApi.SaleReturnItem) { |
| | | /** |
| | | * éç®è¡éé¢ï¼å价为**å«ç¨**åä»·ï¼ |
| | | * å«ç¨éé¢ = å«ç¨åä»· à æ°éï¼ç¨é¢ = å«ç¨éé¢ Ã ç¨çï¼ä¸å«ç¨éé¢ = å«ç¨éé¢ - ç¨é¢ |
| | | */ |
| | | function recalcRow(row: ErpSaleReturnApi.SaleReturnItem) { |
| | | if (row.productPrice && row.count) { |
| | | row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0; |
| | | row.taxPrice = |
| | | erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalPrice = row.totalProductPrice + row.taxPrice; |
| | | erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0; |
| | | row.totalProductPrice = taxInclusivePrice - row.taxPrice; |
| | | row.totalPrice = taxInclusivePrice; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åå§åè¡æ°æ® |
| | | * å·²æåæ®çæç»è¡ï¼å¸¦ idï¼æ²¿ç¨å端è¿åçéé¢ï¼é¿å
åå²åæ®è¢«æ°å£å¾è¦çï¼ |
| | | * åªææªä¿åçæ°å¢è¡æææ°å£å¾éç®ã |
| | | */ |
| | | function initRow(row: ErpSaleReturnApi.SaleReturnItem) { |
| | | if (!row.id) { |
| | | recalcRow(row); |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="flex space-x-4"> |
| | | <span>æ°éï¼{{ erpCountInputFormatter(summaries.count) }}</span> |
| | | <span> |
| | | éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | ä¸å«ç¨éé¢ï¼{{ erpPriceInputFormatter(summaries.totalProductPrice) }} |
| | | </span> |
| | | <span>ç¨é¢ï¼{{ erpPriceInputFormatter(summaries.taxPrice) }}</span> |
| | | <span> |
| | | ç¨é¢å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | å«ç¨å计ï¼{{ erpPriceInputFormatter(summaries.totalPrice) }} |
| | | </span> |
| | | </div> |
| | | </div> |