hurx hace 2 meses
padre
commit
0034a72fd5

+ 8 - 0
src/api/customer/customerFile/customerContact/types.ts

@@ -41,8 +41,12 @@ export interface CustomerContactVO {
    */
   roleId: string | number;
 
+  roleName: string;
+
   deptId: string | number;
 
+  deptName: string;
+
   /**
    * 是否主联系人:0=是,1=否
    */
@@ -129,8 +133,12 @@ export interface CustomerContactForm extends BaseEntity {
    */
   roleId?: string | number;
 
+  roleName?: string;
+
   deptId?: string | number;
 
+  deptName?: string;
+
   email: string;
 
   /**

+ 14 - 0
src/api/order/orderMain/index.ts

@@ -76,6 +76,20 @@ export const delOrderMain = (id: string | number | Array<string | number>) => {
   });
 };
 
+/**
+ * 关闭订单
+ * @param id
+ */
+export const closeOrderMain = (id: string | number | Array<string | number>) => {
+  const ids = Array.isArray(id) ? id : [id];
+
+  return request({
+    url: '/order/orderMain/closeOrder',
+    method: 'post',
+    params: { ids }
+  });
+};
+
 /**
  * 查询数量
  * @param query

+ 12 - 0
src/api/order/orderProduct/types.ts

@@ -9,6 +9,12 @@ export interface OrderProductVO {
    */
   orderId: string | number;
 
+  originalItemId: string | number;
+
+  assignedChildOrderId: string | number;
+
+  assignmentStatus: string;
+
   /**
    * 订单编号
    */
@@ -164,6 +170,12 @@ export interface OrderProductForm extends BaseEntity {
    */
   orderId?: string | number;
 
+  originalItemId?: string | number;
+
+  assignedChildOrderId?: string | number;
+
+  assignmentStatus?: string;
+
   /**
    * 订单编号
    */

+ 95 - 21
src/api/product/base/types.ts

@@ -54,7 +54,12 @@ export interface BaseVO {
   isSelf: string;
 
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
   productReviewStatus: string;
 
@@ -89,7 +94,7 @@ export interface BaseVO {
   isNew: string;
 
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
   productStatus: string;
 
@@ -228,6 +233,11 @@ export interface BaseVO {
    */
   minOrderQuantity?: number;
 
+  /**
+   * 审核意见
+   */
+  reviewComments?: string;
+
   /**
    * 商品属性值(JSON字符串)
    */
@@ -283,27 +293,32 @@ export interface BaseForm extends BaseEntity {
   /**
    * 是否自营(1=是,0=否)
    */
-  isSelf?: string;
+  isSelf?: number;
 
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
-  productReviewStatus?: string;
+  productReviewStatus?: number;
 
   /**
    * 首页推荐:1=推荐,0=不推荐
    */
-  homeRecommended?: string;
+  homeRecommended?: number;
 
   /**
    * 分类推荐:1=推荐,0=不推荐
    */
-  categoryRecommendation?: string;
+  categoryRecommendation?: number;
 
   /**
    * 购物车推荐:1=推荐,0=不推荐
    */
-  cartRecommendation?: string;
+  cartRecommendation?: number;
 
   /**
    * 推荐产品顺序
@@ -313,15 +328,15 @@ export interface BaseForm extends BaseEntity {
   /**
    * 是否热门:1=是,0=否
    */
-  isPopular?: string;
+  isPopular?: number;
 
   /**
    * 是否新品:1=是,0=否
    */
-  isNew?: string;
+  isNew?: number;
 
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
   productStatus?: string;
 
@@ -549,9 +564,24 @@ export interface BaseForm extends BaseEntity {
    * 商品属性值(JSON字符串)
    */
   attributesList?: string;
+
+  /**
+   * 审核意见
+   */
+  reviewComments?: string;
+
+  /**
+   * 上下架审核意见
+   */
+  shelfComments?: string;
 }
 
 export interface BaseQuery extends PageQuery {
+  /**
+   * 搜索文本(商品名称/商品编号)
+   */
+  searchText?: string;
+
   /**
    * 产品编号
    */
@@ -567,6 +597,11 @@ export interface BaseQuery extends PageQuery {
    */
   brandId?: string | number;
 
+  /**
+   * 商品品牌名称
+   */
+  brandName?: string;
+
   /**
    * 顶级分类id
    */
@@ -595,27 +630,32 @@ export interface BaseQuery extends PageQuery {
   /**
    * 是否自营(1=是,0=否)
    */
-  isSelf?: string;
+  isSelf?: number;
 
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
-  productReviewStatus?: string;
+  productReviewStatus?: number;
 
   /**
    * 首页推荐:1=推荐,0=不推荐
    */
-  homeRecommended?: string;
+  homeRecommended?: number;
 
   /**
    * 分类推荐:1=推荐,0=不推荐
    */
-  categoryRecommendation?: string;
+  categoryRecommendation?: number;
 
   /**
    * 购物车推荐:1=推荐,0=不推荐
    */
-  cartRecommendation?: string;
+  cartRecommendation?: number;
 
   /**
    * 推荐产品顺序
@@ -625,17 +665,17 @@ export interface BaseQuery extends PageQuery {
   /**
    * 是否热门:1=是,0=否
    */
-  isPopular?: string;
+  isPopular?: number;
 
   /**
    * 是否新品:1=是,0=否
    */
-  isNew?: string;
+  isNew?: number;
 
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
-  productStatus?: string | number;
+  productStatus?: number;
 
   /**
    * 平台标识
@@ -672,3 +712,37 @@ export interface BaseQuery extends PageQuery {
    */
   params?: any;
 }
+/**
+ * 状态数量统计视图对象
+ */
+export class StatusCountVo {
+  /**
+   * 总数
+   */
+  total: number | null = null;
+
+  /**
+   * 上架数
+   */
+  onSale: number | null = null;
+
+  /**
+   * 下架数
+   */
+  offSale: number | null = null;
+
+  /**
+   * 待审核数量
+   */
+  waitAudit: number | null = null;
+
+  /**
+   * 通过数量
+   */
+  auditPass: number | null = null;
+
+  /**
+   * 驳回数量
+   */
+  auditReject: number | null = null;
+}

+ 59 - 3
src/components/Pagination/index.vue

@@ -1,6 +1,18 @@
 <template>
   <div :class="{ hidden: hidden }" class="pagination-container">
+    <!-- 游标分页模式 -->
+    <div v-if="cursorMode" class="cursor-pagination">
+      <el-button :disabled="currentPage === 1" @click="handlePrevPage"> 上一页 </el-button>
+      <span class="page-info">第 {{ currentPage }} 页</span>
+      <el-button :disabled="!hasMore" @click="handleNextPage"> 下一页 </el-button>
+      <el-select v-model="pageSize" @change="handleSizeChange" style="width: 100px" class="ml-2">
+        <el-option v-for="size in pageSizes" :key="size" :label="`${size}条/页`" :value="size" />
+      </el-select>
+    </div>
+
+    <!-- 传统分页模式 -->
     <el-pagination
+      v-else
       v-model:current-page="currentPage"
       v-model:page-size="pageSize"
       :background="background"
@@ -22,6 +34,7 @@ const props = defineProps({
   total: propTypes.number,
   page: propTypes.number.def(1),
   limit: propTypes.number.def(20),
+  way: propTypes.number.def(1),
   pageSizes: { type: Array<number>, default: () => [10, 20, 30, 50] },
   // 移动端页码按钮的数量端默认值5
   pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
@@ -29,10 +42,14 @@ const props = defineProps({
   background: propTypes.bool.def(true),
   autoScroll: propTypes.bool.def(true),
   hidden: propTypes.bool.def(false),
-  float: propTypes.string.def('right')
+  float: propTypes.string.def('right'),
+  // 游标分页模式
+  cursorMode: propTypes.bool.def(false),
+  // 是否还有更多数据(游标分页使用)
+  hasMore: propTypes.bool.def(true)
 });
 
-const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
+const emit = defineEmits(['update:page', 'update:limit', 'update:way', 'pagination']);
 const currentPage = computed({
   get() {
     return props.page;
@@ -50,7 +67,7 @@ const pageSize = computed({
   }
 });
 function handleSizeChange(val: number) {
-  if (currentPage.value * val > props.total) {
+  if (!props.cursorMode && currentPage.value * val > props.total) {
     currentPage.value = 1;
   }
   emit('pagination', { page: currentPage.value, limit: val });
@@ -64,6 +81,28 @@ function handleCurrentChange(val: number) {
     scrollTo(0, 800);
   }
 }
+// 游标分页:下一页
+function handleNextPage() {
+  if (props.hasMore) {
+    currentPage.value += 1;
+    emit('update:way', 1);
+    emit('pagination', { page: currentPage.value, limit: pageSize.value, way: 1 });
+    if (props.autoScroll) {
+      scrollTo(0, 800);
+    }
+  }
+}
+// 游标分页:上一页
+function handlePrevPage() {
+  if (currentPage.value > 1) {
+    currentPage.value -= 1;
+    emit('update:way', 0);
+    emit('pagination', { page: currentPage.value, limit: pageSize.value, way: 0 });
+    if (props.autoScroll) {
+      scrollTo(0, 800);
+    }
+  }
+}
 </script>
 
 <style lang="scss" scoped>
@@ -71,6 +110,23 @@ function handleCurrentChange(val: number) {
   .el-pagination {
     float: v-bind(float);
   }
+
+  .cursor-pagination {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 16px;
+    float: v-bind(float);
+
+    .page-info {
+      font-size: 14px;
+      color: #606266;
+    }
+
+    .ml-2 {
+      margin-left: 8px;
+    }
+  }
 }
 .pagination-container.hidden {
   display: none;

+ 27 - 10
src/views/bill/statementInvoice/addDrawer.vue

@@ -60,7 +60,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
           <el-table-column prop="orderAmount" label="金额" min-width="120" align="center" />
           <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
-          <el-table-column prop="signingDate" label="签收日期" min-width="120" align="center" />
           <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
           <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
         </el-table>
@@ -81,7 +80,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
           <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
           <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
-          <el-table-column prop="specifications" label="规格型号" min-width="120" align="center" />
           <el-table-column prop="unitName" label="单位" align="center" />
           <el-table-column prop="quantity" label="数量" align="center" />
           <el-table-column prop="unitPrice" label="单价" align="center">
@@ -137,7 +135,7 @@
               {{ Number(scope.row.invoiceAmount || 0).toFixed(2) }}
             </template>
           </el-table-column>
-
+          <el-table-column prop="remark" label="备注" align="center" />
           <el-table-column label="操作" width="150" align="center">
             <template #default="scope">
               <el-button link type="primary" size="small" @click="handleEditInvoice(scope.row, scope.$index)">编辑</el-button>
@@ -225,6 +223,7 @@ const fileSelectorVisible = ref(false);
 const addInvoiceDialogRef = ref<any>();
 const currentSelectedStatements = ref<StatementOrderVO[]>([]);
 const invoiceList = ref<any[]>([]); // 发票列表
+const editingInvoiceIndex = ref<number>(-1);
 
 /** 计算当前页的商品列表 */
 const pagedProductList = computed(() => {
@@ -290,6 +289,7 @@ const reset = () => {
   form.value = { ...initFormData };
   fileList.value = [];
   invoiceList.value = [];
+  editingInvoiceIndex.value = -1;
   productPage.pageNum = 1;
   productPage.pageSize = 10;
   productPage.total = 0;
@@ -468,21 +468,38 @@ const handleProductCurrentChange = (val: number) => {
 
 /** 新增发票 */
 const handleAddInvoice = () => {
-  addInvoiceDialogRef.value?.open();
+  editingInvoiceIndex.value = -1;
+  addInvoiceDialogRef.value?.open({
+    invoiceCompanyName: form.value.customerName
+  });
 };
 
 /** 发票添加成功 */
 const handleInvoiceAdded = (invoiceData: any) => {
-  // 将发票数据添加到发票列表
-  invoiceList.value.push({
-    ...invoiceData,
-    id: Date.now() // 临时ID
-  });
+  // 编辑:更新当前行;新增:追加
+  if (editingInvoiceIndex.value >= 0 && editingInvoiceIndex.value < invoiceList.value.length) {
+    const prev = invoiceList.value[editingInvoiceIndex.value] || {};
+    invoiceList.value.splice(editingInvoiceIndex.value, 1, {
+      ...prev,
+      ...invoiceData,
+      id: prev.id
+    });
+  } else {
+    invoiceList.value.push({
+      ...invoiceData,
+      id: invoiceData?.id ?? Date.now()
+    });
+  }
+  editingInvoiceIndex.value = -1;
 };
 
 /** 编辑发票 */
 const handleEditInvoice = (invoice: any, index: number) => {
-  addInvoiceDialogRef.value?.open(invoice);
+  editingInvoiceIndex.value = index;
+  addInvoiceDialogRef.value?.open({
+    ...invoice,
+    invoiceCompanyName: invoice?.invoiceCompanyName ?? invoice?.invoiceCompany ?? invoice?.companyName ?? invoice?.company ?? form.value.customerName
+  });
 };
 
 /** 删除发票 */

+ 9 - 0
src/views/bill/statementInvoice/addInvoiceDialog.vue

@@ -42,6 +42,13 @@
           </el-form-item>
         </el-col>
       </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" :min="2" placeholder="请填写备注" clearable />
+          </el-form-item>
+        </el-col>
+      </el-row>
 
       <el-row :gutter="20">
         <el-col :span="24">
@@ -96,6 +103,7 @@ interface InvoiceForm {
   invoiceCompanyName?: string;
   invoiceAmount?: number;
   invoiceDate?: string;
+  remark?: string;
   invoiceAttachment?: string;
 }
 
@@ -104,6 +112,7 @@ const initFormData: InvoiceForm = {
   invoiceCode: undefined,
   invoiceCompanyName: undefined,
   invoiceAmount: undefined,
+  remark: undefined,
   invoiceDate: undefined,
   invoiceAttachment: undefined
 };

+ 2 - 3
src/views/bill/statementInvoice/detailDrawer.vue

@@ -63,7 +63,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
           <el-table-column prop="orderAmount" label="金额" min-width="120" align="center" />
           <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
-          <el-table-column prop="signingDate" label="签收日期" min-width="120" align="center" />
           <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
           <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
         </el-table>
@@ -84,7 +83,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
           <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
           <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
-          <el-table-column prop="specifications" label="规格型号" min-width="120" align="center" />
           <el-table-column prop="unitName" label="单位" align="center" />
           <el-table-column prop="quantity" label="数量" align="center" />
           <el-table-column prop="unitPrice" label="单价" align="center">
@@ -136,9 +134,10 @@
               {{ Number(scope.row.invoiceAmount || 0).toFixed(2) }}
             </template>
           </el-table-column>
+          <el-table-column prop="remark" label="备注" align="center" />
           <el-table-column label="操作" width="160" align="center">
             <template #default="scope">
-              <el-button type="primary" link @click="handleDownloadFile(scope.row)">下载</el-button>
+              <el-button type="primary" link @click="handleDownloadFile(scope.row)">查看附件</el-button>
             </template>
           </el-table-column>
         </el-table>

+ 15 - 1
src/views/bill/statementInvoice/index.vue

@@ -279,8 +279,15 @@ const handleDetail = async (row?: StatementInvoiceVO) => {
 const handleSend = async (row?: StatementInvoiceVO) => {
   const _no = row?.statementInvoiceNo;
   const _ids = row?.id || ids.value;
+  const oldValue = row.invoiceStatus; // 保存旧值
   await proxy?.$modal.confirm('是否发送当前发票编号【' + _no + '】吗?').finally(() => (loading.value = false));
   //todo 发送
+  try {
+    await changeStatus(row.id, '1'); // 传新值 1 待开票
+  } catch (e) {
+    // 恢复旧值
+    row.invoiceStatus = oldValue;
+  }
   proxy?.$modal.msgSuccess('发送成功');
   await getList();
 };
@@ -288,9 +295,16 @@ const handleSend = async (row?: StatementInvoiceVO) => {
 /** 撤回按钮操作 */
 const handleWithdraw = async (row?: StatementInvoiceVO) => {
   const _no = row?.statementInvoiceNo;
-  const _ids = row?.id || ids.value;
+  const _ids = row?.id;
+  const oldValue = row.invoiceStatus; // 保存旧值
   await proxy?.$modal.confirm('是否撤回当前发票编号【' + _no + '】吗?').finally(() => (loading.value = false));
   //todo 撤回
+  try {
+    await changeStatus(_ids, '0'); // 传新值 0 待确认
+  } catch (e) {
+    // 恢复旧值
+    row.invoiceStatus = oldValue;
+  }
   proxy?.$modal.msgSuccess('撤回成功');
   await getList();
 };

+ 0 - 10
src/views/bill/statementInvoice/statementOrderDrawer.vue

@@ -17,11 +17,6 @@
             {{ Number(scope.row.statementAmount || 0).toFixed(2) }}
           </template>
         </el-table-column>
-        <el-table-column prop="type" label="订单类型" min-width="100" align="center">
-          <template #default="scope">
-            {{ scope.row.type === '1' ? '销售订单' : scope.row.type || '-' }}
-          </template>
-        </el-table-column>
         <el-table-column prop="orderNo" label="订单编号" min-width="140" align="center" />
         <el-table-column prop="amount" label="金额" min-width="100" align="center">
           <template #default="scope">
@@ -29,11 +24,6 @@
           </template>
         </el-table-column>
         <el-table-column prop="orderTime" label="下单日期" min-width="110" align="center" />
-        <el-table-column prop="signingDate" label="签收日期" min-width="110" align="center">
-          <template #default="scope">
-            {{ scope.row.signingDate || '-' }}
-          </template>
-        </el-table-column>
         <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
         <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
       </el-table>

+ 1 - 8
src/views/bill/statementOrder/addDrawer.vue

@@ -113,15 +113,9 @@
 
         <el-table :data="form.detailList" border style="width: 100%; margin-bottom: 20px">
           <el-table-column type="index" label="序号" width="60" align="center" />
-          <el-table-column prop="type" label="订单类型" min-width="100" align="center">
-            <template #default="scope">
-              <dict-tag :options="statement_order_type" :value="scope.row.type" />
-            </template>
-          </el-table-column>
           <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
           <el-table-column prop="amount" label="金额" min-width="120" align="center" />
           <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
-          <el-table-column prop="signingDate" label="签收日期" min-width="120" align="center" />
           <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
           <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
         </el-table>
@@ -146,7 +140,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
           <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
           <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
-          <el-table-column prop="specifications" label="规格型号" min-width="120" align="center" />
           <el-table-column prop="unitName" label="单位" width="80" align="center" />
           <el-table-column prop="quantity" label="数量" width="100" align="center" />
           <el-table-column prop="unitPrice" label="单价" width="100" align="center">
@@ -240,7 +233,7 @@ import FileSelector from '@/components/FileSelector/index.vue';
 import { any } from 'vue-types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { statement_status, statement_order_type, invoice_issuance_status, payment_status } = toRefs<any>(
+const { statement_status, invoice_issuance_status, payment_status } = toRefs<any>(
   proxy?.useDict('statement_status', 'statement_order_type', 'invoice_issuance_status', 'payment_status')
 );
 

+ 1 - 8
src/views/bill/statementOrder/detailDrawer.vue

@@ -93,15 +93,9 @@
 
         <el-table :data="form.detailList" border style="width: 100%; margin-bottom: 20px">
           <el-table-column type="index" label="序号" width="60" align="center" />
-          <el-table-column prop="type" label="订单类型" min-width="100" align="center">
-            <template #default="scope">
-              <dict-tag :options="statement_order_type" :value="scope.row.type" />
-            </template>
-          </el-table-column>
           <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
           <el-table-column prop="amount" label="金额" min-width="120" align="center" />
           <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
-          <el-table-column prop="signingDate" label="签收日期" min-width="120" align="center" />
           <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
           <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
         </el-table>
@@ -126,7 +120,6 @@
           <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
           <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
           <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
-          <el-table-column prop="specifications" label="规格型号" min-width="120" align="center" />
           <el-table-column prop="unitName" label="单位" width="80" align="center" />
           <el-table-column prop="quantity" label="数量" width="100" align="center" />
           <el-table-column prop="unitPrice" label="单价" width="100" align="center">
@@ -203,7 +196,7 @@ import { listOrderMain, getOrderMain } from '@/api/order/orderMain';
 import { OrderMainVO, OrderMainQuery, OrderMainForm } from '@/api/order/orderMain/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { statement_status, statement_order_type, invoice_issuance_status, payment_status } = toRefs<any>(
+const { statement_status, invoice_issuance_status, payment_status } = toRefs<any>(
   proxy?.useDict('statement_status', 'statement_order_type', 'invoice_issuance_status', 'payment_status')
 );
 

+ 16 - 2
src/views/bill/statementOrder/index.vue

@@ -256,9 +256,16 @@ const handleDetail = async (row?: StatementOrderVO) => {
 /** 发送按钮操作 */
 const handleSend = async (row?: StatementOrderVO) => {
   const _no = row?.statementOrderNo;
-  const _ids = row?.id || ids.value;
+  const _ids = row?.id;
+  const oldValue = row.statementStatus; // 保存旧值
   await proxy?.$modal.confirm('是否发送当前账单编号【' + _no + '】吗?').finally(() => (loading.value = false));
   //todo 发送
+  try {
+    await changeStatus(_ids, '1'); // 传新值 1 待确认
+  } catch (e) {
+    // 恢复旧值
+    row.statementStatus = oldValue;
+  }
   proxy?.$modal.msgSuccess('发送成功');
   await getList();
 };
@@ -266,9 +273,16 @@ const handleSend = async (row?: StatementOrderVO) => {
 /** 撤回按钮操作 */
 const handleWithdraw = async (row?: StatementOrderVO) => {
   const _no = row?.statementOrderNo;
-  const _ids = row?.id || ids.value;
+  const _ids = row?.id;
+  const oldValue = row.statementStatus; // 保存旧值
   await proxy?.$modal.confirm('是否撤回当前账单编号【' + _no + '】吗?').finally(() => (loading.value = false));
   //todo 撤回
+  try {
+    await changeStatus(_ids, '0'); // 传新值 0 待确认
+  } catch (e) {
+    // 恢复旧值
+    row.statementStatus = oldValue;
+  }
   proxy?.$modal.msgSuccess('撤回成功');
   await getList();
 };

+ 5 - 7
src/views/bill/statementOrder/orderMainDrawer.vue

@@ -4,17 +4,15 @@
     <div class="drawer-content">
       <el-table ref="tableRef" v-loading="loading" :data="orderList" border @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column prop="orderType" label="订单类型" min-width="120" />
-        <el-table-column prop="orderNo" label="订单编号" min-width="150" />
-        <el-table-column prop="totalAmount" label="金额" min-width="100" align="right">
+        <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
+        <el-table-column prop="totalAmount" label="金额" min-width="100" align="center">
           <template #default="scope">
             {{ scope.row.totalAmount ? Number(scope.row.totalAmount).toFixed(2) : '0.00' }}
           </template>
         </el-table-column>
-        <el-table-column prop="orderTime" label="下单日期" min-width="120" />
-        <el-table-column prop="signingDate" label="签收日期" min-width="120" />
-        <el-table-column prop="createName" label="下单人" min-width="100" />
-        <el-table-column prop="createDeptName" label="部门" min-width="150" />
+        <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
+        <el-table-column prop="createName" label="下单人" min-width="100" align="center" />
+        <el-table-column prop="createDeptName" label="部门" min-width="150" align="center" />
       </el-table>
 
       <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />

+ 15 - 3
src/views/customer/customerFile/customerInfo/components/addInvoiceDialog.vue

@@ -6,7 +6,7 @@
           <el-form-item label="纳税人识别号" prop="taxId">
             <el-input v-model="form.taxId" placeholder="">
               <template #append>
-                <el-button>还原</el-button>
+                <el-button @click="handleResetTaxId">还原</el-button>
               </template>
             </el-input>
           </el-form-item>
@@ -24,7 +24,7 @@
       <el-row :gutter="20">
         <el-col :span="24">
           <el-form-item label="开户行名称" prop="bankId">
-            <el-select v-model="form.bankId" placeholder="请选择" class="w-full" filterable>
+            <el-select v-model="form.bankId" placeholder="请选择" class="w-full" filterable @change="handleBankChange">
               <el-option v-for="bank in bankList" :key="bank.id" :label="`${bank.bnId} , ${bank.bnName}`" :value="bank.id" />
             </el-select>
           </el-form-item>
@@ -124,7 +124,19 @@ const rules = {
   bankCode: [{ required: true, message: '请输入开户行行号', trigger: 'blur' }],
   bankName: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
   bankAccount: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
-  phone: [{ required: true, message: '请输入电话', trigger: 'blur' }]
+  phone: [
+    { required: true, message: '请输入电话', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/ as RegExp, message: '请输入正确的手机号格式', trigger: 'blur' }
+  ]
+};
+
+const handleBankChange = (bankId: string | number) => {
+  const bank = bankList.value.find((b) => b.id === bankId);
+  form.bankName = bank?.bnName || '';
+};
+
+const handleResetTaxId = () => {
+  form.taxId = undefined;
 };
 
 // 监听编辑数据

+ 47 - 6
src/views/customer/customerFile/customerInfo/overview/contactInfo.vue

@@ -24,7 +24,7 @@
         </el-table-column>
         <el-table-column label="手机号" align="center" prop="phone" />
         <el-table-column label="自定义登录名" align="center" prop="customLoginName" />
-        <el-table-column label="部门" align="center" prop="" />
+        <el-table-column label="部门" align="center" prop="deptName" />
         <el-table-column label="采购角色" align="center" prop="roleName" />
         <el-table-column label="状态" align="center" prop="status">
           <template #default="scope">
@@ -79,11 +79,12 @@
               <el-tree-select
                 v-model="form.deptId"
                 :data="customerDeptList"
-                :props="{ value: 'id', label: 'deptName', children: 'children' }"
-                value-key="id"
+                :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
+                value-key="deptId"
                 placeholder="请选择"
                 check-strictly
                 :render-after-expand="false"
+                @change="handleDeptChange"
                 filterable
                 style="width: 100%"
               />
@@ -98,7 +99,9 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="采购角色" prop="roleId">
-              <el-input v-model="form.roleId" placeholder="请输入采购角色" />
+              <el-select v-model="form.roleId" placeholder="请选择采购角色" clearable filterable style="width: 100%" @change="handleRoleChange">
+                <el-option v-for="role in roleOptions" :key="role.roleId" :label="role.roleName" :value="role.roleId" />
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -124,7 +127,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="详细地址" prop="codeArr">
-              <el-cascader v-model="codeArr" :options="regionData" placeholder="请选择" @change="handleChange" style="width: 100%"></el-cascader>
+              <el-cascader v-model="codeArr" :options="regionOptions" placeholder="请选择" @change="handleChange" style="width: 100%"></el-cascader>
             </el-form-item>
             <el-form-item prop="addressDetail">
               <el-input v-model="form.addressDetail" type="textarea" :rows="3" placeholder="请输入详细地址" style="width: 100%" />
@@ -153,12 +156,16 @@ import {
 import { CustomerContactVO, CustomerContactQuery, CustomerContactForm } from '@/api/customer/customerFile/customerContact/types';
 import { listCustomerDept, getCustomerDept } from '@/api/customer/customerFile/customerDept';
 import { CustomerDeptVO, CustomerDeptQuery } from '@/api/customer/customerFile/customerDept/types';
+import { listRole } from '@/api/system/role';
+import type { RoleVO } from '@/api/system/role/types';
 import { regionData } from 'element-china-area-data';
 // 接收父组件传递的props
 const props = defineProps<{
   customerId?: string;
   customerNo?: string;
 }>();
+
+const regionOptions = regionData as any;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_platform_yes_no, sys_user_sex, sys_normal_disable } = toRefs<any>(
   proxy?.useDict('sys_platform_yes_no', 'sys_user_sex', 'sys_normal_disable')
@@ -182,6 +189,8 @@ const dialog = reactive<DialogOption>({
   title: ''
 });
 
+const roleOptions = ref<RoleVO[]>([]);
+
 const initFormData: CustomerContactForm = {
   id: undefined,
   customerId: undefined,
@@ -228,7 +237,10 @@ const data = reactive<PageData<CustomerContactForm, CustomerContactQuery>>({
   },
   rules: {
     contactName: [{ required: true, message: '联系人姓名不能为空', trigger: 'blur' }],
-    phone: [{ required: true, message: '手机号码不能为空', trigger: 'blur' }]
+    phone: [
+      { required: true, message: '手机号码不能为空', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/ as RegExp, message: '请输入正确的手机号格式', trigger: 'blur' }
+    ]
   }
 });
 
@@ -247,6 +259,34 @@ const getList = async () => {
   loading.value = false;
 };
 
+/** 加载角色列表 */
+const loadRoleOptions = async () => {
+  try {
+    const res: any = await listRole({
+      pageNum: 1,
+      pageSize: 9999,
+      roleName: '',
+      roleKey: '',
+      status: ''
+    } as any);
+
+    roleOptions.value = res?.rows || res?.data?.rows || res?.data || [];
+  } catch (error) {
+    console.error('加载角色列表失败:', error);
+    roleOptions.value = [];
+  }
+};
+
+const handleDeptChange = (deptId: string | number) => {
+  const dept = customerDeptList.value.find((d) => d.deptId === deptId);
+  form.value.deptName = dept?.deptName;
+};
+
+const handleRoleChange = (roleId: string | number) => {
+  const role = roleOptions.value.find((r) => r.roleId === roleId);
+  form.value.roleName = role?.roleName;
+};
+
 /** 加载客户部门列表 */
 const loadCustomerDeptList = async () => {
   if (!props.customerId) return;
@@ -399,6 +439,7 @@ onMounted(() => {
   if (props.customerId) {
     queryParams.value.customerId = props.customerId;
   }
+  loadRoleOptions();
   getList();
 });
 

+ 22 - 5
src/views/order/orderDeliver/index.vue

@@ -46,13 +46,13 @@
         <el-row :gutter="10" class="mb8">
           <el-col :span="19"> 发货单信息列表 </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain>关闭订单</el-button>
+            <el-button type="primary" @click="handleCloseOrder()" :disabled="!ids.length" plain>关闭订单</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain>删除订单</el-button>
+            <el-button type="primary" @click="handleDelete()" :disabled="!ids.length" plain>删除订单</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain>导出订单</el-button>
+            <el-button type="primary" :disabled="!ids.length" plain>导出订单</el-button>
           </el-col>
         </el-row>
       </template>
@@ -92,7 +92,15 @@
 </template>
 
 <script setup name="OrderMain" lang="ts">
-import { listOrderMain, getOrderMain, delOrderMain, addOrderMain, updateOrderMain, queryOrderStatusStats } from '@/api/order/orderMain';
+import {
+  listOrderMain,
+  getOrderMain,
+  delOrderMain,
+  addOrderMain,
+  updateOrderMain,
+  queryOrderStatusStats,
+  closeOrderMain
+} from '@/api/order/orderMain';
 import { OrderMainVO, OrderMainQuery, OrderMainForm } from '@/api/order/orderMain/types';
 import DeliverDialog from '../saleOrder/deliverDialog.vue';
 
@@ -210,7 +218,7 @@ const data = reactive<PageData<OrderMainForm, OrderMainQuery>>({
     paymentStatus: undefined,
     orderSource: undefined,
     orderStatus: undefined,
-    orderStatuses: '2,3',
+    orderStatuses: '2,3,4',
     orderTime: undefined,
     confirmTime: undefined,
     shippingTime: undefined,
@@ -254,6 +262,15 @@ const queryOrderStatusStatsMethod = async () => {
   orderStatusStats.value = res as any;
 };
 
+/** 关闭订单操作 */
+const handleCloseOrder = async (row?: OrderMainVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认关闭订单主信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await closeOrderMain(_ids);
+  proxy?.$modal.msgSuccess('关闭成功');
+  await getList();
+};
+
 /** 取消按钮 */
 const cancel = () => {
   reset();

+ 114 - 18
src/views/order/orderMain/components/chooseProduct.vue

@@ -78,14 +78,14 @@
     </el-table>
 
     <!-- 分页 -->
-    <el-pagination
-      v-model:current-page="queryParams.pageNum"
-      v-model:page-size="queryParams.pageSize"
-      :page-sizes="[10, 20, 30, 50]"
+    <pagination
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      v-model:way="queryParams.way"
+      :cursor-mode="true"
+      :has-more="hasMore"
       :total="total"
-      layout="prev, next"
-      @current-change="handleCurrentChange"
-      class="mt-4"
+      @pagination="getList"
     />
   </el-dialog>
 </template>
@@ -115,15 +115,34 @@ const brandOptions = ref<BrandVO[]>([]);
 const categoryList = ref<categoryTreeVO[]>([]);
 const total = ref(0);
 
-const queryParams = ref<BaseQuery>({
+const queryParams = ref<any>({
   pageNum: 1,
   pageSize: 10,
   productNo: undefined,
   itemName: undefined,
+  brandName: undefined,
   brandId: undefined,
-  topCategoryId: undefined
+  productTag: undefined,
+  purchaseNature: undefined,
+  supplierType: undefined,
+  supplierNature: undefined,
+  projectOrg: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  productStatus: undefined,
+  lastSeenId: undefined,
+  firstSeenId: undefined,
+  way: undefined,
+  params: {}
 });
 
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
 // 对话框状态变化
 const handleDialogChange = (val: boolean) => {
   emit('update:modelValue', val);
@@ -139,27 +158,99 @@ const formatTaxRate = (taxRate: number | string | undefined): string => {
 
 // 对话框打开时触发
 const handleOpen = () => {
+  // 重置查询参数到第一页
+  queryParams.value.pageNum = 1;
+  queryParams.value.lastSeenId = undefined;
+  queryParams.value.firstSeenId = undefined;
+  queryParams.value.way = undefined;
+  pageHistory.value = [];
   loadProductList();
 };
 
 // 对话框关闭时触发
 const handleClose = () => {
-  // 可以在这里重置数据
+  // 重置查询参数
+  queryParams.value.pageNum = 1;
+  queryParams.value.productNo = undefined;
+  queryParams.value.itemName = undefined;
+  queryParams.value.brandId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  queryParams.value.productStatus = undefined;
+  productList.value = [];
+  pageHistory.value = [];
 };
 
-// 加载商品列表
-const loadProductList = async () => {
-  if (loading.value) return;
+// // 加载商品列表
+// const loadProductList = async () => {
+//   if (loading.value) return;
 
+//   loading.value = true;
+//   try {
+//     const res = await listBase(queryParams.value);
+//     productList.value = res.rows || [];
+//     total.value = res.total || 0;
+//   } catch (error) {
+//     console.error('加载商品列表失败:', error);
+//     productList.value = [];
+//     total.value = 0;
+//   } finally {
+//     loading.value = false;
+//   }
+// };
+
+/** 查询产品基础信息列表 */
+const loadProductList = async () => {
   loading.value = true;
   try {
-    const res = await listBase(queryParams.value);
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
     productList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = productList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (productList.value.length > 0) {
+      const firstItem = productList.value[0];
+      const lastItem = productList.value[productList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
     total.value = res.total || 0;
   } catch (error) {
-    console.error('加载商品列表失败:', error);
-    productList.value = [];
-    total.value = 0;
+    console.error('获取列表失败:', error);
   } finally {
     loading.value = false;
   }
@@ -211,9 +302,14 @@ const handleAddProduct = (product: BaseVO) => {
   emit('update:modelValue', false);
 };
 
+// 分页查询
+const getList = () => {
+  loadProductList();
+};
+
 // 初始化
 onMounted(() => {
-  // loadBrandList(); // 暂时注释掉
+  // loadBrandList();
   loadCategoryTree();
 });
 </script>

+ 13 - 3
src/views/order/saleOrder/index.vue

@@ -42,13 +42,13 @@
         <el-row :gutter="10" class="mb8">
           <el-col :span="15"> 销售订单信息列表 </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain>关闭订单</el-button>
+            <el-button type="primary" @click="handleCloseOrder()" :disabled="!ids.length" plain>关闭订单</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" @click="handleDelete()" plain>删除订单</el-button>
+            <el-button type="primary" @click="handleDelete()" :disabled="!ids.length" plain>删除订单</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain>导出订单</el-button>
+            <el-button type="primary" :disabled="!ids.length" plain>导出订单</el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
@@ -160,6 +160,7 @@ import {
   delOrderMain,
   addOrderMain,
   updateOrderMain,
+  closeOrderMain,
   queryOrderStatusStats,
   changeStatus,
   changeCheckStatus
@@ -555,6 +556,15 @@ const handleDelete = async (row?: OrderMainVO) => {
   await getList();
 };
 
+/** 关闭订单操作 */
+const handleCloseOrder = async (row?: OrderMainVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认关闭订单主信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await closeOrderMain(_ids);
+  proxy?.$modal.msgSuccess('关闭成功');
+  await getList();
+};
+
 /** 导出按钮操作 */
 const handleExport = () => {
   proxy?.download(