ae5f1ea03be87c76e0eefd0a00c34dab4163ec56..ee42bf1badae06026efa79dc17d2a541297ab49b
13 小时以前 gaoluyang
采购管理整体样式优化,搜索条件修改
dev
ee42bf 对比 | 目录
17 小时以前 gaoluyang
销售管理整体样式优化,搜索条件修改
a26e8d 对比 | 目录
21 小时以前 gaoluyang
头部样式修改、适配不同机型
77861f 对比 | 目录
已修改28个文件
已添加2个文件
4269 ■■■■■ 文件已修改
src/components/PageHeader.vue 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/clientVisit/detail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/clientVisit/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/collaborativeApproval/index.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/ledger/detail.vue 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/ledger/index.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/repair/add.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/repair/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/mine.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/invoiceEntry/index.vue 230 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/paymentEntry/index.vue 220 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/paymentLedger/detail.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/paymentLedger/index.vue 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/procurementInvoiceLedger/index.vue 281 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/procurementLedger/index.vue 201 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/receiptPaymentHistory/index.vue 234 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/invoiceLedger/detail.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/invoiceLedger/index.vue 226 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/invoicingRegistration/index.vue 257 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPayment/index.vue 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPaymentHistory/index.vue 214 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPaymentLedger/detail.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/receiptPaymentLedger/index.vue 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/salesAccount/detail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/salesAccount/index.vue 278 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/procurement-common.scss 420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/sales-common.scss 337 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PageHeader.vue
@@ -1,20 +1,17 @@
<template>
    <view class="page-header">
        <view class="header-left">
            <up-icon
                name="arrow-left"
                size="20"
                color="#333"
                @click="handleBack"
            ></up-icon>
        </view>
        <view class="header-center">
            <text class="page-title">{{ title }}</text>
        </view>
        <view class="header-right" v-if="$slots.right">
            <slot name="right"></slot>
        </view>
    </view>
  <up-navbar
    :title="title"
    :show-back="showBack"
    @leftClick="handleBack"
    :color="color"
    :border="true"
    :fixed="true"
    :placeholder="true"
  >
    <template v-if="$slots.right" #right>
      <slot name="right"></slot>
    </template>
  </up-navbar>
</template>
<script setup>
@@ -22,21 +19,41 @@
// å®šä¹‰ç»„件属性
const props = defineProps({
    // é¡µé¢æ ‡é¢˜
    title: {
        type: String,
        default: ''
    },
    // æ˜¯å¦æ˜¾ç¤ºè¿”回按钮
    showBack: {
        type: Boolean,
        default: true
    },
    // è‡ªå®šä¹‰è¿”回事件
    customBack: {
        type: Function,
        default: null
    }
  // é¡µé¢æ ‡é¢˜
  title: {
    type: String,
    default: ''
  },
  // æ˜¯å¦æ˜¾ç¤ºè¿”回按钮
  showBack: {
    type: Boolean,
    default: true
  },
  // è‡ªå®šä¹‰è¿”回事件
  customBack: {
    type: Function,
    default: null
  },
  // èƒŒæ™¯è‰²
  background: {
    type: String,
    default: '#ffffff'
  },
  // æ–‡å­—颜色
  color: {
    type: String,
    default: '#333333'
  },
  // æ˜¯å¦æ˜¾ç¤ºåº•部分割线
  borderBottom: {
    type: Boolean,
    default: true
  },
  // æ˜¯å¦å›ºå®šåœ¨é¡¶éƒ¨
  isFixed: {
    type: Boolean,
    default: true
  }
});
// å®šä¹‰äº‹ä»¶
@@ -44,60 +61,28 @@
// å¤„理返回事件
const handleBack = () => {
    if (props.customBack) {
        props.customBack();
    } else {
        emit('back');
        // uni.navigateBack();
    }
  if (props.customBack) {
    props.customBack();
  } else {
    emit('back');
    // uni.navigateBack();
  }
};
</script>
<style scoped lang="scss">
.page-header {
    background: #ffffff;
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #f0f0f0;
    position: sticky;
    /* å…¼å®¹ iOS åˆ˜æµ·/灵动岛安全区 */
    padding-top: calc(env(safe-area-inset-top));
    top: 0;
    z-index: 100;
    position: relative;
}
/* up-navbar ç»„件已经内置了安全区域适配,不需要额外的样式调整 */
.header-left {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 30px; /* ç¡®ä¿ç‚¹å‡»åŒºåŸŸè¶³å¤Ÿå¤§ */
}
.header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: 0;
    right: 0;
    pointer-events: none;
}
.page-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    pointer-events: auto;
}
.header-right {
    display: flex;
    align-items: center;
    min-width: 44px; /* ç¡®ä¿å³ä¾§åŒºåŸŸæœ‰è¶³å¤Ÿç©ºé—´ */
    justify-content: flex-end;
/* æš—色模式适配 */
@media (prefers-color-scheme: dark) {
  :deep(.up-navbar) {
    background: #1e1f24 !important;
    .up-navbar__title {
      color: #e9edf3 !important;
    }
    .up-navbar__back {
      color: #e9edf3 !important;
    }
  }
}
</style>
src/config.js
@@ -2,7 +2,7 @@
const config = {
  //  baseUrl: 'https://vue.ruoyi.vip/prod-api',
  // baseUrl: 'http://localhost/prod-api',
  baseUrl: 'http://114.132.189.42:8089',
  baseUrl: 'http://114.132.189.42:9036',
   //cloud后台网关地址
  //  baseUrl: 'http://192.168.10.3:8080',
   // åº”用信息
src/pages/cooperativeOffice/clientVisit/detail.vue
@@ -53,7 +53,7 @@
            placeholder="请输入拜访地点"
          >
            <template #suffix>
              <u-icon name="map" @click.stop="getCurrentLocation" class="location-icon" />
              <u-icon name="map" @click="getCurrentLocation" class="location-icon" />
            </template>
          </u-input>
        </u-form-item>
src/pages/cooperativeOffice/clientVisit/index.vue
@@ -165,6 +165,7 @@
// æŸ¥è¯¢åˆ—表
const getList = () => {
  showLoadingToast('加载中...')
  const params = {
    current: -1,
    size: -1,
@@ -173,12 +174,27 @@
  getVisitRecords(params)
    .then((res) => {
      visitList.value = res.records || res.data?.records || []
      closeToast()
    })
    .catch(() => {
      closeToast()
      showToast('获取数据失败')
    })
}
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
  uni.showLoading({
    title: message,
    mask: true
  });
};
// å…³é—­æç¤º
const closeToast = () => {
  uni.hideLoading();
};
// æ–°å¢žæ‹œè®¿ - è·³è½¬åˆ°ç™»è®°é¡µé¢
const addVisit = () => {
  uni.navigateTo({
src/pages/cooperativeOffice/collaborativeApproval/index.vue
@@ -133,6 +133,7 @@
    };
    // æŸ¥è¯¢åˆ—表
    const getList = () => {
        showLoadingToast('加载中...')
        const page = {
            current: -1,
            size: -1,
@@ -142,11 +143,25 @@
            })
            .then((res) => {
                ledgerList.value = res.data.records;
                closeToast()
            })
            .catch(() => {
                // tableLoading.value = false;
                closeToast()
            });
    };
    // æ˜¾ç¤ºåŠ è½½æç¤º
    const showLoadingToast = (message) => {
        uni.showLoading({
            title: message,
            mask: true
        });
    };
    // å…³é—­æç¤º
    const closeToast = () => {
        uni.hideLoading();
    };
    // æ˜¾ç¤ºç­›é€‰é€‰é¡¹
    const showFilterOptions = () => {
        uni.showActionSheet({
src/pages/equipmentManagement/ledger/detail.vue
@@ -1,10 +1,10 @@
<template>
    <view class="equipment-detail">
    <view class="account-detail">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="设备台账详情" @back="goBack" />
        
        <!-- è¡¨å•内容 -->
        <u-form @submit="sendForm" ref="formRef" :rules="formRules" label-width="110">
        <u-form @submit="sendForm" ref="formRef" :model="form" :rules="formRules" label-width="110">
            <!-- åŸºæœ¬ä¿¡æ¯ -->
            <u-cell-group title="基本信息">
                <u-form-item label="设备名称" prop="deviceName" required border-bottom>
@@ -22,13 +22,13 @@
                        clearable
                    />
                </u-form-item>
                <u-form-item label="设备品牌" prop="deviceBrand" required border-bottom>
                <!-- <u-form-item label="设备品牌" prop="deviceBrand" required border-bottom>
                    <u-input
                        v-model="form.deviceBrand"
                        placeholder="请输入设备品牌"
                        clearable
                    />
                </u-form-item>
                </u-form-item> -->
                <u-form-item label="供应商" prop="supplierName" required border-bottom>
                    <u-input
                        v-model="form.supplierName"
@@ -36,13 +36,13 @@
                        clearable
                    />
                </u-form-item>
                <u-form-item label="存放位置" prop="storageLocation" required border-bottom>
                <!-- <u-form-item label="存放位置" prop="storageLocation" required border-bottom>
                    <u-input
                        v-model="form.storageLocation"
                        placeholder="请输入存放位置"
                        clearable
                    />
                </u-form-item>
                </u-form-item> -->
                <u-form-item label="单位" prop="unit" required border-bottom>
                    <u-input
                        v-model="form.unit"
@@ -50,13 +50,13 @@
                        clearable
                    />
                </u-form-item>
                <u-form-item label="启用折旧" prop="enableDepreciation" required border-bottom>
                <!-- <u-form-item label="启用折旧" prop="enableDepreciation" required border-bottom>
                    <u-switch
                        v-model="form.enableDepreciation"
                        :active-value="true"
                        :inactive-value="false"
                    />
                </u-form-item>
                </u-form-item> -->
                <u-form-item label="数量" prop="number" required border-bottom>
                    <u-input
                        v-model="form.number"
@@ -186,9 +186,46 @@
    supplierName: [{ required: true, trigger: "blur", message: "请输入" }],
    storageLocation: [{ required: true, trigger: "blur", message: "请输入" }],
    unit: [{ required: true, trigger: "blur", message: "请输入" }],
    number: [{ required: true, trigger: "blur", message: "请输入" }],
    taxIncludingPriceUnit: [{ required: true, trigger: "blur", message: "请输入" }],
    taxRate: [{ required: true, trigger: "change", message: "请输入" }],
    // æ•°å­—类型字段需要特殊处理,确保有数值时不会触发必填校验
    number: [{
        required: true,
        trigger: "blur",
        message: "请输入",
        validator: (rule, value, callback) => {
            // å¯¹äºŽæ•°å­—类型,检查是否为有效数字(包括0)
            if (value !== undefined && value !== null && value !== '' && !isNaN(value)) {
                callback();
            } else {
                callback(new Error('请输入数量'));
            }
        }
    }],
    taxIncludingPriceUnit: [{
        required: true,
        trigger: "blur",
        message: "请输入",
        validator: (rule, value, callback) => {
            // å¯¹äºŽæ•°å­—类型,检查是否为有效数字(包括0)
            if (value !== undefined && value !== null && value !== '' && !isNaN(value)) {
                callback();
            } else {
                callback(new Error('请输入含税单价'));
            }
        }
    }],
    taxRate: [{
        required: true,
        trigger: "change",
        message: "请选择",
        validator: (rule, value, callback) => {
            // æ£€æŸ¥ç¨ŽçŽ‡æ˜¯å¦ä¸ºæœ‰æ•ˆæ•°å­—
            if (value !== undefined && value !== null && value !== '' && !isNaN(value)) {
                callback();
            } else {
                callback(new Error('请选择税率'));
            }
        }
    }],
    createTime: [{ required: true, trigger: "change", message: "请选择" }],
};
@@ -218,6 +255,8 @@
    }
    try {
        const { code, data } = await getLedgerById(id);
        console.log(data);
        if (code == 200) {
            form.value.deviceName = data.deviceName;
            form.value.deviceModel = data.deviceModel;
@@ -232,6 +271,11 @@
            form.value.taxRate = data.taxRate;
            form.value.unTaxIncludingPriceTotal = data.unTaxIncludingPriceTotal;
            form.value.createTime = data.createTime;
            // æ•°æ®åŠ è½½å®ŒæˆåŽï¼Œé‡ç½®è¡¨å•éªŒè¯çŠ¶æ€
            setTimeout(() => {
                clearValidate();
            }, 100);
        }
    } catch (e) {
        showToast('获取详情失败');
@@ -240,11 +284,12 @@
// æ•°å­¦è®¡ç®—
const mathNum = () => {
    if (!form.value.taxIncludingPriceUnit) {
    // åªæœ‰åœ¨æ–°å¢žæ¨¡å¼æˆ–者字段确实为空时才显示提示
    if (operationType.value !== 'edit' || (form.value.taxIncludingPriceUnit === undefined || form.value.taxIncludingPriceUnit === '')) {
        showToast("请输入单价");
        return;
    }
    if (!form.value.number) {
    if (operationType.value !== 'edit' || (form.value.number === undefined || form.value.number === '')) {
        showToast("请输入数量");
        return;
    }
@@ -265,47 +310,65 @@
    formRef.value?.clearValidate();
};
// é‡ç½®è¡¨å•数据和校验状态
const resetForm = () => {
    form.value = {
        deviceName: undefined,
        deviceModel: undefined,
        deviceBrand: undefined,
        supplierName: undefined,
        storageLocation: undefined,
        unit: undefined,
        enableDepreciation: false,
        number: undefined,
        taxIncludingPriceUnit: undefined,
        taxIncludingPriceTotal: undefined,
        taxRate: undefined,
        unTaxIncludingPriceTotal: undefined,
        createTime: dayjs().format("YYYY-MM-DD"),
    };
};
const resetFormAndValidate = () => {
    resetForm();
    clearValidate();
};
// æäº¤è¡¨å•
const sendForm = async () => {
    try {
        // æ‰‹åŠ¨éªŒè¯è¡¨å•
        await formRef.value?.validate();
        // æ£€æŸ¥å¿…填字段
        let isValid = true;
        let errorMessage = '';
        // æ£€æŸ¥æ–‡æœ¬ç±»åž‹å¿…填字段
        if (!form.value.deviceName || form.value.deviceName.trim() === '') {
            isValid = false;
            errorMessage = '请输入设备名称';
        } else if (!form.value.deviceModel || form.value.deviceModel.trim() === '') {
            isValid = false;
            errorMessage = '请输入规格型号';
        } else if (!form.value.deviceBrand || form.value.deviceBrand.trim() === '') {
            isValid = false;
            errorMessage = '请输入设备品牌';
        } else if (!form.value.supplierName || form.value.supplierName.trim() === '') {
            isValid = false;
            errorMessage = '请输入供应商';
        } else if (!form.value.storageLocation || form.value.storageLocation.trim() === '') {
            isValid = false;
            errorMessage = '请输入存放位置';
        } else if (!form.value.unit || form.value.unit.trim() === '') {
            isValid = false;
            errorMessage = '请输入单位';
        }
        // æ£€æŸ¥æ•°å­—类型必填字段
        else if (form.value.number === undefined || form.value.number === null || form.value.number === '' || isNaN(form.value.number)) {
            isValid = false;
            errorMessage = '请输入数量';
        } else if (form.value.taxIncludingPriceUnit === undefined || form.value.taxIncludingPriceUnit === null || form.value.taxIncludingPriceUnit === '' || isNaN(form.value.taxIncludingPriceUnit)) {
            isValid = false;
            errorMessage = '请输入含税单价';
        } else if (form.value.taxRate === undefined || form.value.taxRate === null || form.value.taxRate === '' || isNaN(form.value.taxRate)) {
            isValid = false;
            errorMessage = '请选择税率';
        } else if (!form.value.createTime || form.value.createTime.trim() === '') {
            isValid = false;
            errorMessage = '请选择录入日期';
        }
        // å¦‚果验证失败,显示错误提示
        if (!isValid) {
            showToast(errorMessage);
            return;
        }
        // éªŒè¯é€šè¿‡ï¼Œæ˜¾ç¤ºæäº¤ä¸­æç¤º
        showToast('正在提交表单...');
        
        loading.value = true;
        const id = getPageId();
        
        // å‡†å¤‡æäº¤æ•°æ®ï¼ŒcreateTime åŠ ä¸Šå½“å‰æ—¶åˆ†ç§’
        const submitData = { ...form.value };
        if (submitData.createTime && !submitData.createTime.includes(':')) {
            // å¦‚æžœ createTime åªåŒ…含日期,添加当前时分秒
            submitData.createTime = submitData.createTime + ' ' + dayjs().format('HH:mm:ss');
        }
        
        const { code } = id
        const { code, res } = id
            ? await editLedger({ id: id, ...submitData })
            : await addLedger(submitData);
        
@@ -316,47 +379,52 @@
            }, 1500);
        } else {
            loading.value = false;
            console.log(res);
        }
    } catch (e) {
        loading.value = false;
        showToast('表单验证失败');
        showToast('提交失败');
    }
};
// è¿”回上一页
const goBack = () => {
    // ä½¿ç”¨åŽæ¸…除storage中的ID,避免数据残留
            uni.removeStorageSync('ledgerId');
    uni.navigateBack();
};
// èŽ·å–é¡µé¢å‚æ•°
const getPageParams = () => {
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const options = currentPage.options;
    if (options.id) {
        // ç¼–辑模式,获取详情
        loadForm(options.id);
    } else {
        // æ–°å¢žæ¨¡å¼
    try {
        // ä¼˜å…ˆä»Žstorage中获取ID
        const ledgerId = uni.getStorageSync('ledgerId');
        if (ledgerId) {
            // ç¼–辑模式,获取详情
            loadForm(ledgerId);
        } else {
            // æ–°å¢žæ¨¡å¼
            operationType.value = 'add';
        }
    } catch (e) {
        operationType.value = 'add';
    }
};
// èŽ·å–é¡µé¢ID
const getPageId = () => {
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const options = currentPage.options;
    return options.id;
};
// ç¡®è®¤ç¨ŽçŽ‡é€‰æ‹©
const onTaxRateConfirm = (e) => {
    form.value.taxRate = e.value;
    mathNum(); // é‡æ–°è®¡ç®—
    try {
        // ä¼˜å…ˆä»Žstorage中获取ID
        const ledgerId = uni.getStorageSync('ledgerId');
        if (ledgerId) {
            return ledgerId;
        }
    } catch (e) {
        console.error('获取页面ID出错:', e);
    }
    return null;
};
// é€‰æ‹©ç¨Žçއ
src/pages/equipmentManagement/ledger/index.vue
@@ -143,6 +143,7 @@
// æŸ¥è¯¢åˆ—表(current/size å›ºå®šä¼  -1)
const getList = () => {
  showLoadingToast('加载中...')
  const params = {
    current: -1,
    size: -1,
@@ -150,12 +151,27 @@
  }
  getLedgerPage(params)
    .then((res) => {
      ledgerList.value = res.records || res.data?.records || []
      ledgerList.value = res.data.records
      closeToast()
    })
    .catch(() => {
      closeToast()
      showToast('获取数据失败')
    })
}
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
  uni.showLoading({
    title: message,
    mask: true
  });
};
// å…³é—­æç¤º
const closeToast = () => {
  uni.hideLoading();
};
// æ–°å¢ž - è·³è½¬åˆ°è¯¦æƒ…页面
const add = () => {
@@ -167,8 +183,9 @@
// ç¼–辑 - è·³è½¬åˆ°è¯¦æƒ…页面
const edit = (id) => {
  if (!id) return
  uni.setStorageSync('ledgerId', id)
  uni.navigateTo({
    url: `/pages/equipmentManagement/ledger/detail?id=${id}`
    url: '/pages/equipmentManagement/ledger/detail'
  })
}
src/pages/equipmentManagement/repair/add.vue
@@ -4,7 +4,7 @@
        <PageHeader :title="operationType === 'edit' ? '编辑报修' : '新增报修'" @back="goBack" />
        
        <!-- è¡¨å•内容 -->
        <u-form @submit="sendForm" ref="formRef" :rules="formRules" label-width="110" input-align="right" error-message-align="right">
        <u-form @submit="sendForm" ref="formRef" :rules="formRules" :model="form" label-width="110">
            <!-- åŸºæœ¬ä¿¡æ¯ -->
            <u-cell-group title="基本信息">
                <u-form-item label="设备名称" prop="deviceLedgerId" required border-bottom>
@@ -204,11 +204,6 @@
    deviceNameText.value = '';
};
const resetFormAndValidate = () => {
    resetForm();
    clearValidate();
};
// æ‰«æäºŒç»´ç åŠŸèƒ½
const startScan = () => {
    if (isScanning.value) {
@@ -313,18 +308,37 @@
const sendForm = async () => {
    try {
        // æ‰‹åŠ¨éªŒè¯è¡¨å•
        await formRef.value?.validate();
        let isValid = true;
        let errorMessage = '';
        if (!form.value.deviceLedgerId) {
            isValid = false;
            errorMessage = '请选择设备名称';
        } else if (!form.value.repairTime || form.value.repairTime.trim() === '') {
            isValid = false;
            errorMessage = '请选择报修日期';
        } else if (!form.value.repairName || form.value.repairName.trim() === '') {
            isValid = false;
            errorMessage = '请输入报修人';
        } else if (!form.value.remark || form.value.remark.trim() === '') {
            isValid = false;
            errorMessage = '请输入故障现象';
        }
        if (!isValid) {
            showToast(errorMessage);
            return;
        }
        loading.value = true;
        const id = getPageId();
        // å‡†å¤‡æäº¤æ•°æ®
        const submitData = { ...form.value };
        const { code } = id
            ? await editRepair({ id: id, ...submitData })
            : await addRepair(submitData);
        if (code == 200) {
            showToast(`${id ? "编辑" : "新增"}报修成功`);
            setTimeout(() => {
src/pages/equipmentManagement/repair/index.vue
@@ -152,6 +152,7 @@
// æŸ¥è¯¢åˆ—表
const getList = () => {
  showLoadingToast('加载中...')
  const params = {
    current: -1,
    size: -1,
@@ -160,12 +161,27 @@
  getRepairPage(params)
    .then((res) => {
      repairList.value = res.records || res.data?.records || []
      closeToast()
    })
    .catch(() => {
      closeToast()
      showToast('获取数据失败')
    })
}
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
  uni.showLoading({
    title: message,
    mask: true
  });
};
// å…³é—­æç¤º
const closeToast = () => {
  uni.hideLoading();
};
// æ–°å¢žç»´ä¿® - è·³è½¬åˆ°ç»´ä¿®é¡µé¢
const addMaintain = (id) => {
  if (!id) {
src/pages/equipmentManagement/upkeep/index.vue
@@ -168,6 +168,7 @@
// æŸ¥è¯¢åˆ—表
const getList = () => {
  showLoadingToast('加载中...')
  const params = {
    current: -1,
    size: -1,
@@ -177,12 +178,27 @@
    .then((res) => {
      // å¦‚æžœres.data不是数组,设置为空数组
      upkeepList.value = res.records || res.data?.records || []
      closeToast()
    })
    .catch(() => {
      closeToast()
      showToast('获取数据失败')
    })
}
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
  uni.showLoading({
    title: message,
    mask: true
  });
};
// å…³é—­æç¤º
const closeToast = () => {
  uni.hideLoading();
};
// åˆ‡æ¢é€‰æ‹©çŠ¶æ€
const toggleSelection = (item) => {
  const index = multipleList.value.findIndex(selected => selected.id === item.id)
src/pages/index.vue
@@ -433,8 +433,22 @@
    background: linear-gradient(135deg, #f8f9fa 0%, #e3f2fd 100%);
    min-height: 100vh;
    padding: 1.25rem;
    padding-top: env(safe-area-inset-top);
    /* ä¸ºæ‰€æœ‰è®¾å¤‡è®¾ç½®åŸºç¡€padding-top */
    padding-top: 40px;
    position: relative;
    /* iOS设备使用env()函数处理安全区域 */
    padding-top: env(safe-area-inset-top);
    /* ä¸ºå®‰å“设备设置更大的顶部内边距 */
    /* #ifdef APP-PLUS && !MP && !H5 */
    padding-top: 45px;
    /* #endif */
    /* H5和小程序平台的通用样式 */
    /* #ifdef H5 || MP */
    padding-top: 30px;
    /* #endif */
    
    &::before {
        content: '';
@@ -462,11 +476,13 @@
    }
}
/* æœ¬é¡µä¸å†å®šä¹‰ .safe-area-top,已移至全局样式 */
.header-section {
    margin-bottom: 1rem;
    animation: fadeInDown 0.6s ease-out;
    /* ä¸ºå®‰å“设备额外调整头部位置 */
    /* #ifdef APP-PLUS && !MP && !H5 */
    margin-top: 10px;
    /* #endif */
}
.currentFactory {
src/pages/mine.vue
@@ -150,9 +150,23 @@
.mine-page {
  min-height: 100vh;
    padding: 1.25rem;
    padding-top: env(safe-area-inset-top);
    /* ä¸ºæ‰€æœ‰è®¾å¤‡è®¾ç½®åŸºç¡€padding-top */
    padding-top: 40px;
    position: relative;
  background: linear-gradient( 225deg, #E7F1FF 0%, rgba(255,255,255,0) 74%, rgba(255,255,255,0) 100%);
    /* iOS设备使用env()函数处理安全区域 */
    padding-top: env(safe-area-inset-top);
    /* ä¸ºå®‰å“设备设置更大的顶部内边距 */
    /* #ifdef APP-PLUS && !MP && !H5 */
    padding-top: 45px;
    /* #endif */
    /* H5和小程序平台的通用样式 */
    /* #ifdef H5 || MP */
    padding-top: 30px;
    /* #endif */
}
/* é¡¶éƒ¨ä¸ªäººä¿¡æ¯å¡ */
@@ -162,6 +176,11 @@
  align-items: center;
  color: #333;
  margin: 1.25rem 0;
  /* ä¸ºå®‰å“设备额外调整卡片位置 */
    /* #ifdef APP-PLUS && !MP && !H5 */
    margin-top: 15px;
    /* #endif */
  .left {
    display: flex;
src/pages/procurementManagement/invoiceEntry/index.vue
@@ -4,13 +4,15 @@
        <PageHeader title="来票登记" @back="goBack" />
        
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入采购合同号/供应商名称"
                        v-model="searchKeyword"
                        v-model="supplierName"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -96,7 +98,7 @@
const userStore = useUserStore()
// æœç´¢å…³é”®è¯
const searchKeyword = ref('');
const supplierName = ref('');
// é‡‡è´­å°è´¦æ•°æ®
const ledgerList = ref([]);
@@ -107,15 +109,30 @@
};
// æŸ¥è¯¢åˆ—表
const getList = () => {
    showLoadingToast('加载中...')
    const page = {
        current: -1,
        size: -1
    }
    gePurchaseListPage({...page}).then((res) => {
    gePurchaseListPage({...page, supplierName: supplierName.value}).then((res) => {
        ledgerList.value = res.data.records;
        closeToast()
    }).catch(() => {
        // tableLoading.value = false;
        closeToast()
    });
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// å¤„理新增来票
@@ -162,35 +179,9 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
@import '@/styles/procurement-common.scss';
.page-header {
    background: #ffffff;
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #f0f0f0;
    position: sticky;
    /* å…¼å®¹ iOS åˆ˜æµ·/灵动岛安全区 */
    padding-top: env(safe-area-inset-top);
    top: 0;
    z-index: 100;
}
.header-left {
    display: flex;
    align-items: center;
    gap: 8px;
}
// æ¥ç¥¨ç™»è®°ç‰¹æœ‰æ ·å¼
.nav-icon {
    width: 24px;
    height: 24px;
@@ -243,176 +234,7 @@
    border-radius: 2px;
}
.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-tag {
    background: #4caf50;
    border-radius: 4px;
    padding: 2px 4px;
}
.tag-text {
    font-size: 11px;
    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;
}
.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.redlight {
    color: red;
    font-weight: 500;
}
.action-buttons {
    display: flex;
    gap: 12px;
    padding: 0 0 16px 0;
    justify-content: space-between;
}
.action-btn {
    flex: 1;
}
.no-data {
    padding: 40px 0;
    text-align: center;
    color: #999;
}
.fab-button {
    position: fixed;
    bottom: 30px;
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
    bottom: 30px; // ä¸Žå…¶ä»–页面的 calc(30px + env(safe-area-inset-bottom)) ä¸åŒ
}
</style>
src/pages/procurementManagement/paymentEntry/index.vue
@@ -1,17 +1,18 @@
<template>
    <view class="receipt-payment">
    <view class="sales-account">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="付款登记" @back="goBack" />
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="供应商名称/合同号"
                        placeholder="请输入供应商名称/合同号搜索"
                        v-model="searchForm.supplierNameOrContractNo"
                        confirm-type="search"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -135,14 +136,30 @@
// èŽ·å–åˆ—è¡¨æ•°æ®
const getList = () => {
    showLoadingToast('加载中...')
    tableLoading.value = true
    invoiceListPage({ ...searchForm.value, ...page.value }).then((res) => {
        tableLoading.value = false
        tableData.value = res.records || []
        closeToast()
    }).catch(() => {
        tableLoading.value = false
        closeToast()
    })
}
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// æ‰“开新增表单
const openForm = (type, item) => {
@@ -161,201 +178,12 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
@import '@/styles/procurement-common.scss';
.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>
src/pages/procurementManagement/paymentLedger/detail.vue
@@ -89,17 +89,16 @@
// è¿”回上一页
const goBack = () => {
    uni.removeStorageSync('supplierId')
    uni.navigateBack();
};
// èŽ·å–é¡µé¢å‚æ•°
const getPageParams = () => {
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const options = currentPage.options;
    if (options.supplierId) {
        supplierId.value = options.supplierId;
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å–ä¾›åº”å•†ID
    const storedSupplierId = uni.getStorageSync('supplierId');
    if (storedSupplierId) {
        supplierId.value = storedSupplierId;
    }
};
@@ -112,6 +111,7 @@
        });
        return;
    }
    showLoadingToast('加载中...')
    const param = {
        supplierId: supplierId.value,
        current: -1,
@@ -119,7 +119,9 @@
    };
    paymentLedgerList(param).then((res) => {
        tableData.value = res.data.records;
        closeToast()
    }).catch(() => {
        closeToast()
        uni.showToast({
            title: '查询失败',
            icon: 'error'
@@ -132,6 +134,19 @@
    return amount ? parseFloat(amount).toFixed(2) : '0.00';
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
onMounted(() => {
    // é¡µé¢åŠ è½½æ—¶èŽ·å–å‚æ•°å¹¶åˆ·æ–°åˆ—è¡¨
    getPageParams();
src/pages/procurementManagement/paymentLedger/index.vue
@@ -1,5 +1,5 @@
<template>
  <view class="receipt-payment-ledger">
  <view class="sales-account">
    <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
    <PageHeader title="供应商往来" @back="goBack" />
    
@@ -7,11 +7,12 @@
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <input
          <up-input
            class="search-text"
            placeholder="请输入供应商名称"
            v-model="searchForm.searchText"
            @input="handleQuery"
            v-model="searchForm.supplierName"
            @change="handleQuery"
                        clearable
          />
        </view>
        <view class="search-button" @click="handleQuery">
@@ -81,7 +82,7 @@
const data = reactive({
  searchForm: {
    searchText: "",
    supplierName: "",
    invoiceDate: "",
  },
});
@@ -99,9 +100,12 @@
};
const getList = () => {
    showLoadingToast('加载中...')
    paymentLedgerList({ ...searchForm.value, ...page }).then((res) => {
    tableData.value = res.data.records;
    closeToast()
  }).catch(() => {
    closeToast()
    uni.showToast({
      title: '查询失败',
      icon: 'error'
@@ -113,12 +117,25 @@
  return parseFloat(value || 0).toFixed(2);
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
const rowClickMethod = (row) => {
  // ä½¿ç”¨ uni.setStorageSync å­˜å‚¨ä¾›åº”商信息
  uni.setStorageSync('supplierId', row.supplierId);
  // è·³è½¬åˆ°å›žæ¬¾è®°å½•明细页面
  uni.navigateTo({
    url: `/pages/procurementManagement/paymentLedger/detail?supplierId=${row.supplierId}`
    url: '/pages/procurementManagement/paymentLedger/detail'
  });
};
@@ -128,168 +145,11 @@
</script>
<style scoped lang="scss">
.u-divider {
  margin: 0 !important;
}
@import '@/styles/procurement-common.scss';
.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;
  color: #ff4757; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ #ee0a24 ä¸åŒ
  font-weight: 500;
}
.no-data {
  padding: 40px 0;
  text-align: center;
  color: #999;
}
</style>
src/pages/procurementManagement/procurementInvoiceLedger/index.vue
@@ -4,15 +4,15 @@
        <PageHeader title="来票台账" @back="goBack" />
        
        <!-- æœç´¢åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="供应商名称/采购合同号"
                        v-model="searchForm.searchText"
                        confirm-type="search"
                        @confirm="handleQuery"
                        placeholder="请输入供应商名称搜索"
                        v-model="searchForm.supplierName"
                        @change="handleQuery"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="handleQuery">
@@ -108,26 +108,26 @@
                        >
                            åˆ é™¤
                        </u-button>
                        <u-button
                            type="default"
                            size="small"
                            plain
                            class="action-btn"
                            v-if="item.invoiceFileName"
                            @click="openFileActions(item.commonFiles || [])"
                        >
                            æŸ¥çœ‹é™„ä»¶
                        </u-button>
                        <u-button
                            type="primary"
                            size="small"
                            class="action-btn"
                            v-else
                            :disabled="item.issUer !== userStore.nickName"
                            @click="openUpload(item)"
                        >
                            ä¸Šä¼ 
                        </u-button>
<!--                        <u-button-->
<!--                            type="default"-->
<!--                            size="small"-->
<!--                            plain-->
<!--                            class="action-btn"-->
<!--                            v-if="item.invoiceFileName"-->
<!--                            @click="openFileActions(item.commonFiles || [])"-->
<!--                        >-->
<!--                            æŸ¥çœ‹é™„ä»¶-->
<!--                        </u-button>-->
<!--                        <u-button-->
<!--                            type="primary"-->
<!--                            size="small"-->
<!--                            class="action-btn"-->
<!--                            v-else-->
<!--                            :disabled="item.issUer !== userStore.nickName"-->
<!--                            @click="openUpload(item)"-->
<!--                        >-->
<!--                            ä¸Šä¼ -->
<!--                        </u-button>-->
                    </view>
                </view>
            </view>
@@ -203,7 +203,7 @@
const total = ref(0)
const page = reactive({ current: -1, size: -1 })
const searchForm = reactive({
    searchText: '',
    supplierName: '',
})
const currentId = ref('')
@@ -413,230 +413,7 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
@import '@/styles/procurement-common.scss';
.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;
}
.popup-header {
    padding: 10px 16px;
    border-bottom: 1px solid #f5f5f5;
}
.popup-title {
    font-size: 16px;
    font-weight: 500;
    color: #333;
}
.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;
}
.filter-actions {
    display: flex;
    gap: 12px;
    padding: 12px 16px 16px;
    justify-content: center;
}
.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>
src/pages/procurementManagement/procurementLedger/index.vue
@@ -4,13 +4,15 @@
        <PageHeader title="采购台账" @back="goBack" />
        
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入采购合同号/客户名称"
                        v-model="searchKeyword"
                        placeholder="请输入采购合同号搜索"
                        v-model="purchaseContractNumber"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -92,7 +94,7 @@
const userStore = useUserStore()
// æœç´¢å…³é”®è¯
const searchKeyword = ref('');
const purchaseContractNumber = ref('');
// é‡‡è´­å°è´¦æ•°æ®
const ledgerList = ref([]);
@@ -103,15 +105,30 @@
};
// æŸ¥è¯¢åˆ—表
const getList = () => {
    showLoadingToast('加载中...')
    const page = {
        current: -1,
        size: -1
    }
    purchaseListPage({...page}).then((res) => {
    purchaseListPage({...page, purchaseContractNumber: purchaseContractNumber.value}).then((res) => {
        ledgerList.value = res.data.records;
        closeToast()
    }).catch(() => {
            // tableLoading.value = false;
        closeToast()
    });
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// å¤„理台账信息操作(查看/编辑/新增)
@@ -170,173 +187,7 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
@import '@/styles/procurement-common.scss';
.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-tag {
    background: #4caf50;
    border-radius: 4px;
    padding: 2px 4px;
}
.tag-text {
    font-size: 11px;
    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;
}
.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;
}
.fab-button {
    position: fixed;
    bottom: calc(30px + env(safe-area-inset-bottom));
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
    /* ç¡®ä¿æµ®åŠ¨æŒ‰é’®ä¸è¢«åº•éƒ¨å®‰å…¨åŒºåŸŸé®æŒ¡ */
}
// é‡‡è´­å°è´¦ç‰¹æœ‰æ ·å¼ï¼ˆå¦‚有需要可在此添加)
</style>
src/pages/procurementManagement/receiptPaymentHistory/index.vue
@@ -1,5 +1,5 @@
<template>
    <view class="receipt-payment-history">
    <view class="sales-account">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="付款流水" @back="goBack" />
        
@@ -7,11 +7,12 @@
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入供应商名称"
                        v-model="searchForm.searchText"
                        @input="getList"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="search-button" @click="getList">
@@ -126,13 +127,16 @@
// æŸ¥è¯¢åˆ—表
const getList = () => {
    showLoadingToast('加载中...')
    const params = {
        ...searchForm.value,
        ...page.value
    };
    paymentHistoryListPage(params).then((res) => {
        tableData.value = res.records;
        closeToast()
    }).catch(() => {
        closeToast()
        uni.showToast({
            title: '查询失败',
            icon: 'error'
@@ -155,6 +159,20 @@
const formatAmount = (amount) => {
    return amount ? parseFloat(amount).toFixed(2) : '0.00';
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// æ‰“开编辑表单
const openForm = (item) => {
    uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item))
@@ -167,218 +185,20 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
@import '@/styles/procurement-common.scss';
.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;
// ä»˜æ¬¾æµæ°´ç‰¹æœ‰æ ·å¼
.action-buttons {
    padding: 12px 0 0 0; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 0 0 16px 0 ä¸åŒ
}
.item-tag {
    border-radius: 4px;
    padding:  2px 8px;
}
.tag-electric {
    background: #4caf50;
}
.tag-acceptance {
    background: #ff9800;
}
.tag-unknown {
    background: #9e9e9e;
    padding: 2px 8px; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 2px 4px ä¸åŒ
}
.tag-text {
    font-size: 14px;
    font-size: 14px; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 11px ä¸åŒ
    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>
src/pages/sales/invoiceLedger/detail.vue
@@ -26,24 +26,24 @@
                </u-form-item>
            </u-cell-group>
            
            <u-cell-group title="附件材料(仅支持 pdf)">
                <u-upload
                    accept=".pdf"
                    multiple
                    :afterRead="afterReadUpload"
                    :beforeRead="beforeReadPdf"
                >
                    <u-button class="upload-btn" type="primary">
                        ä¸Šä¼ æ–‡ä»¶
                    </u-button>
                </u-upload>
                <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>
                        <u-button size="mini" type="error" plain @click="removeUploaded(idx)">移除</u-button>
                    </view>
                </view>
            </u-cell-group>
<!--            <u-cell-group title="附件材料(仅支持 pdf)">-->
<!--                <u-upload-->
<!--                    accept=".pdf"-->
<!--                    multiple-->
<!--                    :afterRead="afterReadUpload"-->
<!--                    :beforeRead="beforeReadPdf"-->
<!--                >-->
<!--                    <u-button class="upload-btn" type="primary">-->
<!--                        ä¸Šä¼ æ–‡ä»¶-->
<!--                    </u-button>-->
<!--                </u-upload>-->
<!--                <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>-->
<!--                        <u-button size="mini" type="error" plain @click="removeUploaded(idx)">移除</u-button>-->
<!--                    </view>-->
<!--                </view>-->
<!--            </u-cell-group>-->
            
            <!-- æäº¤æŒ‰é’® -->
            <view class="footer-btns">
src/pages/sales/invoiceLedger/index.vue
@@ -2,28 +2,28 @@
    <view class="sales-account">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="开票台账" @back="goBack" />
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸï¼ˆä¿æŒä¸Žé”€å”®å°è´¦é£Žæ ¼ä¸€è‡´ï¼‰ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="客户名称/销售合同号"
                        placeholder="请输入客户名称/合同号搜索"
                        v-model="searchForm.searchText"
                        confirm-type="search"
                        @confirm="handleQuery"
                        @change="handleQuery"
                        clearable
                    />
                </view>
<!--                <view class="filter-button" @click="showFilter = true">-->
<!--                    <up-icon name="list" size="24" color="#999"></up-icon>-->
<!--                </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="ledgerList.length > 0">
            <view v-for="(item, index) in ledgerList" :key="index">
@@ -103,25 +103,25 @@
                        >
                            åˆ é™¤
                        </up-button>
                        <up-button
                            size="small"
                            plain
                            class="action-btn"
                            v-if="item.invoiceFileName"
                            @click="openFileActions(item.commonFiles || [])"
                        >
                            æŸ¥çœ‹é™„ä»¶
                        </up-button>
                        <up-button
                            type="primary"
                            size="small"
                            class="action-btn"
                            v-else
                            :disabled="item.invoicePerson !== userStore.nickName"
                            @click="openUpload(item)"
                        >
                            ä¸Šä¼ 
                        </up-button>
<!--                        <up-button-->
<!--                            size="small"-->
<!--                            plain-->
<!--                            class="action-btn"-->
<!--                            v-if="item.invoiceFileName"-->
<!--                            @click="openFileActions(item.commonFiles || [])"-->
<!--                        >-->
<!--                            æŸ¥çœ‹é™„ä»¶-->
<!--                        </up-button>-->
<!--                        <up-button-->
<!--                            type="primary"-->
<!--                            size="small"-->
<!--                            class="action-btn"-->
<!--                            v-else-->
<!--                            :disabled="item.invoicePerson !== userStore.nickName"-->
<!--                            @click="openUpload(item)"-->
<!--                        >-->
<!--                            ä¸Šä¼ -->
<!--                        </up-button>-->
                    </view>
                </view>
            </view>
@@ -129,7 +129,7 @@
        <view v-else class="no-data">
            <text>暂无开票台账数据</text>
        </view>
        <!-- ç­›é€‰å¼¹çª— -->
        <up-popup v-model="showFilter" mode="bottom" round><up-transition>
            <view class="filter-popup">
@@ -158,7 +158,7 @@
                </view>
            </view>
        </up-transition></up-popup>
        <!-- æ—¥åŽ†ï¼šå¼€ç¥¨æ—¥æœŸèŒƒå›´ -->
        <up-popup v-model="showInvoiceRange" mode="bottom"><up-transition>
            <up-datetime-picker
@@ -169,7 +169,7 @@
                @cancel="showInvoiceRange = false"
            />
        </up-transition></up-popup>
        <!-- æ—¥æœŸï¼šå½•入日期 -->
        <up-popup v-model="showCreateDatePicker" mode="bottom"><up-transition>
            <up-datetime-picker
@@ -181,9 +181,9 @@
                @cancel="showCreateDatePicker = false"
            />
        </up-transition></up-popup>
        
        <!-- å•行上传弹窗(无表单) -->
        <up-popup v-model="showUpload" mode="bottom" round><up-transition>
            <view class="upload-container">
@@ -210,7 +210,7 @@
                </view>
            </view>
        </up-transition></up-popup>
        <!-- é™„件列表选择 -->
        <up-action-sheet v-model="showFileSheet" :actions="fileActions" cancel-text="取消" close-on-click-action @select="onSelectFile">
            <view class="up-action-sheet__cancel" @click="showFileSheet = false">
@@ -530,165 +530,15 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
@import '@/styles/sales-common.scss';
.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 {
@@ -743,6 +593,7 @@
    box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05);
    z-index: 1000;
}
.cancel-btn {
    font-weight: 400;
    font-size: 1rem;
@@ -752,6 +603,7 @@
    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;
src/pages/sales/invoicingRegistration/index.vue
@@ -4,13 +4,15 @@
        <PageHeader title="开票登记" @back="goBack" />
        
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入销售合同号/客户名称"
                        v-model="searchKeyword"
                        placeholder="请输入客户名称搜索"
                        v-model="customerName"
                        clearable
                        @change="getList"
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -67,21 +69,21 @@
                    <!-- æ“ä½œæŒ‰é’®åŒºåŸŸ -->
                    <view class="action-buttons">
                        <up-button
            type="primary"
            size="small"
            @click="handleAddInvoice(item)"
            class="action-btn"
            :disabled="item.noInvoiceAmountTotal == 0"
        >
            æ–°å¢žå¼€ç¥¨
        </up-button>
        <up-button
            size="small"
            @click="handleViewDetail(item)"
            class="action-btn"
        >
            æŸ¥çœ‹è¯¦æƒ…
        </up-button>
                            type="primary"
                            size="small"
                            @click="handleAddInvoice(item)"
                            class="action-btn"
                            :disabled="item.noInvoiceAmountTotal == 0"
                        >
                            æ–°å¢žå¼€ç¥¨
                        </up-button>
                        <up-button
                            size="small"
                            @click="handleViewDetail(item)"
                            class="action-btn"
                        >
                            æŸ¥çœ‹è¯¦æƒ…
                        </up-button>
                    </view>
                </view>
            </view>
@@ -100,7 +102,7 @@
const userStore = useUserStore()
// æœç´¢å…³é”®è¯
const searchKeyword = ref('');
const customerName = ref('');
// é”€å”®å°è´¦æ•°æ®
const ledgerList = ref([]);
@@ -112,16 +114,31 @@
};
// æŸ¥è¯¢åˆ—表
const getList = () => {
    showLoadingToast('加载中...')
    const page = {
        current: -1,
        size: -1
    }
    ledgerListPage({...page}).then((res) => {
    ledgerListPage({...page, customerName: customerName.value}).then((res) => {
        ledgerList.value = res.records;
        total.value = res.total;
        closeToast()
    }).catch(() => {
        // tableLoading.value = false;
        closeToast()
    });
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// å¤„理新增开票
@@ -169,35 +186,9 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
@import '@/styles/sales-common.scss';
.page-header {
    background: #ffffff;
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #f0f0f0;
    position: sticky;
    /* å…¼å®¹ iOS åˆ˜æµ·/灵动岛安全区 */
    padding-top: env(safe-area-inset-top);
    top: 0;
    z-index: 100;
}
.header-left {
    display: flex;
    align-items: center;
    gap: 8px;
}
// å¼€ç¥¨ç™»è®°ç‰¹æœ‰æ ·å¼
.nav-icon {
    width: 24px;
    height: 24px;
@@ -250,176 +241,12 @@
    border-radius: 2px;
}
.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-tag {
    background: #4caf50;
    border-radius: 4px;
    padding: 2px 4px;
}
.tag-text {
    font-size: 11px;
    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;
}
.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.redlight {
    color: red;
    font-weight: 500;
}
.action-buttons {
    display: flex;
    gap: 12px;
    padding: 0 0 16px 0;
    justify-content: space-between;
}
.action-btn {
    flex: 1;
}
.no-data {
    padding: 40px 0;
    text-align: center;
    color: #999;
}
.fab-button {
    position: fixed;
    bottom: 30px;
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
    bottom: 30px; // ä¸Žå…¶ä»–页面的 calc(30px + env(safe-area-inset-bottom)) ä¸åŒ
}
</style>
src/pages/sales/receiptPayment/index.vue
@@ -2,16 +2,17 @@
    <view class="sales-account">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="回款登记" @back="goBack" />
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="客户名称/合同号/项目名称"
                        v-model="searchForm.searchText"
                        confirm-type="search"
                        placeholder="请输入客户名称搜索"
                        v-model="searchForm.customerName"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -25,9 +26,9 @@
                <up-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">
@@ -95,7 +96,7 @@
                </view>
            </view>
        </view>
        <!-- æ— æ•°æ®æç¤º -->
        <view class="no-data" v-else>
            <text>暂无回款数据</text>
@@ -145,9 +146,8 @@
// æœç´¢è¡¨å•
const searchForm = ref({
    searchText: '',
    status: true,
    customerName: '',
    status: true,
    customerContractNo: '',
    projectName: ''
})
@@ -193,201 +193,12 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
@import '@/styles/sales-common.scss';
.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;
}
.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>
src/pages/sales/receiptPaymentHistory/index.vue
@@ -1,17 +1,18 @@
<template>
    <view class="receipt-payment-history">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="回款历史" @back="goBack" />
        <PageHeader title="回款流水" @back="goBack" />
        
        <!-- æœç´¢åŒºåŸŸ -->
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入客户名称/客户合同号"
                        placeholder="请输入客户名称搜索"
                        v-model="searchForm.searchText"
                        @input="getList"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="search-button" @click="getList">
@@ -134,18 +135,34 @@
// æŸ¥è¯¢åˆ—表
const getList = () => {
    showLoadingToast('加载中...')
    const params = {
        ...searchForm.value,
        ...page.value
    };
    receiptPaymentHistoryListPage(params).then((res) => {
        tableData.value = res.records;
        closeToast()
    }).catch(() => {
        closeToast()
        uni.showToast({
            title: '查询失败',
            icon: 'error'
        });
    });
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
// æ ¼å¼åŒ–回款方式
@@ -186,118 +203,21 @@
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
@import '@/styles/sales-common.scss';
// å›žæ¬¾æµæ°´ç‰¹æœ‰æ ·å¼
.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;
}
.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;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.item-id {
    font-size: 14px;
    color: #333;
    font-weight: 500;
    padding: 12px 0 0 0; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 0 0 16px 0 ä¸åŒ
}
.item-tag {
    border-radius: 4px;
    padding:  2px 8px;
    padding: 2px 8px; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 2px 4px ä¸åŒ
}
.tag-electric {
@@ -313,90 +233,8 @@
}
.tag-text {
    font-size: 14px;
    font-size: 14px; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ 11px ä¸åŒ
    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;
}
.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>
src/pages/sales/receiptPaymentLedger/detail.vue
@@ -89,17 +89,16 @@
// è¿”回上一页
const goBack = () => {
    uni.removeStorageSync('customerId')
    uni.navigateBack();
};
// èŽ·å–é¡µé¢å‚æ•°
const getPageParams = () => {
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const options = currentPage.options;
    if (options.customerId) {
        customerId.value = options.customerId;
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å–å®¢æˆ·ID
    const storedCustomerId = uni.getStorageSync('customerId');
    if (storedCustomerId) {
        customerId.value = storedCustomerId;
    }
};
@@ -113,6 +112,7 @@
        return;
    }
    
    showLoadingToast('加载中...')
    const param = {
        customerId: customerId.value,
        current: -1,
@@ -121,7 +121,9 @@
    
    customerInteractions(param).then((res) => {
        tableData.value = res.data;
        closeToast()
    }).catch(() => {
        closeToast()
        uni.showToast({
            title: '查询失败',
            icon: 'error'
@@ -134,6 +136,19 @@
    return amount ? parseFloat(amount).toFixed(2) : '0.00';
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
onShow(() => {
    // é¡µé¢æ˜¾ç¤ºæ—¶èŽ·å–å‚æ•°å¹¶åˆ·æ–°åˆ—è¡¨
    getPageParams();
src/pages/sales/receiptPaymentLedger/index.vue
@@ -1,67 +1,68 @@
<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">
    <view class="sales-account">
        <!-- ä½¿ç”¨é€šç”¨é¡µé¢å¤´éƒ¨ç»„ä»¶ -->
        <PageHeader title="客户往来" @back="goBack" />
        <!-- æœç´¢åŒºåŸŸ -->
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <up-input
                        class="search-text"
                        placeholder="请输入客户名称"
                        v-model="searchForm.customerName"
                        @change="handleQuery"
                        clearable
                    />
                </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.customerName }}</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.invoiceTotal) }}</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.unReceiptPaymentAmount) }}</text>
            </view>
          </view>
        </view>
      </view>
      <view v-else class="no-data">
        <text>暂无客户数据</text>
      </view>
    </view>
  </view>
                            </view>
                            <text class="customer-name">{{ item.customerName }}</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.invoiceTotal) }}</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.unReceiptPaymentAmount) }}</text>
                        </view>
                    </view>
                </view>
            </view>
            <view v-else class="no-data">
                <text>暂无客户数据</text>
            </view>
        </view>
    </view>
</template>
<script setup>
@@ -73,228 +74,87 @@
const tableData = ref([]);
const page = reactive({
  current: -1,
  size: -1,
    current: -1,
    size: -1,
});
const data = reactive({
  searchForm: {
    searchText: "",
    invoiceDate: "",
  },
    searchForm: {
        customerName: "",
        invoiceDate: "",
    },
});
const { searchForm } = toRefs(data);
// è¿”回上一页
const goBack = () => {
  uni.navigateBack();
    uni.navigateBack();
};
// æŸ¥è¯¢åˆ—表
const handleQuery = () => {
  getList();
    getList();
};
const getList = () => {
  invoiceLedgerSalesAccount({ ...searchForm.value, ...page }).then((res) => {
    tableData.value = res.data.records;
  }).catch(() => {
    uni.showToast({
      title: '查询失败',
      icon: 'error'
    });
  });
    showLoadingToast('加载中...')
    invoiceLedgerSalesAccount({ ...searchForm.value, ...page }).then((res) => {
        tableData.value = res.data.records;
        closeToast()
    }).catch(() => {
        closeToast()
        uni.showToast({
            title: '查询失败',
            icon: 'error'
        });
    });
};
const formattedNumber = (value) => {
  return parseFloat(value || 0).toFixed(2);
    return parseFloat(value || 0).toFixed(2);
};
// æ˜¾ç¤ºåŠ è½½æç¤º
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
// å…³é—­æç¤º
const closeToast = () => {
    uni.hideLoading();
};
const rowClickMethod = (row) => {
  // è·³è½¬åˆ°å›žæ¬¾è®°å½•明细页面
  uni.navigateTo({
    url: `/pages/sales/receiptPaymentLedger/detail?customerId=${row.id}`
  });
    // ä½¿ç”¨ uni.setStorageSync å­˜å‚¨å®¢æˆ·ä¿¡æ¯
    uni.setStorageSync('customerId', row.id);
    // è·³è½¬åˆ°å›žæ¬¾è®°å½•明细页面
    uni.navigateTo({
        url: '/pages/sales/receiptPaymentLedger/detail'
    });
};
onShow(() => {
  // é¡µé¢æ˜¾ç¤ºæ—¶åˆ·æ–°åˆ—表
  getList();
    // é¡µé¢æ˜¾ç¤ºæ—¶åˆ·æ–°åˆ—表
    getList();
});
onMounted(() => {
  getList();
    getList();
});
</script>
<style scoped lang="scss">
.u-divider {
  margin: 0 !important;
}
@import '@/styles/sales-common.scss';
.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;
    color: #ff4757; // ä¸Žå…¬å…±æ ·å¼ä¸­çš„ #ee0a24 ä¸åŒ
    font-weight: 500;
}
</style>
src/pages/sales/salesAccount/detail.vue
@@ -17,7 +17,7 @@
            >
                <up-input
                    v-model="form.salesman"
                    readonly=""
                    readonly
                    @click="showPicker = true"
                    placeholder="点击选择业务员"
                />
src/pages/sales/salesAccount/index.vue
@@ -4,13 +4,15 @@
        <PageHeader title="销售台账" @back="goBack" />
        
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                    <up-input
                        class="search-text"
                        placeholder="请输入销售合同号/客户名称"
                        v-model="searchKeyword"
                        placeholder="请输入销售合同号搜索"
                        v-model="salesContractNo"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
@@ -109,7 +111,7 @@
}
// æœç´¢å…³é”®è¯
const searchKeyword = ref('');
const salesContractNo = ref('');
// é”€å”®å°è´¦æ•°æ®
const ledgerList = ref([]);
@@ -126,7 +128,7 @@
        current: -1,
        size: -1
    }
    ledgerListPage({...page}).then((res) => {
    ledgerListPage({...page, salesContractNo: salesContractNo.value}).then((res) => {
        ledgerList.value = res.records;
        total.value = res.total;
        closeToast()
@@ -137,227 +139,59 @@
// å¤„理台账信息操作(查看/编辑/新增)
const handleInfo = (type, row) => {
  try {
    // è®¾ç½®æ“ä½œç±»åž‹
    uni.setStorageSync('operationType', type);
    // å¦‚果是查看或编辑操作
    if (type !== 'add') {
      // éªŒè¯è¡Œæ•°æ®æ˜¯å¦å­˜åœ¨
      if (!row) {
        uni.showToast({
          title: '数据不存在',
          icon: 'error'
        });
        return;
      }
      // æ£€æŸ¥æƒé™ï¼šåªæœ‰å½•入人才能编辑
      if (row.entryPerson != userStore.id) {
        // éžå½•入人跳转到只读详情页面
        uni.setStorageSync('editData', JSON.stringify(row));
        uni.navigateTo({
          url: '/pages/sales/salesAccount/view'
        });
        return;
      }
      // å½•入人编辑:存储数据并跳转到编辑页面
      uni.setStorageSync('editData', JSON.stringify(row));
      uni.navigateTo({
        url: '/pages/sales/salesAccount/detail'
      });
      return;
    }
    // æ–°å¢žæ“ä½œï¼šç›´æŽ¥è·³è½¬åˆ°ç¼–辑页面
    uni.navigateTo({
      url: '/pages/sales/salesAccount/detail'
    });
  } catch (error) {
    console.error('处理台账信息操作失败:', error);
    uni.showToast({
      title: '操作失败,请重试',
      icon: 'error'
    });
  }
    try {
        // è®¾ç½®æ“ä½œç±»åž‹
        uni.setStorageSync('operationType', type);
        // å¦‚果是查看或编辑操作
        if (type !== 'add') {
            // éªŒè¯è¡Œæ•°æ®æ˜¯å¦å­˜åœ¨
            if (!row) {
                uni.showToast({
                    title: '数据不存在',
                    icon: 'error'
                });
                return;
            }
            // æ£€æŸ¥æƒé™ï¼šåªæœ‰å½•入人才能编辑
            if (row.entryPerson != userStore.id) {
                // éžå½•入人跳转到只读详情页面
                uni.setStorageSync('editData', JSON.stringify(row));
                uni.navigateTo({
                    url: '/pages/sales/salesAccount/view'
                });
                return;
            }
            // å½•入人编辑:存储数据并跳转到编辑页面
            uni.setStorageSync('editData', JSON.stringify(row));
            uni.navigateTo({
                url: '/pages/sales/salesAccount/detail'
            });
            return;
        }
        // æ–°å¢žæ“ä½œï¼šç›´æŽ¥è·³è½¬åˆ°ç¼–辑页面
        uni.navigateTo({
            url: '/pages/sales/salesAccount/detail'
        });
    } catch (error) {
        console.error('处理台账信息操作失败:', error);
        uni.showToast({
            title: '操作失败,请重试',
            icon: 'error'
        });
    }
};
onShow(() => {
    // é¡µé¢æ˜¾ç¤ºæ—¶åˆ·æ–°åˆ—表
    getList();
    // é¡µé¢æ˜¾ç¤ºæ—¶åˆ·æ–°åˆ—表
    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-tag {
    background: #4caf50;
    border-radius: 4px;
    padding: 2px 4px;
}
.tag-text {
    font-size: 11px;
    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;
}
.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;
}
.fab-button {
    position: fixed;
    bottom: calc(30px + env(safe-area-inset-bottom));
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
    /* ç¡®ä¿æµ®åŠ¨æŒ‰é’®ä¸è¢«åº•éƒ¨å®‰å…¨åŒºåŸŸé®æŒ¡ */
}
@import '@/styles/sales-common.scss';
</style>
src/styles/procurement-common.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,420 @@
// é‡‡è´­ç®¡ç†æ¨¡å—公共样式
// ç”¨äºŽç»Ÿä¸€é‡‡è´­ç›¸å…³é¡µé¢çš„æ ·å¼é£Žæ ¼
// é¡µé¢å®¹å™¨æ ·å¼
.sales-account {
    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: 0 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.search-text {
    flex: 1;
    font-size: 14px;
    color: #333;
    background: transparent;
    border: none;
    outline: none;
    &::placeholder {
        color: #999;
    }
}
.filter-button,
.search-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,
.history-list,
.customer-list-container {
    padding: 20px;
}
.customer-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
// åˆ—表项样式
.ledger-item,
.history-item,
.customer-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;
    &:active {
        transform: scale(0.98);
        box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
    }
}
.customer-item {
    transition: all 0.3s ease;
    margin-bottom: 0;
}
// é¡¹ç›®å¤´éƒ¨æ ·å¼
.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;
}
// å›¾æ ‡æ ·å¼
.document-icon,
.customer-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
// æ–‡æœ¬æ ·å¼
.item-id,
.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-tag {
    border-radius: 4px;
    padding: 2px 4px;
    &.tag-electric {
        background: #4caf50;
    }
    &.tag-acceptance {
        background: #ff9800;
    }
    &.tag-unknown {
        background: #9e9e9e;
    }
}
.tag-text {
    font-size: 11px;
    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;
}
.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;
    &.highlight {
        color: #2979ff;
        font-weight: 500;
    }
    &.danger {
        color: #ee0a24;
        font-weight: 500;
    }
    &.redlight {
        color: red;
        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-buttons-top {
        padding: 12px 0 0 0;
    }
}
.action-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
// æµ®åŠ¨æŒ‰é’®æ ·å¼
.fab-button {
    position: fixed;
    bottom: calc(30px + env(safe-area-inset-bottom));
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
}
// æ— æ•°æ®æç¤ºæ ·å¼
.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;
    &.highlight {
        color: #2979ff;
        font-weight: 600;
    }
}
// å¼¹çª—样式
.filter-popup {
    padding: 12px 12px 20px;
}
.popup-header {
    padding: 10px 16px;
    border-bottom: 1px solid #f5f5f5;
}
.popup-title {
    font-size: 16px;
    font-weight: 500;
    color: #333;
}
.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;
}
.filter-actions {
    display: flex;
    gap: 12px;
    padding: 12px 16px 16px;
    justify-content: center;
}
.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;
}
// uView组件样式重置
.u-divider {
    margin: 0 !important;
}
src/styles/sales-common.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,337 @@
// é”€å”®æ¨¡å—公共样式
// ç”¨äºŽç»Ÿä¸€é”€å”®ç›¸å…³é¡µé¢çš„æ ·å¼é£Žæ ¼
// é¡µé¢å®¹å™¨æ ·å¼
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
.receipt-payment-ledger {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
// æœç´¢å’Œç­›é€‰åŒºåŸŸæ ·å¼
.search-filter-section,
.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: 0 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.search-text {
    flex: 1;
    font-size: 14px;
    color: #333;
    background: transparent;
    border: none;
    outline: none;
    &::placeholder {
        color: #999;
    }
}
.filter-button,
.search-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,
.history-list,
.customer-list-container {
    padding: 20px;
}
.customer-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
// åˆ—表项样式
.ledger-item,
.history-item,
.customer-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;
    &:active {
        transform: scale(0.98);
        box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
    }
}
.customer-item {
    transition: all 0.3s ease;
    margin-bottom: 0;
}
// é¡¹ç›®å¤´éƒ¨æ ·å¼
.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;
}
// å›¾æ ‡æ ·å¼
.document-icon,
.customer-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
// æ–‡æœ¬æ ·å¼
.item-id,
.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-tag {
    border-radius: 4px;
    padding: 2px 4px;
    &.tag-electric {
        background: #4caf50;
    }
    &.tag-acceptance {
        background: #ff9800;
    }
    &.tag-unknown {
        background: #9e9e9e;
    }
}
.tag-text {
    font-size: 11px;
    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;
}
.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;
    &.highlight {
        color: #2979ff;
        font-weight: 500;
    }
    &.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-buttons-top {
        padding: 12px 0 0 0;
    }
}
.action-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
// æµ®åŠ¨æŒ‰é’®æ ·å¼
.fab-button {
    position: fixed;
    bottom: calc(30px + env(safe-area-inset-bottom));
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
}
// æ— æ•°æ®æç¤ºæ ·å¼
.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;
    &.highlight {
        color: #2979ff;
        font-weight: 600;
    }
}
// uView组件样式重置
.u-divider {
    margin: 0 !important;
}