@ozdao/prometheus-framework 0.2.65 → 0.2.66
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +1 -1
- package/src/components/Feed/Feed.vue +17 -18
- package/src/components/Field/Field.vue +1 -0
- package/src/components/Tooltip/Tooltip.vue +1 -1
- package/src/modules/globals/components/blocks/CardHeader.vue +6 -3
- package/src/modules/globals/controllers/utils/queryProcessor.js +2 -1
- package/src/modules/globals/store/globals.js +3 -4
- package/src/modules/products/components/blocks/CardLeftover.vue +47 -27
- package/src/modules/products/components/pages/EditLeftover.vue +13 -0
- package/src/modules/products/components/pages/Leftovers.vue +3 -3
- package/src/modules/products/controllers/leftovers.controller.js +54 -17
- package/src/modules/products/models/leftover.model.js +5 -0
- package/src/modules/products/routes/leftovers.routes.js +1 -1
- package/src/styles/config.scss +2 -2
package/package.json
CHANGED
@@ -2,18 +2,20 @@
|
|
2
2
|
|
3
3
|
<TransitionGroup tag="ul" name="scaleTransition" >
|
4
4
|
<BlockSearch
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
v-if="search"
|
6
|
+
@search="updateSearch"
|
7
|
+
placeholder="Enter product name"
|
8
|
+
class="bg-white mn-b-thin"
|
9
|
+
/>
|
10
10
|
</TransitionGroup>
|
11
|
+
|
11
12
|
<TransitionGroup v-if="isLoading" tag="ul" name="scaleTransition" class="o-hidden bg-grey radius-big">
|
12
13
|
<SkeletonEvent
|
13
14
|
v-if="isLoading"
|
14
15
|
v-for="i in currentLimit" :key="i"
|
15
16
|
/>
|
16
17
|
</TransitionGroup>
|
18
|
+
|
17
19
|
<transition name="scaleTransition">
|
18
20
|
<EmptyState
|
19
21
|
v-if="!isLoading && itemsList.length < 1"
|
@@ -24,8 +26,6 @@
|
|
24
26
|
</transition>
|
25
27
|
|
26
28
|
<TransitionGroup tag="ul" name="scaleTransition" :class="$attrs.class">
|
27
|
-
|
28
|
-
|
29
29
|
<slot
|
30
30
|
v-if="!isLoading && itemsList.length > 0"
|
31
31
|
:items="itemsList"
|
@@ -41,7 +41,6 @@
|
|
41
41
|
</button>
|
42
42
|
</TransitionGroup>
|
43
43
|
|
44
|
-
|
45
44
|
</template>
|
46
45
|
|
47
46
|
<script setup>
|
@@ -106,6 +105,14 @@ let isLoading = ref(true);
|
|
106
105
|
let currentSkip = ref(props.options.skip ? props.options.skip : 0);
|
107
106
|
let currentLimit = ref(props.options.limit ? props.options.limit : 10);
|
108
107
|
|
108
|
+
let currentSearch = ref('');
|
109
|
+
|
110
|
+
function updateSearch(search) {
|
111
|
+
currentSearch.value = search
|
112
|
+
|
113
|
+
fetchItems();
|
114
|
+
}
|
115
|
+
|
109
116
|
const loadMoreItems = async () => {
|
110
117
|
if (hasMoreItems.value) {
|
111
118
|
currentSkip.value += currentLimit.value;
|
@@ -113,6 +120,7 @@ const loadMoreItems = async () => {
|
|
113
120
|
const data = await props.store.read({
|
114
121
|
skip: currentSkip.value,
|
115
122
|
limit: currentLimit.value,
|
123
|
+
search: currentSearch.value,
|
116
124
|
...props.options
|
117
125
|
});
|
118
126
|
|
@@ -132,6 +140,7 @@ const fetchItems = async () => {
|
|
132
140
|
const data = await props.store.read({
|
133
141
|
skip: currentSkip.value,
|
134
142
|
limit: currentLimit.value,
|
143
|
+
search: currentSearch.value,
|
135
144
|
...props.options
|
136
145
|
});
|
137
146
|
|
@@ -143,8 +152,6 @@ const fetchItems = async () => {
|
|
143
152
|
hasMoreItems.value = true;
|
144
153
|
}
|
145
154
|
|
146
|
-
console.log(data)
|
147
|
-
|
148
155
|
itemsList.value = data;
|
149
156
|
isLoading.value = false;
|
150
157
|
};
|
@@ -164,14 +171,6 @@ watch(() => props.options, (newVal, oldVal) => {
|
|
164
171
|
}
|
165
172
|
}, { deep: true });
|
166
173
|
|
167
|
-
function updateSearch(search) {
|
168
|
-
props.options.search = search
|
169
|
-
|
170
|
-
console.log(search)
|
171
|
-
|
172
|
-
fetchItems();
|
173
|
-
}
|
174
|
-
|
175
174
|
|
176
175
|
onMounted(async () => {
|
177
176
|
await fetchItems()
|
@@ -35,7 +35,6 @@
|
|
35
35
|
})"
|
36
36
|
/>
|
37
37
|
|
38
|
-
|
39
38
|
<span
|
40
39
|
v-if="type !== 'short'"
|
41
40
|
class="t-semi"
|
@@ -62,9 +61,13 @@
|
|
62
61
|
>
|
63
62
|
· by {{creator.target?.profile?.name}}
|
64
63
|
</span>
|
65
|
-
|
64
|
+
|
65
|
+
<span v-if="date" class="pos-relative">
|
66
|
+
<Tooltip v-if="date" :text="formatDate(date)">
|
66
67
|
· {{getTimeElapsed(date)}}
|
68
|
+
</Tooltip>
|
67
69
|
</span>
|
70
|
+
|
68
71
|
<span v-if="dateFormatted">
|
69
72
|
· {{dateFormatted}}
|
70
73
|
</span>
|
@@ -182,7 +185,7 @@
|
|
182
185
|
|
183
186
|
import PlaceholderUserpic from '@pf/src/modules/icons/placeholders/PlaceholderUserpic.vue'
|
184
187
|
import FormReport from '@pf/src/modules/reports/components/sections/FormReport.vue'
|
185
|
-
|
188
|
+
import Tooltip from '@pf/src/components/Tooltip/Tooltip.vue'
|
186
189
|
import Dropdown from "@pf/src/components/Dropdown/Dropdown.vue";
|
187
190
|
import ButtonToggleMembership from '@pf/src/modules/organizations/components/elements/ButtonToggleMembership.vue'
|
188
191
|
|
@@ -2,7 +2,7 @@ const ObjectId = require('mongoose').Types.ObjectId;
|
|
2
2
|
|
3
3
|
function getBasicOptions(query) {
|
4
4
|
// Деструктуризация для извлечения параметров запроса
|
5
|
-
const { _id, url, status, owner, creator } = query;
|
5
|
+
const { _id, url, status, type, owner, creator } = query;
|
6
6
|
|
7
7
|
// Подготовка условий для каждого возможного параметра
|
8
8
|
const conditions = [];
|
@@ -10,6 +10,7 @@ function getBasicOptions(query) {
|
|
10
10
|
if (_id) { conditions.push({ _id: new ObjectId(_id) }); }
|
11
11
|
if (url) { conditions.push({ url: url }); }
|
12
12
|
if (status) { conditions.push({ status: status }); }
|
13
|
+
if (type) { conditions.push({ type: type }); }
|
13
14
|
if (owner) { conditions.push({ "owner.target": new ObjectId(owner) }); }
|
14
15
|
if (creator) { conditions.push({ "creator.target": new ObjectId(creator) }); }
|
15
16
|
|
@@ -66,17 +66,16 @@ const actions = {
|
|
66
66
|
array[existingItemIndex] = item
|
67
67
|
}
|
68
68
|
},
|
69
|
-
|
70
69
|
update(array, item) {
|
71
70
|
const existingItemIndex = array.findIndex(i => i._id === item._id);
|
72
|
-
|
73
71
|
if (existingItemIndex === -1) {
|
72
|
+
// If the item doesn't exist, push it to the array
|
74
73
|
array.push(item);
|
75
74
|
} else {
|
76
|
-
array
|
75
|
+
// Update the item in the array without creating a new array
|
76
|
+
Object.assign(array[existingItemIndex], item);
|
77
77
|
}
|
78
78
|
},
|
79
|
-
|
80
79
|
delete(array, item) {
|
81
80
|
const existingItemIndex = array.findIndex(c => c._id === item._id);
|
82
81
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
<template>
|
2
2
|
<div class="flex-column pos-relative flex-wrap">
|
3
|
+
|
3
4
|
<CardHeader
|
4
5
|
:entity="leftover"
|
5
6
|
:entityType="'leftover'"
|
@@ -9,45 +10,64 @@
|
|
9
10
|
:date="leftover.createdAt"
|
10
11
|
/>
|
11
12
|
|
12
|
-
<
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
<router-link
|
14
|
+
:to="{
|
15
|
+
name: 'LeftoverEdit',
|
16
|
+
params: {
|
17
|
+
_id: leftover.organization,
|
18
|
+
leftover: leftover._id
|
19
|
+
}
|
20
|
+
}"
|
21
|
+
class="
|
22
|
+
cursor-pointer
|
23
|
+
pos-absolute pos-t-regular pos-r-regular
|
24
|
+
radius-extra pd-thin bg-second
|
25
|
+
"
|
26
|
+
>
|
16
27
|
<IconEdit
|
17
|
-
|
18
|
-
|
19
|
-
params: {
|
20
|
-
_id: leftover.organization,
|
21
|
-
leftover: leftover._id
|
22
|
-
}
|
23
|
-
})"
|
24
|
-
class="pos-absolute pos-t-regular pos-r-regular i-regular t-transp"
|
28
|
+
class="i-regular"
|
29
|
+
classes="fill-white"
|
25
30
|
/>
|
26
|
-
</
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
</router-link>
|
32
|
+
|
33
|
+
<div class="mn-t-small w-100 bg-white radius-small pd-small spoiler">
|
34
|
+
<div @click="spoiler = !spoiler" class="flex-v-center flex">
|
35
|
+
<span
|
36
|
+
class="flex-child flex-child-shrink-0 capitalize w-max mn-r-thin t-medium radius-big pd-b-nano pd-t-nano pd-r-thin pd-l-thin"
|
37
|
+
:class="{
|
38
|
+
'bg-green': leftover.type === 'stock-in',
|
39
|
+
'bg-red': leftover.type === 'stock-out'
|
40
|
+
}"
|
41
|
+
>
|
42
|
+
{{leftover.type}}
|
43
|
+
</span>
|
44
|
+
<span class="flex-child flex-child-shrink-0">Positions {{leftover.positions.length}}</span>
|
45
|
+
<span v-if="leftover.order" class="mn-r-thin mn-l-thin t-transp">|</span>
|
46
|
+
<span class="flex-child flex-child-shrink-0" v-if="leftover.order">For order {{leftover.order}}</span>
|
47
|
+
<span v-if="leftover.comment" class="mn-r-thin mn-l-thin t-transp">|</span>
|
48
|
+
<p v-if="leftover.comment" class="t-truncate">Comment: {{leftover.comment}}</p>
|
33
49
|
<!-- <img :class="{ 'spoiler-active': spoiler }" class="button-icon" src="@/assets/icons/arrow-down-spoiler.svg"> -->
|
34
50
|
</div>
|
51
|
+
|
35
52
|
<transition name="fade">
|
36
53
|
<div v-if="spoiler">
|
37
54
|
<div v-for="position in leftover.positions" class="mn-t-small w-100 mn-b-thin flex">
|
38
55
|
<div class=" w-50 flex">
|
39
56
|
<span>
|
40
|
-
<!-- <span class="t-transp">Название:</span> -->
|
41
57
|
{{position.name}}
|
42
58
|
</span>
|
59
|
+
<span class="mn-r-thin mn-l-thin t-transp">|</span>
|
60
|
+
|
61
|
+
<span class="w-50">
|
62
|
+
{{position.price}}
|
63
|
+
<span class="t-transp">{{returnCurrency()}}</span>
|
64
|
+
</span>
|
65
|
+
|
43
66
|
</div>
|
44
67
|
|
45
|
-
<div class="t-right w-50
|
46
|
-
|
47
|
-
|
48
|
-
{{position.quantity}}
|
49
|
-
<span class="t-transp">{{declOfNum(position.quantity, ['единица', ' единицы', ' единиц'])}}</span>
|
50
|
-
</span>
|
68
|
+
<div class="t-right w-50">
|
69
|
+
{{position.quantity}}
|
70
|
+
<span class="t-transp">{{position.type}}</span>
|
51
71
|
</div>
|
52
72
|
</div>
|
53
73
|
</div>
|
@@ -76,7 +96,7 @@
|
|
76
96
|
});
|
77
97
|
|
78
98
|
|
79
|
-
const spoiler = ref(
|
99
|
+
const spoiler = ref(true)
|
80
100
|
|
81
101
|
function declOfNum(number, words) {
|
82
102
|
return words[(number % 100 > 4 && number % 100 < 20) ? 2 : [2, 0, 1, 1, 1, 2][(number % 10 < 5) ? number % 10 : 5]];
|
@@ -89,6 +89,19 @@
|
|
89
89
|
class="mn-b-small radius-medium bg-white pd-small"
|
90
90
|
/>
|
91
91
|
</Block>
|
92
|
+
|
93
|
+
<Block
|
94
|
+
title="Comment"
|
95
|
+
class="mn-b-semi"
|
96
|
+
>
|
97
|
+
<Field
|
98
|
+
v-model:field="leftovers.state.current.comment"
|
99
|
+
label="Comment"
|
100
|
+
type="textarea"
|
101
|
+
class="w-100 bg-white radius-small pd-medium"
|
102
|
+
/>
|
103
|
+
|
104
|
+
</Block>
|
92
105
|
|
93
106
|
<Block class="">
|
94
107
|
<section class="gap-thin flex-v-center flex-nojustify flex">
|
@@ -12,7 +12,7 @@
|
|
12
12
|
</header>
|
13
13
|
|
14
14
|
<section class="mn-b-semi pd-medium bg-grey radius-big">
|
15
|
-
<p class="mn-b-thin">
|
15
|
+
<p class="mn-b-thin">Balance:</p>
|
16
16
|
<h3>{{formatPrice(totalPrice)}}</h3>
|
17
17
|
</section>
|
18
18
|
|
@@ -47,6 +47,7 @@
|
|
47
47
|
/>
|
48
48
|
|
49
49
|
<Feed
|
50
|
+
:search="true"
|
50
51
|
:states="{
|
51
52
|
empty: {
|
52
53
|
title: 'No Leftovers Found',
|
@@ -58,9 +59,8 @@
|
|
58
59
|
}"
|
59
60
|
:options="{
|
60
61
|
limit: 15,
|
61
|
-
|
62
|
+
owner: route.params._id,
|
62
63
|
...(tab !== 'all' && { type: tab })
|
63
|
-
// user: user
|
64
64
|
}"
|
65
65
|
v-slot="{
|
66
66
|
items
|
@@ -1,29 +1,66 @@
|
|
1
|
+
const queryProcessorGlobals = require('@pf/src/modules/globals/controllers/utils/queryProcessor');
|
2
|
+
|
1
3
|
const controllerFactory = (db) => {
|
2
4
|
const Leftover = db.leftover;
|
3
5
|
|
4
|
-
const
|
6
|
+
const read = async (req, res) => {
|
5
7
|
try {
|
6
|
-
let query = {};
|
7
|
-
let options = {};
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
let matchConditions = [];
|
10
|
+
|
11
|
+
const search = req.query.search;
|
12
|
+
|
13
|
+
if (search) {
|
14
|
+
const parts = search.split('.');
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
let regexPattern = '';
|
17
|
+
|
18
|
+
if (parts.length === 2) {
|
19
|
+
// Создаем паттерн, который допускает замену одного символа в каждой части
|
20
|
+
regexPattern = parts.map(part => part.substr(0, part.length - 1) + '.{1}').join('\\.');
|
21
|
+
} else {
|
22
|
+
// Если нет точки, применяем аналогичный подход к всей строке
|
23
|
+
regexPattern = search.substr(0, search.length - 1) + '.{1}';
|
24
|
+
}
|
25
|
+
|
26
|
+
matchConditions.push({
|
27
|
+
$or: [
|
28
|
+
{ "comment": { $regex: regexPattern, $options: 'i' } },
|
29
|
+
{ "positions.name": { $regex: regexPattern, $options: 'i' } }
|
30
|
+
]
|
31
|
+
});
|
17
32
|
}
|
18
33
|
|
19
|
-
|
34
|
+
const matchStage = matchConditions.length > 0 ? { $match: { $and: matchConditions } } : null;
|
35
|
+
|
36
|
+
let stages = [
|
37
|
+
...queryProcessorGlobals.getBasicOptions(
|
38
|
+
req.query
|
39
|
+
),
|
40
|
+
// For creator
|
41
|
+
queryProcessorGlobals.getCreatorUserLookupStage(),
|
42
|
+
queryProcessorGlobals.getCreatorOrganizationLookupStage(),
|
43
|
+
// For owner
|
44
|
+
queryProcessorGlobals.getOwnerUserLookupStage(),
|
45
|
+
queryProcessorGlobals.getOwnerOrganizationLookupStage(),
|
46
|
+
queryProcessorGlobals.getAddFieldsCreatorOwnerStage(),
|
47
|
+
|
48
|
+
...(matchStage != null ? [matchStage] : []),
|
49
|
+
// Pagination
|
50
|
+
...queryProcessorGlobals.getSortingOptions(
|
51
|
+
req.query.sortParam,
|
52
|
+
req.query.sortOrder,
|
53
|
+
),
|
54
|
+
...queryProcessorGlobals.getPaginationOptions(
|
55
|
+
req.query.skip,
|
56
|
+
req.query.limit
|
57
|
+
)
|
58
|
+
];
|
20
59
|
|
21
|
-
const leftoveres = await Leftover.
|
22
|
-
.sort({ createdAt: "desc" })
|
23
|
-
.exec();
|
60
|
+
const leftoveres = await Leftover.aggregate(stages).exec();
|
24
61
|
|
25
|
-
if (!leftoveres) {
|
26
|
-
|
62
|
+
if (!leftoveres.length) {
|
63
|
+
return res.status(404).send({ message: "LEFTOVERES_NOT_FOUND" });
|
27
64
|
}
|
28
65
|
|
29
66
|
res.status(200).send(leftoveres);
|
@@ -93,7 +130,7 @@ const controllerFactory = (db) => {
|
|
93
130
|
};
|
94
131
|
|
95
132
|
return {
|
96
|
-
|
133
|
+
read,
|
97
134
|
create,
|
98
135
|
get,
|
99
136
|
update,
|
@@ -13,11 +13,16 @@ module.exports = (db) => {
|
|
13
13
|
required: true,
|
14
14
|
},
|
15
15
|
order: {
|
16
|
+
type: db.mongoose.Schema.Types.ObjectId,
|
17
|
+
ref: 'Order',
|
18
|
+
},
|
19
|
+
comment: {
|
16
20
|
type: String
|
17
21
|
},
|
18
22
|
store: {
|
19
23
|
type: Object
|
20
24
|
},
|
25
|
+
|
21
26
|
positions: [{
|
22
27
|
_id: {
|
23
28
|
type: db.mongoose.Schema.Types.ObjectId,
|
package/src/styles/config.scss
CHANGED