|
|
@@ -36,6 +36,8 @@
|
|
|
</view>
|
|
|
<!-- 操作按钮 -->
|
|
|
<view class="popup-actions">
|
|
|
+ <text class="action-btn action-btn-contact" v-if="selectedNode.groupType !== 'PERSON' && selectedNode.groupType !== 'SKILL'" @tap="onContact">联系</text>
|
|
|
+ <text class="action-btn action-btn-priority" v-if="selectedNode.groupType !== 'PERSON' && selectedNode.groupType !== 'SKILL'" @tap="onAdjustPriority">优先级</text>
|
|
|
<text class="action-btn action-btn-delete" v-if="canDelete" @tap="onDelete">删除</text>
|
|
|
</view>
|
|
|
<view class="popup-arrow" :class="{ 'popup-arrow-down': showPopupBelow }"></view>
|
|
|
@@ -46,7 +48,7 @@
|
|
|
<view class="pearl-graph-empty" v-else-if="isEmpty">
|
|
|
<text class="empty-icon">📿</text>
|
|
|
<text class="empty-text">暂无珍珠图数据</text>
|
|
|
- <text class="empty-hint">登记你的资源,画出珍珠项链图</text>
|
|
|
+ <text class="empty-hint">登记你的社会连接,画出珍珠项链图</text>
|
|
|
<text class="action-btn action-btn-primary" @tap="onAdd">+ 登记资源</text>
|
|
|
</view>
|
|
|
<!-- 加载状态 -->
|
|
|
@@ -56,18 +58,20 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+import { addPearlInteraction, updatePearlPriority } from '../utils/api.js'
|
|
|
+
|
|
|
/**
|
|
|
* PearlDiagram - 珍珠图 Canvas 组件
|
|
|
*
|
|
|
* 珍珠项链式资源清单可视化:
|
|
|
* - 中心节点 = 当前用户"我"(固定不动)
|
|
|
- * - 珍珠节点 = 资源,按 4 组分布在中心周围:
|
|
|
- * 人脉(PERSON) / 技能(SKILL) / 信息(INFO) / 场所(PLACE)
|
|
|
+ * - 珍珠节点 = 资源,按 25 组分布在中心周围(两层同心圆):
|
|
|
+ * 内圈必备 12 组 + 外圈理想 13 组
|
|
|
* - 每组以弧形分布在中心周围,颜色编码
|
|
|
* - 点击珍珠 → 显示详情弹窗
|
|
|
*
|
|
|
* 数据源:父组件通过 resources prop 传入
|
|
|
- * 布局方式:确定性弧形布局(非力导向)
|
|
|
+ * 布局方式:环形均分布局(非力导向)
|
|
|
*/
|
|
|
export default {
|
|
|
name: 'PearlDiagram',
|
|
|
@@ -96,6 +100,11 @@ export default {
|
|
|
interactive: {
|
|
|
type: Boolean,
|
|
|
default: true
|
|
|
+ },
|
|
|
+ /** 逾期提醒映射 { resourceItemId: daysSinceLast },父组件从 /reminder/list 构建 */
|
|
|
+ overdueMap: {
|
|
|
+ type: Object,
|
|
|
+ default: null
|
|
|
}
|
|
|
},
|
|
|
data: function() {
|
|
|
@@ -114,16 +123,37 @@ export default {
|
|
|
_touchStartPos: null,
|
|
|
// 默认头像
|
|
|
defaultAvatar: '/static/default-avatar.png',
|
|
|
- // 分组配置:类型、颜色、半径比例、弧度范围(弧度)
|
|
|
- // 0=右(3点钟), PI/2=下(6点), PI=左(9点), -PI/2=上(12点)
|
|
|
+ // 分组配置:25 类社会连接,内圈必备 12 组 / 外圈理想 13 组
|
|
|
+ // 颜色盘:内圈偏暖(红橙),外圈偏冷(蓝紫绿)
|
|
|
groupConfigs: [
|
|
|
- { type: 'PERSON', typeName: '人脉', color: '#F97316', radiusPct: 0.28, startAngle: -Math.PI / 2, endAngle: 0 },
|
|
|
- { type: 'SKILL', typeName: '技能', color: '#F59E0B', radiusPct: 0.38, startAngle: Math.PI, endAngle: Math.PI * 1.5 },
|
|
|
- { type: 'INFO', typeName: '信息', color: '#10B981', radiusPct: 0.38, startAngle: 0, endAngle: Math.PI / 2 },
|
|
|
- { type: 'PLACE', typeName: '场所', color: '#6366F1', radiusPct: 0.28, startAngle: Math.PI / 2, endAngle: Math.PI }
|
|
|
+ // ===== 内圈:必备 12 组(radiusPct 0.28)=====
|
|
|
+ { type: 'MEDICAL', typeName: '医疗', color: '#EF4444', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'EDUCATION', typeName: '教育', color: '#F97316', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'PUBLIC_SECURITY', typeName: '公安', color: '#DC2626', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'AUTO', typeName: '汽车相关', color: '#EA580C', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'REAL_ESTATE', typeName: '房产服务', color: '#D97706', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'TICKETING', typeName: '票务', color: '#CA8A04', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'HANDYMAN', typeName: '多能工人', color: '#B45309', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'APPLIANCE', typeName: '家电', color: '#92400E', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'CATERING', typeName: '餐饮', color: '#E11D48', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'FOOD', typeName: '食品', color: '#BE123C', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'LEGAL', typeName: '法律', color: '#B91C1C', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ { type: 'WEEKEND_EXPERT', typeName: '周末达人', color: '#FB7185', radiusPct: 0.28, ring: 'inner' },
|
|
|
+ // ===== 外圈:理想 13 组(radiusPct 0.55)=====
|
|
|
+ { type: 'GOVERNMENT', typeName: '政府综合', color: '#8B5CF6', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'TAX', typeName: '税务', color: '#7C3AED', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'BUSINESS_ADMIN', typeName: '工商', color: '#6D28D9', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'BANK', typeName: '银行', color: '#2563EB', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'MEDIA', typeName: '媒体', color: '#1D4ED8', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'TRAVEL', typeName: '旅游', color: '#0EA5E9', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'LEADING_ENTERPRISE', typeName: '领军企业', color: '#0891B2', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'INDUSTRY_BENCHMARK', typeName: '行业标杆', color: '#059669', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'OVERSEAS', typeName: '国外', color: '#10B981', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'UNIVERSITY', typeName: '高校', color: '#16A34A', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'FINANCE', typeName: '金融', color: '#84CC16', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'SENIOR_LOCAL', typeName: '资深土著', color: '#65A30D', radiusPct: 0.55, ring: 'outer' },
|
|
|
+ { type: 'KEY_CITY', typeName: '北上广等', color: '#4D7C0F', radiusPct: 0.55, ring: 'outer' }
|
|
|
],
|
|
|
- // 弧度边距(每侧留白角度)
|
|
|
- arcMargin: Math.PI / 20
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -245,12 +275,13 @@ export default {
|
|
|
* 根据 resources 构建珍珠节点的 x, y 坐标
|
|
|
* 布局逻辑:
|
|
|
* - 中心 = (canvasWidth/2, canvasHeight/2) → "我"
|
|
|
- * - 每组分配一个象限 + 特定半径
|
|
|
+ * - 内圈 12 组均分整个圆周(radiusPct 0.28)
|
|
|
+ * - 外圈 13 组均分整个圆周(radiusPct 0.55)
|
|
|
* - 组内珍珠沿弧线等间距分布
|
|
|
+ * - 珍珠半径按 priority 映射
|
|
|
*/
|
|
|
buildLayout: function() {
|
|
|
this.pearlNodes = []
|
|
|
-
|
|
|
if (!this.resources || !this.resources.groups || !Array.isArray(this.resources.groups)) {
|
|
|
return
|
|
|
}
|
|
|
@@ -258,51 +289,82 @@ export default {
|
|
|
var cx = this.canvasWidth / 2
|
|
|
var cy = this.canvasHeight / 2
|
|
|
var minDim = Math.min(this.canvasWidth, this.canvasHeight)
|
|
|
- var configs = this.groupConfigs
|
|
|
-
|
|
|
- for (var c = 0; c < configs.length; c++) {
|
|
|
- var config = configs[c]
|
|
|
- // 在 resources.groups 中查找该类型
|
|
|
- var group = null
|
|
|
- for (var g = 0; g < this.resources.groups.length; g++) {
|
|
|
- if (this.resources.groups[g].type === config.type) {
|
|
|
- group = this.resources.groups[g]
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
+ var self = this
|
|
|
|
|
|
- if (!group || !group.items || group.items.length === 0) continue
|
|
|
+ // 按 ring 分组:内圈 12 / 外圈 13
|
|
|
+ var innerConfigs = []
|
|
|
+ var outerConfigs = []
|
|
|
+ for (var c = 0; c < this.groupConfigs.length; c++) {
|
|
|
+ var cfg = this.groupConfigs[c]
|
|
|
+ if (cfg.ring === 'inner') innerConfigs.push(cfg)
|
|
|
+ else outerConfigs.push(cfg)
|
|
|
+ }
|
|
|
|
|
|
- var R = minDim * config.radiusPct
|
|
|
- var effStart = config.startAngle + this.arcMargin
|
|
|
- var effEnd = config.endAngle - this.arcMargin
|
|
|
- var arcSpan = effEnd - effStart
|
|
|
- var items = group.items
|
|
|
-
|
|
|
- for (var i = 0; i < items.length; i++) {
|
|
|
- var item = items[i]
|
|
|
- var t = items.length === 1 ? 0.5 : i / (items.length - 1)
|
|
|
- var angle = effStart + t * arcSpan
|
|
|
-
|
|
|
- this.pearlNodes.push({
|
|
|
- id: item.id || item.contactId || null,
|
|
|
- contactId: item.contactId || null,
|
|
|
- groupType: config.type,
|
|
|
- groupTypeName: config.typeName,
|
|
|
- name: item.name || '未知',
|
|
|
- displayName: item.name ? item.name.charAt(0) : '?',
|
|
|
- avatar: item.avatar || null,
|
|
|
- description: item.description || '',
|
|
|
- skillCount: item.skillCount || 0,
|
|
|
- skills: item.skills || [],
|
|
|
- relationshipType: item.relationshipType || '',
|
|
|
- radius: (config.type === 'PERSON' || config.type === 'SKILL') ? 24 : 20,
|
|
|
- color: config.color,
|
|
|
- x: cx + R * Math.cos(angle),
|
|
|
- y: cy + R * Math.sin(angle)
|
|
|
- })
|
|
|
+ function placeRing(ringConfigs, radiusPct) {
|
|
|
+ var R = minDim * radiusPct
|
|
|
+ var n = ringConfigs.length
|
|
|
+ var totalSpan = Math.PI * 2
|
|
|
+ var gap = totalSpan * 0.015
|
|
|
+ var used = 0
|
|
|
+ for (var i = 0; i < n; i++) {
|
|
|
+ var config = ringConfigs[i]
|
|
|
+ // 在 resources.groups 中查找该类型
|
|
|
+ var group = null
|
|
|
+ for (var g = 0; g < self.resources.groups.length; g++) {
|
|
|
+ if (self.resources.groups[g].type === config.type) {
|
|
|
+ group = self.resources.groups[g]
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!group || !group.items || group.items.length === 0) {
|
|
|
+ used += (totalSpan / n)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 本组角度区间
|
|
|
+ var groupSpan = totalSpan / n - gap
|
|
|
+ var startAngle = -Math.PI / 2 + used + gap / 2
|
|
|
+ var items = group.items
|
|
|
+
|
|
|
+ for (var k = 0; k < items.length; k++) {
|
|
|
+ var item = items[k]
|
|
|
+ var t = items.length === 1 ? 0.5 : k / (items.length - 1)
|
|
|
+ var angle = startAngle + t * groupSpan
|
|
|
+
|
|
|
+ // 珍珠半径:按 priority 映射(高=大)
|
|
|
+ var priority = item.priority || 2
|
|
|
+ var multiplier = priority === 1 ? 1.5 : priority === 3 ? 0.7 : 1.0
|
|
|
+ var baseR = minDim * radiusPct * 0.09
|
|
|
+ var itemRadius = Math.max(8, Math.min(26, baseR * multiplier))
|
|
|
+
|
|
|
+ self.pearlNodes.push({
|
|
|
+ id: item.id || item.contactId || null,
|
|
|
+ contactId: item.contactId || null,
|
|
|
+ groupType: config.type,
|
|
|
+ groupTypeName: config.typeName,
|
|
|
+ name: item.name || '未知',
|
|
|
+ displayName: item.name ? item.name.charAt(0) : '?',
|
|
|
+ avatar: item.avatar || null,
|
|
|
+ description: item.description || '',
|
|
|
+ skillCount: item.skillCount || 0,
|
|
|
+ skills: item.skills || [],
|
|
|
+ relationshipType: item.relationshipType || '',
|
|
|
+ priority: priority,
|
|
|
+ valueScore: item.valueScore || 0,
|
|
|
+ daysSinceLast: item.daysSinceLast || null,
|
|
|
+ radius: itemRadius,
|
|
|
+ color: config.color,
|
|
|
+ ring: config.ring,
|
|
|
+ x: cx + R * Math.cos(angle),
|
|
|
+ y: cy + R * Math.sin(angle)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ used += (totalSpan / n)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ placeRing(innerConfigs, 0.28)
|
|
|
+ placeRing(outerConfigs, 0.55)
|
|
|
},
|
|
|
|
|
|
/* ===========================
|
|
|
@@ -317,19 +379,22 @@ export default {
|
|
|
|
|
|
ctx.clearRect(0, 0, w, h)
|
|
|
|
|
|
- // 1. 绘制分组弧线背景(半透明色带)
|
|
|
+ // 1. 绘制分组弧线背景(半透明色带,双层)
|
|
|
this._drawGroupArcs(ctx)
|
|
|
|
|
|
// 2. 绘制中心节点"我"
|
|
|
this._drawCenterNode(ctx)
|
|
|
|
|
|
- // 3. 绘制珍珠节点
|
|
|
+ // 3. 绘制珍珠节点(内圈先画,外圈后画)
|
|
|
for (var i = 0; i < this.pearlNodes.length; i++) {
|
|
|
this._drawPearlNode(ctx, this.pearlNodes[i])
|
|
|
}
|
|
|
|
|
|
// 4. 绘制分组标签
|
|
|
this._drawGroupLabels(ctx)
|
|
|
+
|
|
|
+ // 5. 逾期角标(红色圆点+天数,仅 daysSinceLast 超过建议周期的资源)
|
|
|
+ this._drawOverdueBadges(ctx)
|
|
|
},
|
|
|
|
|
|
/** 绘制每组的弧形色带(背景)和连接线 */
|
|
|
@@ -337,36 +402,40 @@ export default {
|
|
|
var cx = this.canvasWidth / 2
|
|
|
var cy = this.canvasHeight / 2
|
|
|
var minDim = Math.min(this.canvasWidth, this.canvasHeight)
|
|
|
- var configs = this.groupConfigs
|
|
|
var self = this
|
|
|
|
|
|
- for (var c = 0; c < configs.length; c++) {
|
|
|
- var config = configs[c]
|
|
|
- // 检查该组是否有节点
|
|
|
- var hasItems = false
|
|
|
+ // 绘制每组的连接线和色带
|
|
|
+ for (var c = 0; c < this.groupConfigs.length; c++) {
|
|
|
+ var config = this.groupConfigs[c]
|
|
|
+ var R = minDim * config.radiusPct
|
|
|
+
|
|
|
+ // 收集该组所有珍珠的角度
|
|
|
+ var groupAngles = []
|
|
|
for (var p = 0; p < this.pearlNodes.length; p++) {
|
|
|
if (this.pearlNodes[p].groupType === config.type) {
|
|
|
- hasItems = true
|
|
|
- break
|
|
|
+ var dx = this.pearlNodes[p].x - cx
|
|
|
+ var dy = this.pearlNodes[p].y - cy
|
|
|
+ groupAngles.push(Math.atan2(dy, dx))
|
|
|
}
|
|
|
}
|
|
|
- if (!hasItems) continue
|
|
|
+ if (groupAngles.length === 0) continue
|
|
|
|
|
|
- var R = minDim * config.radiusPct
|
|
|
- var effStart = config.startAngle + this.arcMargin
|
|
|
- var effEnd = config.endAngle - this.arcMargin
|
|
|
+ // 排序角度
|
|
|
+ groupAngles.sort(function(a, b) { return a - b })
|
|
|
+ var minA = groupAngles[0]
|
|
|
+ var maxA = groupAngles[groupAngles.length - 1]
|
|
|
|
|
|
- // 色带背景(粗线,低透明度)
|
|
|
+ // 色带背景(半透明弧)
|
|
|
ctx.beginPath()
|
|
|
- ctx.arc(cx, cy, R, effStart, effEnd)
|
|
|
+ ctx.arc(cx, cy, R, minA, maxA)
|
|
|
ctx.lineWidth = 14
|
|
|
ctx.strokeStyle = self._hexToRgba(config.color, 0.12)
|
|
|
ctx.lineCap = 'round'
|
|
|
ctx.stroke()
|
|
|
|
|
|
- // 连接线(细线,沿弧串联珍珠)
|
|
|
+ // 连接线(细弧)
|
|
|
ctx.beginPath()
|
|
|
- ctx.arc(cx, cy, R, effStart, effEnd)
|
|
|
+ ctx.arc(cx, cy, R, minA, maxA)
|
|
|
ctx.lineWidth = 1.5
|
|
|
ctx.strokeStyle = self._hexToRgba(config.color, 0.3)
|
|
|
ctx.lineCap = 'butt'
|
|
|
@@ -443,6 +512,15 @@ export default {
|
|
|
ctx.lineWidth = 2
|
|
|
ctx.stroke()
|
|
|
|
|
|
+ // 高优先级(priority=1)白色粗描边
|
|
|
+ if (node.priority === 1) {
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2)
|
|
|
+ ctx.lineWidth = 2
|
|
|
+ ctx.strokeStyle = '#FFFFFF'
|
|
|
+ ctx.stroke()
|
|
|
+ }
|
|
|
+
|
|
|
// 首字
|
|
|
ctx.font = 'bold ' + Math.max(12, r * 0.65) + 'px PingFang SC, sans-serif'
|
|
|
ctx.fillStyle = '#FFFFFF'
|
|
|
@@ -456,23 +534,27 @@ export default {
|
|
|
var cx = this.canvasWidth / 2
|
|
|
var cy = this.canvasHeight / 2
|
|
|
var minDim = Math.min(this.canvasWidth, this.canvasHeight)
|
|
|
- var configs = this.groupConfigs
|
|
|
var self = this
|
|
|
|
|
|
- for (var c = 0; c < configs.length; c++) {
|
|
|
- var config = configs[c]
|
|
|
- // 检查该组是否有节点
|
|
|
- var hasItems = false
|
|
|
+ for (var c = 0; c < this.groupConfigs.length; c++) {
|
|
|
+ var config = this.groupConfigs[c]
|
|
|
+ // 收集该组所有珍珠的角度和位置
|
|
|
+ var groupAngles = []
|
|
|
for (var p = 0; p < this.pearlNodes.length; p++) {
|
|
|
if (this.pearlNodes[p].groupType === config.type) {
|
|
|
- hasItems = true
|
|
|
- break
|
|
|
+ var dx = this.pearlNodes[p].x - cx
|
|
|
+ var dy = this.pearlNodes[p].y - cy
|
|
|
+ groupAngles.push(Math.atan2(dy, dx))
|
|
|
}
|
|
|
}
|
|
|
- if (!hasItems) continue
|
|
|
+ if (groupAngles.length === 0) continue
|
|
|
|
|
|
+ // 中间角度
|
|
|
+ var minA = groupAngles[0]
|
|
|
+ var maxA = groupAngles[groupAngles.length - 1]
|
|
|
+ var midAngle = (minA + maxA) / 2
|
|
|
var R = minDim * config.radiusPct
|
|
|
- var midAngle = (config.startAngle + config.endAngle) / 2
|
|
|
+
|
|
|
// 标签在弧线外侧
|
|
|
var labelR = R + 18
|
|
|
var lx = cx + labelR * Math.cos(midAngle)
|
|
|
@@ -486,6 +568,31 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ /** 逾期角标:红色小圆点 + 天数(仅当 PENDING 提醒语义成立时,由父组件传入 overdueMap) */
|
|
|
+ _drawOverdueBadges: function(ctx) {
|
|
|
+ if (!this.overdueMap) return
|
|
|
+ var self = this
|
|
|
+ var overdueIds = Object.keys(this.overdueMap)
|
|
|
+ for (var i = 0; i < this.pearlNodes.length; i++) {
|
|
|
+ var node = this.pearlNodes[i]
|
|
|
+ if (!node.id) continue
|
|
|
+ var days = this.overdueMap['' + node.id]
|
|
|
+ if (days === undefined || days === null) continue
|
|
|
+ var bx = node.x + node.radius - 4
|
|
|
+ var by = node.y - node.radius + 4
|
|
|
+ // 红底白字小徽标
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(bx, by, 9, 0, Math.PI * 2)
|
|
|
+ ctx.fillStyle = '#EF4444'
|
|
|
+ ctx.fill()
|
|
|
+ ctx.fillStyle = '#FFFFFF'
|
|
|
+ ctx.font = 'bold 10px sans-serif'
|
|
|
+ ctx.textAlign = 'center'
|
|
|
+ ctx.textBaseline = 'middle'
|
|
|
+ ctx.fillText(String(days), bx, by + 1)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
/* ===========================
|
|
|
* 交互:触摸处理
|
|
|
* =========================== */
|
|
|
@@ -584,6 +691,54 @@ export default {
|
|
|
this.selectedNode = null
|
|
|
},
|
|
|
|
|
|
+ /** 联系:弹出方式选择 */
|
|
|
+ onContact: function() {
|
|
|
+ var self = this
|
|
|
+ var node = this.selectedNode
|
|
|
+ if (!node || !node.id) return
|
|
|
+ uni.showActionSheet({
|
|
|
+ itemList: ['电话', '微信', '见面', '其他'],
|
|
|
+ success: function(res) {
|
|
|
+ var types = ['PHONE', 'WECHAT', 'MEETING', 'OTHER']
|
|
|
+ addPearlInteraction({
|
|
|
+ itemId: node.id,
|
|
|
+ interactionType: types[res.tapIndex],
|
|
|
+ content: ''
|
|
|
+ }).then(function(resp) {
|
|
|
+ if (resp.code === 200) {
|
|
|
+ uni.showToast({ title: '已记录', icon: 'success' })
|
|
|
+ self.$emit('interaction-updated')
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: resp.message || '记录失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ /** 调整优先级 */
|
|
|
+ onAdjustPriority: function() {
|
|
|
+ var self = this
|
|
|
+ var node = this.selectedNode
|
|
|
+ if (!node || !node.id) return
|
|
|
+ uni.showActionSheet({
|
|
|
+ itemList: ['高(大珍珠)', '中(默认)', '低(小珍珠)'],
|
|
|
+ success: function(res) {
|
|
|
+ updatePearlPriority({
|
|
|
+ itemId: node.id,
|
|
|
+ priority: res.tapIndex + 1
|
|
|
+ }).then(function(resp) {
|
|
|
+ if (resp.code === 200) {
|
|
|
+ uni.showToast({ title: '已调整', icon: 'success' })
|
|
|
+ self.$emit('interaction-updated')
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: resp.message || '调整失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
/* ===========================
|
|
|
* Canvas 初始化
|
|
|
* =========================== */
|
|
|
@@ -821,6 +976,14 @@ export default {
|
|
|
color: #EF4444;
|
|
|
margin-left: 16rpx;
|
|
|
}
|
|
|
+.action-btn-contact {
|
|
|
+ background: #3B82F6;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+.action-btn-priority {
|
|
|
+ background: #8B5CF6;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
.popup-arrow {
|
|
|
position: absolute;
|
|
|
bottom: -8rpx;
|