From 54d8eb1bd2ae36b8ed5589bf5730284f11434625 Mon Sep 17 00:00:00 2001
From: xhc <15171145581@163.com>
Date: Fri, 6 Jun 2025 17:50:10 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=8A=E4=BC=A0=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E6=B0=B4=E5=8D=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.vue | 36 +-
src/api/api.js | 7 +-
src/components/da-dropdown/changelog.md | 164 ++++
.../da-dropdown/components/cell.vue | 172 ++++
.../da-dropdown/components/daterange.vue | 209 ++++
.../da-dropdown/components/filter.vue | 220 +++++
.../components/part-dropdown-footer.vue | 75 ++
.../da-dropdown/components/picker.vue | 220 +++++
src/components/da-dropdown/index.vue | 898 ++++++++++++++++++
src/components/da-dropdown/readme.md | 443 +++++++++
src/components/da-dropdown/typing.ts | 151 +++
src/components/da-dropdown/utils.ts | 207 ++++
src/components/hpy-watermark.vue | 344 +++++++
src/components/image-watermark-picker.vue | 275 ++++++
src/components/waterMarker.vue | 147 +++
src/package.json | 20 +
src/pages/feedback/feedback.vue | 2 +-
src/pages/index/index.vue | 115 ++-
src/pages/knowledgeBase/knowledgeBase.vue | 104 +-
src/pages/message/message.vue | 49 +-
src/pages/my/my.vue | 8 +-
src/pages/points/points.vue | 220 ++++-
src/pages/startInspection/startInspection.vue | 6 +-
src/uni_modules/hpy-watermark/changelog.md | 5 +
.../hpy-watermark/hpy-watermark.vue | 198 ++++
src/uni_modules/hpy-watermark/package.json | 83 ++
src/uni_modules/hpy-watermark/readme.md | 201 ++++
27 files changed, 4474 insertions(+), 105 deletions(-)
create mode 100644 src/components/da-dropdown/changelog.md
create mode 100644 src/components/da-dropdown/components/cell.vue
create mode 100644 src/components/da-dropdown/components/daterange.vue
create mode 100644 src/components/da-dropdown/components/filter.vue
create mode 100644 src/components/da-dropdown/components/part-dropdown-footer.vue
create mode 100644 src/components/da-dropdown/components/picker.vue
create mode 100644 src/components/da-dropdown/index.vue
create mode 100644 src/components/da-dropdown/readme.md
create mode 100644 src/components/da-dropdown/typing.ts
create mode 100644 src/components/da-dropdown/utils.ts
create mode 100644 src/components/hpy-watermark.vue
create mode 100644 src/components/image-watermark-picker.vue
create mode 100644 src/components/waterMarker.vue
create mode 100644 src/package.json
create mode 100644 src/uni_modules/hpy-watermark/changelog.md
create mode 100644 src/uni_modules/hpy-watermark/components/hpy-watermark/hpy-watermark.vue
create mode 100644 src/uni_modules/hpy-watermark/package.json
create mode 100644 src/uni_modules/hpy-watermark/readme.md
diff --git a/src/App.vue b/src/App.vue
index de2b297..b8b914e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -2,7 +2,7 @@
* @Author: XHC
* @Date: 2025-05-19 10:21:48
* @LastEditors: XHC
- * @LastEditTime: 2025-05-30 10:44:11
+ * @LastEditTime: 2025-06-06 17:37:54
* @Description:
-->
+
+
diff --git a/src/components/da-dropdown/components/daterange.vue b/src/components/da-dropdown/components/daterange.vue
new file mode 100644
index 0000000..57c7415
--- /dev/null
+++ b/src/components/da-dropdown/components/daterange.vue
@@ -0,0 +1,209 @@
+
+
+
+
+
+ {{ daterange.start || '请选择日期' }}
+
+
+ 至
+
+
+ {{ daterange.end || '请选择日期' }}
+
+
+
+
+
+
+ {{ tag.label }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/da-dropdown/components/filter.vue b/src/components/da-dropdown/components/filter.vue
new file mode 100644
index 0000000..4a39be3
--- /dev/null
+++ b/src/components/da-dropdown/components/filter.vue
@@ -0,0 +1,220 @@
+
+
+
+ {{ item.title }}
+
+
+
+
+ {{ opt.label }}
+
+
+
+
+
+ {{ opt.label }}
+
+
+
+
+ handleSliderChange(e, item, index)" />
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/da-dropdown/components/part-dropdown-footer.vue b/src/components/da-dropdown/components/part-dropdown-footer.vue
new file mode 100644
index 0000000..efd18c3
--- /dev/null
+++ b/src/components/da-dropdown/components/part-dropdown-footer.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
diff --git a/src/components/da-dropdown/components/picker.vue b/src/components/da-dropdown/components/picker.vue
new file mode 100644
index 0000000..23e1966
--- /dev/null
+++ b/src/components/da-dropdown/components/picker.vue
@@ -0,0 +1,220 @@
+
+
+
+
+
+ {{ vr.label }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/da-dropdown/index.vue b/src/components/da-dropdown/index.vue
new file mode 100644
index 0000000..aebaba8
--- /dev/null
+++ b/src/components/da-dropdown/index.vue
@@ -0,0 +1,898 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/da-dropdown/readme.md b/src/components/da-dropdown/readme.md
new file mode 100644
index 0000000..9384942
--- /dev/null
+++ b/src/components/da-dropdown/readme.md
@@ -0,0 +1,443 @@
+# da-dropdown
+
+一个基于 Vue3 的头部导航栏下拉弹窗组件,多平台兼容。
+
+组件一直在更新,遇到问题可在下方讨论。
+
+`同时更新 Vue2 版本,在此查看 ===>` **[Vue2 版](https://ext.dcloud.net.cn/plugin?id=13062)**
+
+### 关于使用
+
+可在右侧的`使用 HBuilderX 导入插件`或`下载示例项目ZIP`,示例项目已添加多个示例,方便快速上手。
+
+可通过下方的示例及文档说明,进一步了解使用组件相关细节参数。
+
+插件地址:https://ext.dcloud.net.cn/plugin?id=11840
+
+### 功能一览
+
+1. 下拉列表(单选)
+2. 点击常亮
+3. 点击排序
+4. 下拉筛选(单选按钮、多选按钮、滑动选择器)
+5. 级联筛选(单选)
+6. 日期筛选(日期快选、日期区间选择)
+7. 顶部搜索
+8. 自定插槽
+
+### 组件示例
+
+```jsx
+
+
+
+ 自定义插槽内容
+
+
+
+```
+
+```js
+import { defineComponent, ref } from 'vue'
+
+import DaDropdown from '@/components/da-dropdown/index.vue'
+
+export default defineComponent({
+ components: { DaDropdown },
+ setup() {
+ const dropdownMenuList = ref([
+ // 演示数据请看下方各模块说明或下载示例项目查看
+ // ...
+ ])
+ function handleConfirm(v) {
+ console.log('handleConfirm ==>', v)
+ }
+ function handleClose(v) {
+ console.log('handleClose ==>', v)
+ }
+ function handleOpen(v) {
+ console.log('handleOpen ==>', v)
+ }
+ return {
+ dropdownMenuList,
+ handleConfirm,
+ handleClose,
+ handleOpen,
+ }
+ },
+})
+```
+
+### 组件参数
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :------------------- | :-------- | :-------- | :--- | :--------------------------------- |
+| v-model:dropdownMenu | `Array` | `[]` | 是 | 导航菜单数据 |
+| themeColor | `String` | `#007aff` | 否 | 主题颜色 |
+| textColor | `String` | `#333333` | 否 | 导航文字颜色 |
+| bgColor | `String` | `#ffffff` | 否 | 背景颜色,当固定在顶部时,此为必填 |
+| fixedTop | `Boolean` | `false` | 否 | 是否固定在顶部 |
+| fixedTopValue | `Number` | `0` | 否 | 固定在头部时的位置,单位 px |
+| duration | `Number` | `300` | 否 | 弹窗动画的过渡时间 |
+
+> 温馨提示:如果页面定义了 "navigationStyle": "custom" ,因此固定头部时需要额外获取状态栏高度,以免被异形屏头部覆盖,此时的 fixedTopValue 的作用就出来了,通过 fixedTopValue 自定义加减固定头部所处的位置。
+
+
+### 组件事件
+
+| 事件名称 | 回调参数 | 说明 |
+| :------- | :------------------------- | :----------------------------------------------------------------- |
+| open | `(index) => void` | 打开弹窗时回调 |
+| close | `(index,menuList) => void` | 关闭弹窗时回调 |
+| confirm | `(value,data) => void` | 确定选择内容时回调,返回选择的数据,格式`{'菜单项prop值': '内容'}` |
+
+
+### 组件方法
+
+| 事件名称 | 回调参数 | 说明 |
+| :---------------- | :------------------------- | :-------------------------------------- |
+| openMenuItemPopup | `(index) => void` | 打开指定位置的菜单项弹窗 |
+| closeMenuPopup | `() => void` | 关闭菜单项弹窗 |
+| getMenuValue | `() => object` | 获取菜单存在的值 |
+| updateMenu | `(prop,value,key) => void` | 更新菜单项内容【参考示例7】 |
+| setMenuLoading | `(prop,state) => void` | 操作指定菜单项为加载中状态【参考示例7】 |
+| getMenuIndex | `(prop) => number` | 获取菜单项所在索引位置 |
+| getMenuList | `() => array` | 获取当前菜单列表数据【参考示例6】 |
+
+
+### 组件菜单项
+
+#### dropdownMenu 基础参数
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---------- | :--------- | :----- | :--- | :--------------------------------------------------------------- |
+| title | `String` | - | 是 | 菜单名称 |
+| prop | `String` | - | 是 | 菜单 prop 值,**菜单项的 prop 是唯一的** |
+| type | `String` | - | 是 | 菜单类型,参考下方类型说明 |
+| syncDataFn | `Function` | - | 否 | 异步函数返回子项数据,优先级大于 options |
+| syncDataKey | `String` | - | 否 | 异步数据不是根数据时需要。支持嵌套,如:`data.list`【参考示例7】 |
+
+除上方基础参数以外,不同的菜单项(type)会有额外的配置参数
+
+**type 说明**
+**cell** 下拉列表
+**click** 点击
+**sort** 排序
+**filter** 复杂筛选
+**picker** 级联
+**daterange** 日期范围
+**search** 搜索框(菜单项 type 唯一)
+**slot** 弹窗插槽
+
+#### 菜单项 - 下拉列表(cell)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :------- | :----------------- | :----------------------------------------------------- | :--- | :----------------------------------------- |
+| value | `Number`\|`String` | - | 否 | 默认值,和`options`的 value 必须保持同类型 |
+| showAll | `Boolean` | `false` | 否 | 是否显示 “不限” 项 |
+| showIcon | `Boolean` | `false` | 否 | 是否在选中时显示勾选图标 |
+| field | `Object` | `{ label: 'label', value: 'value', suffix: 'suffix' }` | 否 | 列表子项数据对应内容字段 |
+| options | `Array` | `[]` | 否 | 下拉列表子项数据 |
+
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '下拉',
+ type: 'cell',
+ prop: 'god1',
+ showAll: true,
+ showIcon: true,
+ // value: '2', // 默认内容2
+ options: [
+ { label: '下拉列表项1', value: '1', suffix: '副标题' },
+ { label: '下拉列表项2', value: '2' },
+ { label: '下拉列表项3', value: '3' },
+ ],
+ },
+]
+```
+
+#### 菜单项 - 高亮(click)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---- | :-------- | :----- | :--- | :-------------------------------- |
+| value | `Boolean` | - | 否 | 默认值,true 选中、false 取消选中 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '点击',
+ type: 'click',
+ prop: 'god2',
+ // value: true, // 默认选中
+ },
+]
+```
+
+#### 菜单项 - 排序(sort)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---- | :------------ | :----- | :--- | :-------------------------- |
+| value | `asc`\|`desc` | - | 否 | 默认值,asc 升序、desc 倒序 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '排序',
+ type: 'sort',
+ prop: 'god3',
+ // value: 'asc', // 默认升序
+ },
+]
+```
+
+#### 菜单项 - 筛选(filter)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :------ | :------- | :----- | :--- | :------------------------------------------- |
+| value | `Object` | - | 否 | 默认值,格式`{ prop1: '值1', prop2: '值2' }` |
+| options | `Array` | `[]` | 否 | 筛选子项数据,**说明见下** |
+
+##### filter -> options 参数说明
+
+| 属性 | 类型 | 必填 | 说明 |
+| :------------- | :---------------------------- | :--- | :-------------------------------------------------------------------------------------------- |
+| title | `String` | 是 | 筛选项的子项标题 |
+| type | `radio`\|`checkbox`\|`slider` | 是 | 筛选项的子项类型,可选 radio 单选按钮、checkbox 多选按钮、slider 滑动选择器 |
+| prop | `String` | 是 | 筛选项的子项 prop,**注意保持子项 prop 唯一** |
+| componentProps | `Object` | 否 | 筛选项的对应的组件配置,[slider 组件配置](https://uniapp.dcloud.net.cn/component/slider.html) |
+| options | `Array` | 否 | 筛选子项的类型对应的数据 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '筛选',
+ type: 'filter',
+ prop: 'god4',
+ // 默认选中单选2、多选2、3、滑动30
+ // value: { ft1: '2', ft2: ['2', '3'], ft3: 30 },
+ options: [
+ {
+ title: '单选',
+ type: 'radio',
+ prop: 'ft1',
+ options: [
+ { label: '单选1', value: '1' },
+ { label: '单选2', value: '2' }
+ ],
+ },
+ {
+ title: '多选',
+ type: 'checkbox',
+ prop: 'ft2',
+ options: [
+ { label: '多选1', value: '1' },
+ { label: '多选2', value: '2' }
+ ],
+ },
+ {
+ title: '滑块',
+ type: 'slider',
+ prop: 'ft3',
+ componentProps: {
+ min: 0,
+ max: 100,
+ step: 1,
+ showValue: true,
+ },
+ },
+ ],
+ },
+]
+```
+
+#### 菜单项 - 级联(picker)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---------- | :--------- | :--------------------------------------------------------- | :--- | :--------------------------------------------------------------- |
+| value | `Array` | - | 否 | 默认值,格式`['一级value', '二级value']` |
+| showAll | `Boolean` | `false` | 否 | 是否显示 “不限” 项 |
+| showIcon | `Boolean` | `false` | 否 | 是否在选中末级时显示勾选图标 |
+| field | `Object` | `{ label: 'label', value: 'value', children: 'children' }` | 否 | 级联子项数据对应内容字段 |
+| options | `Array` | `[]` | 否 | 级联子项数据 |
+| syncDataFn | `Function` | - | 否 | 异步函数返回级联子项数据,优先级大于 options |
+| syncDataKey | `String` | - | 否 | 异步数据不是根数据时需要。支持嵌套,如:`data.list`【参考示例7】 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '级联选择',
+ type: 'picker',
+ prop: 'god5',
+ showAll: true,
+ showIcon: true,
+ // showAll 为true时相当于在options第一的位置插入“不限”项
+ // { label: '不限', value: '-9999' },
+ field: {
+ label: 'label',
+ value: 'value',
+ children: 'children',
+ },
+ // value: ['2', '22'], // 默认选中 级联X22
+ options: [
+ {
+ label: '级联X1',
+ value: '1',
+ children: [
+ { label: '级联X11', value: '11' },
+ { label: '级联X12', value: '12' },
+ ],
+ },
+ {
+ label: '级联X2',
+ value: '2',
+ children: [
+ { label: '级联X21', value: '21' },
+ { label: '级联X22', value: '22' },
+ ],
+ },
+ ],
+ },
+]
+```
+
+#### 菜单项 - 日期(daterange)
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :-------- | :-------- | :----- | :--- | :--------------------------------------------------- |
+| value | `Object` | - | 否 | 默认值,格式`{ start: '开始日期', end: '结束日期' }` |
+| showQuick | `Boolean` | `true` | 否 | 是否显示日期快选 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '日期范围',
+ type: 'daterange',
+ prop: 'god6',
+ // 默认选中 2022-01-01到2022-02-01
+ // value: { start: '2022-01-01', end: '2022-02-01' },
+ },
+]
+```
+
+#### 菜单项 - 顶部搜索框(search)
+
+
+当存在此类型时,头部将会展示搜索框,**注意:此类型唯一**
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---- | :------- | :----- | :--- | :----- |
+| value | `String` | - | 否 | 默认值 |
+
+```js
+// 简单示例
+const dropdownMenuList = [
+ {
+ title: '搜索',
+ type: 'search',
+ prop: 'god0',
+ },
+]
+```
+
+#### 菜单项 - 拓展插槽(slot1、slot2、slot3、slot4、slot5)
+
+拓展插槽有 5 个,足以应付业务需求了,类型名称为`slot1`、`slot2`、`slot3`、`slot4`、`slot5`,这是固定的类型值
+
+| 属性 | 类型 | 默认值 | 必填 | 说明 |
+| :---- | :------- | :----- | :--- | :----- |
+| value | `String` | - | 否 | 默认值 |
+
+```jsx
+// 简单示例
+
+
+
+ 自定义插槽2内容 {{item.value}} {{index}}
+
+
+ 自定义插槽2内容 {{item.value}} {{index}}
+
+
+ 自定义插槽3内容 {{item.value}} {{index}}
+
+
+ 自定义插槽4内容 {{item.value}} {{index}}
+
+
+ 自定义插槽5内容 {{item.value}} {{index}}
+
+
+
+```
+
+```js
+const dropdownMenuList = [
+ {
+ title: '插槽1',
+ type: 'slot1',
+ prop: 'god1',
+ },
+ {
+ title: '插槽2',
+ type: 'slot2',
+ prop: 'god2',
+ },
+ {
+ title: '插槽3',
+ type: 'slot3',
+ prop: 'god3',
+ },
+ {
+ title: '插槽4',
+ type: 'slot4',
+ prop: 'god4',
+ },
+ {
+ title: '插槽5',
+ type: 'slot5',
+ prop: 'god5',
+ },
+]
+```
+
+### 组件版本
+
+v2.2.2
+
+### 差异化
+
+已通过测试
+
+> - H5 页面
+> - 微信小程序
+> - 支付宝、钉钉小程序
+> - 字节跳动、抖音、今日头条小程序
+> - 百度小程序
+> - 飞书小程序
+> - QQ 小程序
+> - 京东小程序
+
+未测试
+
+> - 快手小程序由于非企业用户暂无演示
+> - 快应用、360 小程序因 Vue3 支持的原因暂无演示
+
+### 开发组
+
+[@CRLANG](https://crlang.com)
diff --git a/src/components/da-dropdown/typing.ts b/src/components/da-dropdown/typing.ts
new file mode 100644
index 0000000..4bf6d6c
--- /dev/null
+++ b/src/components/da-dropdown/typing.ts
@@ -0,0 +1,151 @@
+/**
+ * 菜单项-下拉配置
+ */
+export interface DaCellOption {
+ /**
+ * 是否显示“不限”选项
+ */
+ showAll?: boolean
+ /**
+ * 是否显示勾选图标
+ */
+ showIcon?: boolean
+}
+/**
+ * 菜单项-点击配置
+ */
+export interface DaClickOption {}
+/**
+ * 菜单项-排序配置
+ */
+export interface DaSortOption {}
+/**
+ * 菜单项-筛选配置
+ */
+export interface DaFilterOption {}
+/**
+ * 菜单项-级联配置
+ */
+export interface DaPickerOption {
+ /**
+ * 是否显示“不限”选项
+ */
+ showAll?: boolean
+ /**
+ * 是否显示勾选图标
+ */
+ showIcon?: boolean
+ field?: {
+ label: string
+ value: string
+ children: string
+ }
+}
+/**
+ * 菜单项-日期范围配置
+ */
+export interface DaDaterangeOption {
+ value?: {
+ start: string
+ end: string
+ }
+}
+/**
+ * 下拉列表-项内容
+ */
+export interface DaCellItemOption extends DaDropdownMenuListOption {
+ /**
+ * 右侧子标题
+ */
+ suffix?: string
+}
+/**
+ * 筛选-项内容
+ */
+export interface DaFilterItemOption {
+ /**
+ * 筛选标题
+ */
+ title: string
+ /**
+ * 筛选类型,可选 radio 单选按钮、checkbox 多选按钮、slider 滑动选择器
+ */
+ type: 'radio' | 'checkbox' | 'slider'
+ /**
+ * 筛选项prop
+ */
+ prop: string
+ /**
+ * 已选内容
+ */
+ value?: string | number | string[] | number[]
+ /**
+ * 筛选项-slider子项组件prop,具体参考 https://uniapp.dcloud.net.cn/component/slider.html
+ */
+ componentProp?: object
+ /**
+ * 筛选项-子项
+ */
+ options?: DaDropdownMenuListOption[]
+}
+
+/**
+ * 级联-项内容
+ */
+export interface DaPickerItem extends DaDropdownMenuListOption {
+ isActived: boolean
+ /**
+ * 子项
+ */
+ children?: DaPickerItem[]
+}
+
+/**
+ * 菜单列表选择项
+ */
+export interface DaDropdownMenuListOption {
+ /**
+ * 选择项标题
+ */
+ label: string
+ /**
+ * 选择项内容
+ */
+ value: string
+}
+
+/**
+ * 菜单项
+ */
+export interface DaDropdownMenuListItem extends DaCellOption, DaClickOption, DaSortOption, DaFilterOption, DaPickerOption {
+ /**
+ * 菜单标题
+ */
+ title: string
+ /**
+ * 菜单类型
+ * 可选:cell 下拉选择、click 点击、sort 排序、filter 复杂筛选、picker 级联、daterange 日期范围
+ */
+ type: 'cell' |'click' | 'sort' | 'filter' | 'picker'| 'daterange'
+ /**
+ * 菜单项prop
+ */
+ prop: string
+ /**
+ * 菜单值
+ */
+ value?: string
+ /**
+ * 菜单选项函数,优先级大于 options
+ */
+ syncDataFn?: Function
+ /**
+ * 菜单选项
+ */
+ options?: DaDropdownMenuListOption[] | DaFilterItemOption[]
+}
+
+/**
+ * 菜单列表
+ */
+export type DaDropdownMenuList = DaDropdownMenuListItem[]
diff --git a/src/components/da-dropdown/utils.ts b/src/components/da-dropdown/utils.ts
new file mode 100644
index 0000000..9207fda
--- /dev/null
+++ b/src/components/da-dropdown/utils.ts
@@ -0,0 +1,207 @@
+/**
+ * 深拷贝内容
+ * @param originData 拷贝对象
+ * @author crlang(https://crlang.com)
+ */
+export function deepClone(originData) {
+ const type = Object.prototype.toString.call(originData)
+ let data
+ if (type === '[object Array]') {
+ data = []
+ for (let i = 0; i < originData.length; i++) {
+ data.push(deepClone(originData[i]))
+ }
+ } else if (type === '[object Object]') {
+ data = {}
+ for (const prop in originData) {
+ // eslint-disable-next-line no-prototype-builtins
+ if (originData.hasOwnProperty(prop)) { // 非继承属性
+ data[prop] = deepClone(originData[prop])
+ }
+ }
+ } else {
+ data = originData
+ }
+ return data
+}
+
+export function getValueByKey(object, path, defaultVal = undefined) {
+ console.log('object, path', object, path)
+ // 先将path处理成统一格式
+ let newPath = []
+ if (Array.isArray(path)) {
+ newPath = path
+ } else {
+ // 先将字符串中的'['、']'去除替换为'.',split分割成数组形式
+ newPath = path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
+ }
+
+ // 递归处理,返回最后结果
+ return newPath.reduce((o, k) => {
+ console.log(o, k) // 此处o初始值为下边传入的 object,后续值为每次取的内部值
+ return (o || {})[k]
+ }, object) || defaultVal
+}
+
+/**
+ * 处理部分初始数据
+ * @param data
+ */
+export function checkDataField(options, fields) {
+ if (!fields || !options || options.length === 0) {
+ return options
+ }
+
+ for (let i = 0; i < options.length; i++) {
+ const k = options[i]
+ k.label = k[fields.label || 'label'] || null
+ k.value = k[fields.value || 'value'] || null
+ k.suffix = k[fields.suffix || 'suffix'] || null
+ k.children = k[fields.children || 'children'] || null
+ if (k.children?.length) {
+ k.options = checkDataField(k.options)
+ }
+ }
+ return options
+}
+
+/**
+ * 格式化数值-个位数补零
+ * @param n 数值
+ * @author crlang(https://crlang.com)
+ */
+export function formatNumber(n) {
+ let s = parseInt(n)
+ if (isNaN(s)) {
+ s = '0'
+ } else {
+ s = s.toString()
+ }
+ return s[1] ? s : `0${s}`
+}
+
+/**
+ * 格式化时间
+ * @param date 时间对象
+ * @param format 格式
+ * @author crlang(https://crlang.com)
+ */
+export function formatTime(date, format) {
+ const daDate = new Date(date.toString().length < 11 ? date * 1000 : date)
+ const fromatsRule = ['y', 'm', 'd', 'h', 'i', 's']
+ let tmp = []
+ const year = daDate.getFullYear()
+ const month = daDate.getMonth() + 1
+ const day = daDate.getDate()
+ const hour = daDate.getHours()
+ const minute = daDate.getMinutes()
+ const second = daDate.getSeconds()
+
+ if (format) {
+ tmp.push(year, month, day, hour, minute, second)
+ tmp = tmp.map(formatNumber)
+ for (let i = 0; i < tmp.length; i++) {
+ format = format.toLowerCase().replace(fromatsRule[i], tmp[i])
+ }
+ return format
+ }
+
+ return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
+}
+
+/**
+ * 获取某个时间范围
+ *
+ * @param v -1、-7、-14、-30、-60
+ * @returns object {start: y-m-d,end: y-m-d}
+ * @author crlang(https://crlang.com)
+ */
+export function getRangeDate(v) {
+ const now = new Date()
+ const nowTime = now.getTime()
+ const oneDay = 24 * 60 * 60 * 1000
+ const dateRange = { start: '', end: '' }
+ const nowWeekDay = now.getDay() // 今天本周的第几天
+ const nowDay = now.getDate() // 当前日
+ const nowMonth = now.getMonth() // 当前月
+ const nowYear = now.getFullYear() // 当前年
+
+ /**
+ * 获得某个月的天数
+ * @param month 当前月份
+ */
+ const getMonthDays = function(month) {
+ const monthStartDate = new Date(nowYear, month, 1)
+ const monthEndDate = new Date(nowYear, month + 1, 1)
+ const days = (monthEndDate - monthStartDate) / oneDay
+ return days
+ }
+
+ // 昨日
+ if (v === '-1') {
+ dateRange.start = formatTime(new Date(nowTime - oneDay), 'y-m-d')
+ dateRange.end = dateRange.start
+ // 本周
+ } else if (v === '-7') {
+ const weekStart = new Date(nowYear, nowMonth, nowDay - nowWeekDay + 1)
+ const weekEnd = new Date(nowTime + oneDay) // 今日
+ dateRange.start = formatTime(weekStart, 'y-m-d')
+ dateRange.end = formatTime(weekEnd, 'y-m-d')
+ // 上周
+ } else if (v === '-14') {
+ const weekStart = new Date(nowYear, nowMonth, nowDay - nowWeekDay - 6)
+ const weekEnd = new Date(nowYear, nowMonth, nowDay - nowWeekDay)
+ dateRange.start = formatTime(weekStart, 'y-m-d')
+ dateRange.end = formatTime(weekEnd, 'y-m-d')
+ // 本月
+ } else if (v === '-30') {
+ const monthStart = new Date(nowYear, nowMonth, 1)
+ const monthEnd = new Date(nowTime + oneDay)
+ dateRange.start = formatTime(monthStart, 'y-m-d')
+ dateRange.end = formatTime(monthEnd, 'y-m-d')
+ // 上月
+ } else if (v === '-60') {
+ const lastMonthDate = new Date() // 上月日期
+ lastMonthDate.setDate(1)
+ lastMonthDate.setMonth(lastMonthDate.getMonth() - 1)
+ const lastMonth = lastMonthDate.getMonth()
+ const lastMonthStart = new Date(nowMonth === 0 ? nowYear - 1 : nowYear, lastMonth, 1)
+ const lastMonthEnd = new Date(nowMonth === 0 ? nowYear - 1 : nowYear, lastMonth, getMonthDays(lastMonth))
+ dateRange.start = formatTime(lastMonthStart, 'y-m-d')
+ dateRange.end = formatTime(lastMonthEnd, 'y-m-d')
+ } else {
+ // 传入 v 为整数是即为近 xx 天
+ if (v > 0) {
+ dateRange.start = formatTime(new Date(nowTime - oneDay * parseInt(v)), 'y-m-d')
+ dateRange.end = formatTime(new Date(nowTime - oneDay), 'y-m-d') // 不含今天
+ }
+ }
+ return dateRange
+}
+
+export const menuInitOpts = {
+ cell: {
+ showArrow: true,
+ },
+ click: {
+ },
+ sort: {
+ showSort: true,
+ },
+ filter: {
+ showArrow: true,
+ },
+ picker: {
+ showArrow: true,
+ },
+ daterange: {
+ showQuick: true,
+ showArrow: true,
+ },
+ slot: {
+ showArrow: true,
+ },
+ search: {
+ showSearch: true,
+ },
+}
diff --git a/src/components/hpy-watermark.vue b/src/components/hpy-watermark.vue
new file mode 100644
index 0000000..e7f91c5
--- /dev/null
+++ b/src/components/hpy-watermark.vue
@@ -0,0 +1,344 @@
+
+
+
+
+
+ {{ item.key }}:{{ item.value }}
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+ selectImg(item, e, collapseIndex, itemIndex)" @delete="deleteImg(item, $event)">
+
+ waterMark(item, path)">
+
+
+ 状态:
+
+ 描述:
+ 照片:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/image-watermark-picker.vue b/src/components/image-watermark-picker.vue
new file mode 100644
index 0000000..461b58b
--- /dev/null
+++ b/src/components/image-watermark-picker.vue
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/waterMarker.vue b/src/components/waterMarker.vue
new file mode 100644
index 0000000..7cdef7f
--- /dev/null
+++ b/src/components/waterMarker.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/package.json b/src/package.json
new file mode 100644
index 0000000..1edf91b
--- /dev/null
+++ b/src/package.json
@@ -0,0 +1,20 @@
+{
+ "id": "da-dropdown",
+ "name": "da-dropdown 下拉筛选菜单(支持主题色、功能丰富,Vue3版)",
+ "displayName": "da-dropdown 下拉筛选菜单(支持主题色、功能丰富,Vue3版)",
+ "version": "2.2.2",
+ "description": "一个基于 Vue3 的头部导航栏下拉筛选菜单组件,兼容App、H5、微信小程序、支付宝小程序、抖音小程序等。。。",
+ "keywords": [
+ "dropdown",
+ "导航栏",
+ "筛选",
+ "下拉菜单",
+ "da系列"
+ ],
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/pages/feedback/feedback.vue b/src/pages/feedback/feedback.vue
index 3f187b2..7a57027 100644
--- a/src/pages/feedback/feedback.vue
+++ b/src/pages/feedback/feedback.vue
@@ -92,7 +92,7 @@ const submit = (ref) => {
.tips {
border-radius: 10rpx;
background: #ffffff3f;
- margin: 30rpx;
+ margin: 0 30rpx 30rpx;
padding: 10rpx;
display: flex;
align-items: center;
diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue
index e043e21..6b3a5ab 100644
--- a/src/pages/index/index.vue
+++ b/src/pages/index/index.vue
@@ -2,7 +2,7 @@
* @Author: XHC
* @Date: 2025-05-19 11:07:37
* @LastEditors: XHC
- * @LastEditTime: 2025-05-29 16:55:28
+ * @LastEditTime: 2025-06-06 17:40:38
* @Description: 首页
-->
@@ -80,18 +80,21 @@
-
+
- {{ item.routeName }}
-
+ {{ item.title }}
+
+
- 线路编号:{{ item.routeNumber }}
+ 线路编号:{{ item.num }}
- {{''}} {{ item.patrolPersonnel }}
+ {{''}} {{ item.info }}
任务 {{ item.task }}
-
+
+
+
+
+
+ 顶部
+
\ No newline at end of file
diff --git a/src/pages/message/message.vue b/src/pages/message/message.vue
index 1154e95..ec00f91 100644
--- a/src/pages/message/message.vue
+++ b/src/pages/message/message.vue
@@ -2,7 +2,7 @@
* @Author: XHC
* @Date: 2025-05-19 15:19:14
* @LastEditors: XHC
- * @LastEditTime: 2025-05-23 15:30:08
+ * @LastEditTime: 2025-06-05 17:46:03
* @Description: 消息
-->
@@ -11,7 +11,7 @@
{{''}}
- {{ item.title }}
+ {{ item.title }}
{{ item.info }}
@@ -20,11 +20,19 @@
+
+
+
+ 顶部
+
diff --git a/src/uni_modules/hpy-watermark/package.json b/src/uni_modules/hpy-watermark/package.json
new file mode 100644
index 0000000..c427e8e
--- /dev/null
+++ b/src/uni_modules/hpy-watermark/package.json
@@ -0,0 +1,83 @@
+{
+ "id": "hpy-watermark",
+ "displayName": "文字水印",
+ "version": "1.0.6",
+ "description": "图片增加文字水印,支持拍照和相册选取多张",
+ "keywords": [
+ "水印",
+ "图片水印",
+ "文字水印",
+ "watermark"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": ""
+ },
+"dcloudext": {
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "",
+ "type": "component-vue"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/uni_modules/hpy-watermark/readme.md b/src/uni_modules/hpy-watermark/readme.md
new file mode 100644
index 0000000..ad8315d
--- /dev/null
+++ b/src/uni_modules/hpy-watermark/readme.md
@@ -0,0 +1,201 @@
+
+## 图片增加文字水印
+
+> **组件名:hpy-watermark
+> 图片增加文字水印,支持拍照和相册选取多张
+
+## API
+
+## Props
+
+
+
+ 属性名 |
+ 类型 |
+ 默认值 |
+ 说明 |
+
+
+ markAlign |
+ String |
+ 左下角 |
+ 文字文字位置(默认:左下角)可选值:左上角:topLeft、右上角:topRight、左下角:bottomLeft、右下角:bottomRight |
+
+
+ fontSize |
+ Number |
+ 40 |
+ 文字大小,默认:40 |
+
+
+ fontColor |
+ String |
+ 白色 |
+ 文字颜色,默认:#FFFFFF |
+
+
+ quality |
+ Number |
+ 1 |
+ 图片的质量,取值范围为 (0, 1],不在范围内时当作1.0处理 |
+
+
+ fileType |
+ String |
+ jpg |
+ 目标文件的类型,只支持 'jpg' 或 'png'。默认为 'jpg' |
+
+
+ shadowColor |
+ String |
+ 黑色 |
+ 阴影颜色,默认:rgba(0, 0, 0, 1.0) |
+
+
+ shadowWidth |
+ Number |
+ 2 |
+ 阴影边框大小,默认:2 |
+
+
+ textAlign |
+ String |
+ start |
+ 设置文本的水平对齐方式,默认:start,文本在指定的位置开始。 start、end、center、left、right |
+
+
+ textBaseline |
+ String |
+ alphabetic |
+ 设置文本的垂直对齐方式,默认:alphabetic文本基线是普通的字母基线。top、hanging、middle、ideographic、bottom |
+
+
+
+
+## methods
+
+
+ 参数名 |
+ 类型 |
+ 说明 |
+
+
+ addWaterMark |
+ Object |
+ {filePaths:['图片地址1', '图片地址2'], fillTexts:['水印文字1', '水印文字2']} |
+
+
+
+## 使用示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```javascript
+
+
+```
+
+```style
+
+```
\ No newline at end of file