From ed89cf9724740addb7e12c53e81b770b0cf9881c Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Thu, 18 Jun 2026 21:27:52 +0800
Subject: [PATCH] 1

---
 src/crud/us-spots/us-pickAddr.js                        |   91 ++++++++
 src/crud/us-spots/pre-market-config.js                  |   53 ++++
 src/views/modules/us-spots/us-pre-market-config.vue     |  156 ++++++++++++++
 src/views/modules/us-spots/pre-market-add-or-update.vue |  231 +++++++++++++++++++++
 src/views/modules/shop/manual-profit-update.vue         |  118 ++++++++++
 5 files changed, 649 insertions(+), 0 deletions(-)

diff --git a/src/crud/us-spots/pre-market-config.js b/src/crud/us-spots/pre-market-config.js
new file mode 100644
index 0000000..a4c82f2
--- /dev/null
+++ b/src/crud/us-spots/pre-market-config.js
@@ -0,0 +1,53 @@
+export const tableOption = {
+  searchMenuSpan: 6,
+  columnBtn: false,
+  border: true,
+  selection: false,
+  index: false,
+  stripe: true,
+  menuAlign: 'center',
+  menuWidth: 200,
+  align: 'center',
+  refreshBtn: true,
+  searchSize: 'mini',
+  addBtn: false,
+  editBtn: false,
+  delBtn: false,
+  viewBtn: false,
+  menu: true,
+  emptyBtn: false,
+  column: [{
+    label: '股票代码',
+    prop: 'symbol',
+    search: true
+  }, {
+    label: '股票名称',
+    prop: 'symbolName'
+  }, {
+    label: '盘前开始(美东)',
+    prop: 'startTime'
+  }, {
+    label: '盘前结束(美东)',
+    prop: 'endTime'
+  }, {
+    label: '盘前价格',
+    prop: 'prePrice'
+  }, {
+    label: '启用状态',
+    prop: 'enabled',
+    type: 'select',
+    dicData: [{
+      label: '启用',
+      value: 1
+    }, {
+      label: '禁用',
+      value: 0
+    }]
+  }, {
+    label: '创建时间',
+    prop: 'createTime'
+  }, {
+    label: '更新时间',
+    prop: 'updateTime'
+  }]
+}
diff --git a/src/crud/us-spots/us-pickAddr.js b/src/crud/us-spots/us-pickAddr.js
new file mode 100644
index 0000000..e659346
--- /dev/null
+++ b/src/crud/us-spots/us-pickAddr.js
@@ -0,0 +1,91 @@
+/** 美股交割合约单 — 固定列配置(含场控) */
+export const tableOption = {
+  searchMenuSpan: 6,
+  columnBtn: false,
+  border: true,
+  selection: false,
+  index: false,
+  stripe: true,
+  menuAlign: 'center',
+  menuWidth: 200,
+  align: 'center',
+  refreshBtn: true,
+  searchSize: 'mini',
+  addBtn: false,
+  editBtn: false,
+  delBtn: false,
+  viewBtn: false,
+  menu: true,
+  emptyBtn: false,
+  column: [{
+    label: '订单号',
+    prop: 'orderNo',
+    hide: true,
+    search: true
+  }, {
+    label: '用户名',
+    prop: 'userName',
+    search: true
+  }, {
+    label: 'UID',
+    prop: 'userCode'
+  }, {
+    type: 'select',
+    label: '账户类型',
+    prop: 'roleName',
+    searchFilterable: true,
+    search: true,
+    searchValue: '',
+    filterable: true,
+    multiple: false,
+    dicData: [{
+      label: '所有账号',
+      value: ''
+    }, {
+      label: '正式账号',
+      value: 'MEMBER'
+    }, {
+      label: '演示账号',
+      value: 'GUEST'
+    }]
+  }, {
+    label: '品种',
+    prop: 'symbol',
+    search: true,
+    slot: true
+  }, {
+    label: '方向',
+    prop: 'direction',
+    type: 'select',
+    dicData: [{
+      label: '买涨',
+      value: 'buy'
+    }, {
+      label: '买跌',
+      value: 'sell'
+    }]
+  }, {
+    label: '金额',
+    prop: 'volume'
+  }, {
+    label: '盈亏',
+    prop: 'profit'
+  }, {
+    label: '场控',
+    prop: 'profitLosssStr'
+  }, {
+    label: '状态',
+    prop: 'state',
+    type: 'select',
+    dicData: [{
+      label: '已提交',
+      value: 'submitted'
+    }, {
+      label: '已撤销',
+      value: 'canceled'
+    }, {
+      label: '委托完成',
+      value: 'created'
+    }]
+  }]
+}
diff --git a/src/views/modules/shop/manual-profit-update.vue b/src/views/modules/shop/manual-profit-update.vue
new file mode 100644
index 0000000..fa85fec
--- /dev/null
+++ b/src/views/modules/shop/manual-profit-update.vue
@@ -0,0 +1,118 @@
+<template>
+  <el-dialog
+    title="订单场控"
+    :close-on-click-modal="false"
+    :visible.sync="visible"
+    append-to-body
+    width="480px"
+    @close="handClose"
+  >
+    <el-form
+      :model="dataForm"
+      :rules="dataRule"
+      ref="dataForm"
+      label-width="120px"
+      @keyup.enter.native="dataFormSubmit()"
+    >
+      <el-form-item label="订单号">
+        <el-input v-model="dataForm.orderNo" disabled></el-input>
+      </el-form-item>
+      <el-form-item label="场控方向" prop="profitLoss">
+        <el-radio-group v-model="dataForm.profitLoss">
+          <el-radio label="profit">盈利</el-radio>
+          <el-radio label="loss">亏损</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="visible = false">取消</el-button>
+      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { Debounce } from "@/utils/debounce";
+
+export default {
+  data() {
+    return {
+      visible: false,
+      dataForm: {
+        orderNo: "",
+        profitLoss: "profit",
+      },
+      dataRule: {
+        profitLoss: [
+          { required: true, message: "请选择场控方向", trigger: "change" },
+        ],
+      },
+    };
+  },
+  methods: {
+    init(row) {
+      this.visible = true;
+      this.dataForm.orderNo = row.orderNo;
+      let profitLoss = "profit";
+      if (row.profitLoss === "loss" || row.profitLoss === "profit") {
+        profitLoss = row.profitLoss;
+      } else if (row.profitLosssStr === "亏损") {
+        profitLoss = "loss";
+      } else if (row.profitLosssStr === "盈利") {
+        profitLoss = "profit";
+      }
+      this.dataForm.profitLoss = profitLoss;
+      this.$nextTick(() => {
+        if (this.$refs.dataForm) {
+          this.$refs.dataForm.clearValidate();
+        }
+      });
+    },
+    handClose() {
+      this.dataForm = {
+        orderNo: "",
+        profitLoss: "profit",
+      };
+      this.$nextTick(() => {
+        if (this.$refs.dataForm) {
+          this.$refs.dataForm.clearValidate();
+        }
+      });
+    },
+    dataFormSubmit: Debounce(function () {
+      this.$refs.dataForm.validate((valid) => {
+        if (!valid) {
+          return;
+        }
+        this.$http({
+          url: this.$http.adornUrl(
+            "/normal/adminFuturesOrderAction!/orderProfitLoss.action"
+          ),
+          method: "get",
+          params: this.$http.adornParams({
+            orderNo: this.dataForm.orderNo,
+            profitLoss: this.dataForm.profitLoss,
+          }),
+        }).then(({ data }) => {
+          if (data.code == 0) {
+            this.$message({
+              message: "操作成功",
+              type: "success",
+              duration: 1500,
+              onClose: () => {
+                this.visible = false;
+                this.$emit("refreshDataList");
+              },
+            });
+          } else {
+            this.$message({
+              message: data.msg,
+              type: "error",
+            });
+          }
+        });
+      });
+    }),
+  },
+};
+</script>
diff --git a/src/views/modules/us-spots/pre-market-add-or-update.vue b/src/views/modules/us-spots/pre-market-add-or-update.vue
new file mode 100644
index 0000000..f57335b
--- /dev/null
+++ b/src/views/modules/us-spots/pre-market-add-or-update.vue
@@ -0,0 +1,231 @@
+<template>
+  <el-dialog
+    :title="dataForm.uuid ? '编辑盘前配置' : '新增盘前配置'"
+    :close-on-click-modal="false"
+    :visible.sync="visible"
+    append-to-body
+    width="560px"
+    @close="handClose"
+  >
+    <el-form
+      :model="dataForm"
+      :rules="dataRule"
+      ref="dataForm"
+      label-width="130px"
+      @keyup.enter.native="dataFormSubmit()"
+    >
+      <el-form-item label="美股代码" prop="symbol">
+        <el-select
+          v-model="dataForm.symbol"
+          placeholder="请选择美股"
+          filterable
+          :disabled="!!dataForm.uuid"
+          class="full-width"
+        >
+          <el-option
+            v-for="item in symbolOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="盘前开始时间" prop="startTime">
+        <el-input
+          v-model="dataForm.startTime"
+          placeholder="美东时间 HH:mm,如 4:00"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="盘前结束时间" prop="endTime">
+        <el-input
+          v-model="dataForm.endTime"
+          placeholder="美东时间 HH:mm,如 9:30"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="盘前固定价格" prop="prePrice">
+        <el-input
+          v-model="dataForm.prePrice"
+          type="number"
+          placeholder="必须大于 0"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="启用" prop="enabled">
+        <el-switch
+          v-model="dataForm.enabled"
+          :active-value="1"
+          :inactive-value="0"
+        ></el-switch>
+      </el-form-item>
+      <div class="tip-text">盘前时段按美东时间 America/New_York 计算,支持跨午夜时段。</div>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="visible = false">取消</el-button>
+      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { Debounce } from "@/utils/debounce";
+
+export default {
+  data() {
+    return {
+      visible: false,
+      symbolOptions: [],
+      dataForm: {
+        uuid: "",
+        symbol: "",
+        startTime: "",
+        endTime: "",
+        prePrice: "",
+        enabled: 1,
+      },
+      dataRule: {
+        symbol: [{ required: true, message: "请选择美股", trigger: "change" }],
+        startTime: [
+          { required: true, message: "盘前开始时间不能为空", trigger: "blur" },
+        ],
+        endTime: [
+          { required: true, message: "盘前结束时间不能为空", trigger: "blur" },
+        ],
+        prePrice: [
+          { required: true, message: "盘前价格不能为空", trigger: "blur" },
+        ],
+      },
+    };
+  },
+  methods: {
+    init(uuid) {
+      this.visible = true;
+      this.loadSymbolOptions();
+      if (uuid) {
+        this.loadDetail(uuid);
+      } else {
+        this.dataForm = {
+          uuid: "",
+          symbol: "",
+          startTime: "",
+          endTime: "",
+          prePrice: "",
+          enabled: 1,
+        };
+      }
+      this.$nextTick(() => {
+        if (this.$refs.dataForm) {
+          this.$refs.dataForm.clearValidate();
+        }
+      });
+    },
+    loadSymbolOptions() {
+      this.$http({
+        url: this.$http.adornUrl("/normal/adminItemAction!/list"),
+        method: "get",
+        params: this.$http.adornParams({
+          type: "US-stocks",
+          current: 1,
+          size: 10000,
+        }),
+      }).then(({ data }) => {
+        if (data.code == 0 && data.data.records) {
+          this.symbolOptions = data.data.records.map((item) => ({
+            label: `${item.symbol} ${item.name || ""}`,
+            value: item.symbol,
+          }));
+        }
+      });
+    },
+    loadDetail(uuid) {
+      this.$http({
+        url: this.$http.adornUrl("/normal/adminItemPreMarketAction!/get.action"),
+        method: "get",
+        params: this.$http.adornParams({ uuid }),
+      }).then(({ data }) => {
+        if (data.code == 0 && data.data) {
+          this.dataForm = {
+            uuid: data.data.uuid,
+            symbol: data.data.symbol,
+            startTime: data.data.startTime,
+            endTime: data.data.endTime,
+            prePrice: data.data.prePrice,
+            enabled: data.data.enabled == null ? 1 : data.data.enabled,
+          };
+        } else {
+          this.$message({
+            message: data.msg || "加载失败",
+            type: "error",
+          });
+        }
+      });
+    },
+    handClose() {
+      this.dataForm = {
+        uuid: "",
+        symbol: "",
+        startTime: "",
+        endTime: "",
+        prePrice: "",
+        enabled: 1,
+      };
+      this.$nextTick(() => {
+        if (this.$refs.dataForm) {
+          this.$refs.dataForm.clearValidate();
+        }
+      });
+    },
+    dataFormSubmit: Debounce(function () {
+      this.$refs.dataForm.validate((valid) => {
+        if (!valid) {
+          return;
+        }
+        const payload = {
+          symbol: this.dataForm.symbol,
+          startTime: this.dataForm.startTime,
+          endTime: this.dataForm.endTime,
+          prePrice: Number(this.dataForm.prePrice),
+          enabled: this.dataForm.enabled,
+        };
+        if (this.dataForm.uuid) {
+          payload.uuid = this.dataForm.uuid;
+        }
+        this.$http({
+          url: this.$http.adornUrl(
+            "/normal/adminItemPreMarketAction!/save.action"
+          ),
+          method: "post",
+          data: this.$http.adornData(payload),
+        }).then(({ data }) => {
+          if (data.code == 0) {
+            this.$message({
+              message: "保存成功",
+              type: "success",
+              duration: 1500,
+              onClose: () => {
+                this.visible = false;
+                this.$emit("refreshDataList");
+              },
+            });
+          } else {
+            this.$message({
+              message: data.msg,
+              type: "error",
+            });
+          }
+        });
+      });
+    }),
+  },
+};
+</script>
+
+<style scoped>
+.full-width {
+  width: 100%;
+}
+.tip-text {
+  color: #909399;
+  font-size: 12px;
+  line-height: 1.6;
+  padding-left: 130px;
+}
+</style>
diff --git a/src/views/modules/us-spots/us-pre-market-config.vue b/src/views/modules/us-spots/us-pre-market-config.vue
new file mode 100644
index 0000000..62b276c
--- /dev/null
+++ b/src/views/modules/us-spots/us-pre-market-config.vue
@@ -0,0 +1,156 @@
+<template>
+  <div class="mod-us-pre-market-config">
+    <div class="toolbar">
+      <el-button
+        type="primary"
+        icon="el-icon-plus"
+        size="small"
+        @click.stop="addOrUpdateHandle()"
+      >新增</el-button>
+    </div>
+    <avue-crud
+      ref="crud"
+      :page.sync="page"
+      :data="dataList"
+      :option="tableOption"
+      @search-change="searchChange"
+      @selection-change="selectionChange"
+      @refresh-change="refreshChange"
+      @on-load="getDataList"
+    >
+      <template slot-scope="scope" slot="menu">
+        <el-button
+          type="primary"
+          icon="el-icon-edit"
+          size="small"
+          @click.stop="addOrUpdateHandle(scope.row.uuid)"
+        >编辑</el-button>
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="small"
+          @click.stop="deleteHandle(scope.row.uuid, scope.row.symbol)"
+        >删除</el-button>
+      </template>
+    </avue-crud>
+    <add-or-update
+      v-if="addOrUpdateVisible"
+      ref="addOrUpdate"
+      @refreshDataList="getDataList"
+    ></add-or-update>
+  </div>
+</template>
+
+<script>
+import { tableOption } from "@/crud/us-spots/pre-market-config";
+import AddOrUpdate from "./pre-market-add-or-update";
+
+export default {
+  data() {
+    return {
+      dataList: [],
+      dataListLoading: false,
+      dataListSelections: [],
+      addOrUpdateVisible: false,
+      tableOption: tableOption,
+      page: {
+        total: 0,
+        currentPage: 1,
+        pageSize: 10,
+      },
+      searchParams: {},
+    };
+  },
+  components: {
+    AddOrUpdate,
+  },
+  methods: {
+    getDataList(page, done) {
+      this.dataListLoading = true;
+      this.$http({
+        url: this.$http.adornUrl("/normal/adminItemPreMarketAction!/list.action"),
+        method: "get",
+        params: this.$http.adornParams(
+          Object.assign(
+            {
+              current: page == null ? this.page.currentPage : page.currentPage,
+              size: page == null ? this.page.pageSize : page.pageSize,
+            },
+            this.searchParams
+          )
+        ),
+      }).then(({ data }) => {
+        if (data.code == 0) {
+          this.dataList = data.data.records;
+          this.page.total = data.data.total;
+        } else {
+          this.$message({
+            message: data.msg,
+            type: "error",
+          });
+        }
+        this.dataListLoading = false;
+        if (done) {
+          done();
+        }
+      });
+    },
+    searchChange(params, done) {
+      this.page.currentPage = 1;
+      this.searchParams = params;
+      this.getDataList(this.page, done);
+    },
+    refreshChange(params, done) {
+      this.getDataList(this.page, params, done);
+    },
+    selectionChange(val) {
+      this.dataListSelections = val;
+    },
+    addOrUpdateHandle(uuid) {
+      this.addOrUpdateVisible = true;
+      this.$nextTick(() => {
+        this.$refs.addOrUpdate.init(uuid);
+      });
+    },
+    deleteHandle(uuid, symbol) {
+      this.$confirm(`确定删除 [${symbol}] 的盘前配置?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.$http({
+            url: this.$http.adornUrl(
+              "/normal/adminItemPreMarketAction!/delete.action"
+            ),
+            method: "delete",
+            params: this.$http.adornParams({ uuid }),
+          }).then(({ data }) => {
+            if (data.code == 0) {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+                duration: 1500,
+                onClose: () => {
+                  this.getDataList();
+                },
+              });
+            } else {
+              this.$message({
+                message: data.msg,
+                type: "error",
+              });
+            }
+          });
+        })
+        .catch(() => {});
+    },
+  },
+};
+</script>
+
+<style scoped>
+.toolbar {
+  margin-bottom: 12px;
+}
+</style>

--
Gitblit v1.9.3